当前位置: 首页 > 知识库问答 >
问题:

线程“主要”中的异常

谭勇
2023-03-14

我已经阅读了与此问题相关的所有堆栈溢出问题。我对此有了一些想法,但它不能帮助我解决这个问题。

我已使用服务帐户进行授权。因为我不想为我的用户显示授权屏幕。因此,我已经创建了服务帐户,并在GoogleAPI控制台中启用了域范围的委托权限。

我需要以编程的方式在用户的Google课堂中创建课程。我已按照 Java 快速入门使用 OAuth 客户端 ID 和 OAuth 客户端密钥。完成后,授权令牌已存储在项目目录中。使用此令牌,我可以在授权用户的Google教室中创建课程。因为我需要在谷歌教室为我域中的许多用户创建课程。所以我使用了服务帐户。当我尝试实现它时,我得到了上述错误。

我已经在Web应用程序中实现了它。为了更好地理解和代码可读性,我创建了一个快速入门 maven 项目并粘贴了代码。代码在系统.out.println(“进入列出课程方法:”)之前工作正常;线。

1) 如何解决这个问题?

2) 它会要求管理员授权吗?因为为了访问用户数据,我们需要访问令牌。如何使用服务帐户获得访问令牌?

public class ClassroomServiceAccount {

    private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
    private static final String SERVICE_ACCOUNT_EMAIL = "xxxxxxx@projectName.iam.gserviceaccount.com";
    private static final String SERVICE_ACCOUNT_PKCS12_FILE_PATH = "/MyProject.p12";
    private static final List<String> SCOPES = Arrays.asList(ClassroomScopes.CLASSROOM_COURSES, ClassroomScopes.CLASSROOM_TOPICS, ClassroomScopes.CLASSROOM_ANNOUNCEMENTS);

    public static void main(String... args) throws IOException, GeneralSecurityException {

        HttpTransport httpTransport = new NetHttpTransport();
        InputStream in = ClassroomServiceAccount.class.getResourceAsStream(SERVICE_ACCOUNT_PKCS12_FILE_PATH);
        KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
        keystore.load(in, "notasecret".toCharArray());

        String alias = "key1";

        Key key = keystore.getKey(alias, "notasecret".toCharArray());

          // Get certificate of public key
          Certificate cert = keystore.getCertificate(alias);

          // Get public key
          PublicKey publicKey = cert.getPublicKey();
          System.out.println("This is public key : "+ publicKey);

          // Return a key pair
          KeyPair k = new KeyPair(publicKey, (PrivateKey) key);
          System.out.println("This is k : "+ k.getPrivate());



    GoogleCredential credential = new GoogleCredential.Builder()
                .setTransport(httpTransport)
                .setJsonFactory(JSON_FACTORY)
                .setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
                .setServiceAccountPrivateKey(k.getPrivate())
                .setServiceAccountScopes(SCOPES)
                .setServiceAccountUser("email@yourdomain.com")
                .build();   


  System.out.println("credentials : " + credential.getServiceAccountPrivateKey());

  Classroom service = new Classroom.Builder(httpTransport, JSON_FACTORY, null)
        .setApplicationName(APPLICATION_NAME)
        .setHttpRequestInitializer(credential)
        .build();

        // Create courses in users google classroom
        Course course = new Course();
        course.setOwnerId("user@yourdomain.com");
        course.setName("Science");
        service.courses().create(course).execute();
        }
    }

共有2个答案

皇甫聪
2023-03-14

我通过更改范围解决了这个异常。即,在我的代码中,我使用了三个范围。这三个范围应该与GSuite的范围相匹配。在将域范围的权限委托给服务号时,我们添加了范围。这两个范围都应该匹配,以避免401未经授权。

呼延渝
2023-03-14

如评论中所述,您必须将用户凭据替换为服务帐户中的凭据。在此示例中,我使用服务帐户中的凭据修改了凭据的“课堂”快速入门示例。如您所见,我完全删除了获取凭据函数。但是,无论如何,您都可以将凭据构建器放在那里:

public class ClassroomQuickstart {
    private static final String APPLICATION_NAME = "Google Classroom API Java Quickstart";
    private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
    private static final String TOKENS_DIRECTORY_PATH = "tokens";
    private static final String KEY_FILE_LOCATION = "full path of your service account creds json";

    /**
     * Global instance of the scopes required by this quickstart.
     * If modifying these scopes, delete your previously saved tokens/ folder.
     */
    private static final List<String> SCOPES = Collections.singletonList(ClassroomScopes.CLASSROOM_COURSES_READONLY);


    /**
     * Creates an authorized Credential object.
     * @param HTTP_TRANSPORT The network HTTP Transport.
     * @return An authorized Credential object.
     * @throws IOException If the credentials.json file cannot be found.
     */

    public static void main(String... args) throws IOException, GeneralSecurityException {


        GoogleCredential credential = GoogleCredential
                .fromStream(new FileInputStream(KEY_FILE_LOCATION))
                .createScoped(ClassroomScopes.all());
        // Build a new authorized API client service.
        final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
        Classroom service = new Classroom.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
                .setApplicationName(APPLICATION_NAME)
                .build();

        // List the first 10 courses that the user has access to.
        ListCoursesResponse response = service.courses().list()
                .setPageSize(10)
                .execute();
        List<Course> courses = response.getCourses();
        if (courses == null || courses.size() == 0) {
            System.out.println("No courses found.");
        } else {
            System.out.println("Courses:");
            for (Course course : courses) {
                System.out.printf("%s\n", course.getName());
            }
        }
    }
}

更新:域名委托

要使用服务帐户在您的 Google 帐户中创建课程,您需要模拟它。要实现此目的,您必须执行所谓的域范围委派。

由于您已经创建了服务帐户,我将跳转到域范围的委托授权:

    < li >转到您的GCP,为您的项目选择服务帐户。 < li >单击左边的三个垂直点,然后编辑 < li >在服务帐户详细信息中,单击显示全域委托,然后确保启用G Suite全域委托复选框被选中。 < li >单击保存以更新服务帐户,并返回到服务帐户表。可以看到一个新列“域范围的委托”。单击查看客户端ID,获取并记下客户端ID。

现在您必须授权您的用户,以便您的服务帐户可以模拟它。我没有写这些步骤,因为它太长了,但你可以在这里看到它们。

回到代码,我们必须选择凭据的设置方式。为了让事情更简单,我现在使用P12密钥文件,而不是JSON凭据:

GoogleCredential credential2 = new GoogleCredential.Builder()
                .setTransport(HTTP_TRANSPORT)
                .setJsonFactory(JSON_FACTORY)
                .setServiceAccountId("example@project.iam.gserviceaccount.com")
                .setServiceAccountScopes(SCOPES)
                .setServiceAccountUser("my_email@example.com")
                .setServiceAccountPrivateKeyFromP12File(new File(KEY_FILE_LOCATION)).build();

域范围的快速入门的其余部分在这里。

您的课堂服务生成器和新课程代码是正确的,应该可以使用新凭据。

 类似资料:
  • 问题内容: 该代码正在编译,但是当我们尝试执行该代码时,给出了“线程“ main”中的异常” Java.lang.NoSuchMethodError:main“ 问题答案: 该函数应这样声明

  • 问题内容: 我需要在Java中进行一次练习的帮助,也许我会在2小时内停留在此错误上。任何帮助都会很棒。 和: 我无法在Proizvod类的变量“ proizvodi”上输入字符串“ imer”或int“ cenar”。 有帮助吗?为什么我会收到此错误?谢谢! 问题答案: 扫描程序抛出此异常,以指示检索到的令牌与预期类型的​​模式不匹配,或者令牌超出预期类型的​​范围。

  • 问题内容: 我已经进行了大约一个小时的工作,并且对stackoverflow进行了问答,但是我没有找到解决问题的建议方案。很抱歉,如果这是重复的,但是找不到解决我特定问题的答案的任何重复问题。 我试图第一次从终端编写和编译Java程序(直到这一点为止,我一直在使用Eclipse for Java和VIM进行其他所有操作,但是我觉得是时候完全使用VIM了)。这是我当前的HelloWorld代码: 我

  • 任何帮助都将不胜感激。

  • 问题内容: 我正在使用Eclipse编译和运行我的Java代码。 这是我得到的错误。 这是我的代码 File.txt 我在项目的同一文件夹中创建了file.txt。 问题答案: 您的文件应直接位于项目文件夹下,而不应位于其他任何子文件夹内。 因此,如果您的项目文件夹为,则其文件夹结构(虽然不完整)应类似于:- 它不应该是文件夹。 或者,您可以提供以下相对于项目文件夹的路径,以在以下位置搜索文件:-

  • 问题内容: 我正在尝试在Android Studio 0.3.0中编译我的Android项目。今天我收到以下错误: 进行一些网络搜索使我相信此问题与JUnit有某种关系。但是,我没有在项目中使用JUnit。也许我无意中打开了某些选项?在这种情况下,如何在项目中禁用单元测试?有任何想法吗? 问题答案: 终于找到了。在“运行/调试配置”对话框中。禁用JUnit并重新编译。