迁移到 People API 时出现 ACCESS_TOKEN_SCOPE_INSUFFICIENT 错误
Get ACCESS_TOKEN_SCOPE_INSUFFICIENT error migrating to People API
我有一个桌面 Java 应用程序,我正在从 Google 联系人 API 迁移到人员 API。我有一些工作。例如,我可以检索联系信息。但是当我尝试创建新联系人时,出现以下错误:
com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
POST https://people.googleapis.com/v1/people:createContact
{
"code" : 403,
"details" : [ {
"@type" : "type.googleapis.com/google.rpc.ErrorInfo",
"reason" : "ACCESS_TOKEN_SCOPE_INSUFFICIENT"
} ],
"errors" : [ {
"domain" : "global",
"message" : "Insufficient Permission",
"reason" : "insufficientPermissions"
} ],
"message" : "Request had insufficient authentication scopes.",
"status" : "PERMISSION_DENIED"
}
相关代码如下:
protected void createContact() throws Exception {
Credential credential = authorize(PeopleServiceScopes.CONTACTS, "people");
PeopleService service = new PeopleService.Builder(
httpTransport, JSON_FACTORY, credential).setApplicationName(APPLICATION_NAME).build();
Person contactToCreate = new Person();
List<Name> names = new ArrayList<Name>();
names.add(new Name().setGivenName("John").setFamilyName("Doe"));
contactToCreate.setNames(names);
Person createdContact = service.people().createContact(contactToCreate).execute();
System.out.println("CREATED Contact: " + createdContact.getNames().get(0).getDisplayName());
}
protected Credential authorize(String scope, String subDir) throws Exception {
File dataStoreDir = new File(System.getProperty("user.home"), ".store/myapp/" + cfg.dataStore + "/" + subDir);
// initialize the transport
httpTransport = GoogleNetHttpTransport.newTrustedTransport();
// initialize the data store factory
dataStoreFactory = new FileDataStoreFactory(dataStoreDir);
// load client secrets
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY,
new InputStreamReader(SyncMgr.class.getResourceAsStream("/client_secrets.json")));
if (clientSecrets.getDetails().getClientId().startsWith("Enter")
|| clientSecrets.getDetails().getClientSecret().startsWith("Enter ")) {
System.out.println(
"Enter Client ID and Secret from https://code.google.com/apis/console/?api=calendar "
+ "into /client_secrets.json");
System.exit(1);
}
// set up authorization code flow
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
httpTransport, JSON_FACTORY, clientSecrets,
Collections.singleton(scope)).setDataStoreFactory(dataStoreFactory).build();
// authorize
return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize(cfg.gUser);
}
当我第一次 运行 它时,我将范围设置为 CONTACTS_READONLY。我得到了同意屏幕。但是当我添加代码以创建新联系人时,我将范围更改为 CONTACTS。那是我收到 ACCESS_TOKEN_SCOPE_INSUFFICIENT 错误的时候。
我在另一个 post 中看到,当您更改范围时,我需要强制您的应用重新授权用户,以便您再次获得同意屏幕。但我不确定该怎么做。有什么建议吗?
谢谢。
22 年 1 月 4 日更新
我尝试了 Gabriel 关于删除对应用程序的访问权限的建议。删除访问权限后,我再次 运行 应用程序。这次我在 execute() 调用中遇到了这个错误:
com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request
POST https://oauth2.googleapis.com/token
{
"error" : "invalid_grant",
"error_description" : "Token has been expired or revoked."
}
甚至以前用于检索联系人的 execute() 语句现在也出现同样的错误。
我的应用程序还使用了日历 API。我没有碰那个代码。但是当我尝试使用它时,我得到了同样的“invalid_grant”错误。我现在该怎么办?
如果您希望再次检索同意屏幕,您可以按照此 documentation and then try to authorize the app again. As you mentioned, the error received is due to the scope that was granted with authorization was CONTACTS_READONLY instead of CONTACTS when checking the authorization scope for this specific create contacts method 中的步骤从您的帐户设置中删除对您的应用程序的访问权限。
您似乎在使用 People.createContact 方法。如果我们查看文档,我们会发现此方法需要用户同意以下权限范围
现在,如果我们检查您的代码,您似乎正在使用
Credential credential = authorize(PeopleServiceScopes.CONTACTS, "people");
这正是需要的范围。但是您最初只读了那里。因此,当您的代码 运行 第一次授权用户访问只读范围而不是完整的联系人范围时,您就卡住了。
这里的关键是这段代码
// set up authorization code flow
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
httpTransport, JSON_FACTORY, clientSecrets,
Collections.singleton(scope)).setDataStoreFactory(dataStoreFactory).build();
// authorize
return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize(cfg.gUser);
请注意,我不是 Java 开发人员,我是 .net 开发人员。图书馆非常接近,多年来我一直在用两种语言帮助解决这个问题。
dataStoreFactory 是存储用户同意的地方。在您的目录结构中的某个位置应该有一个 json 文件,其中包含与之关联的用户名,这就是您的系统重新加载它的方式。当您的代码运行时,它将在该目录中查找名称为 cfg.gUser 的文件。
Java 客户端库中应该有一种方法可以强制它重新请求用户授权。提示类型强制。但我将不得不环顾四周,看看如何在 java 中做到这一点。
现在最简单的解决方案是找到该目录并删除该用户的文件,或者只是将用户名 cfg.gUser 更改为 cfg.gUser +"test" 或其他会导致该名称的名称更改和文件名。强制它再次提示用户授权。
这次当它请求同意时,请注意它请求的权限范围。
令牌已过期或撤销。
这可能是因为您的刷新令牌即将过期。当您的应用程序处于测试阶段时,刷新令牌会在 7 天后过期或由 google 自动撤销。
这是 Google 去年左右添加的新内容。不幸的是,如果刷新令牌以这种方式过期,则客户端库未设计为再次请求访问。
我有一个桌面 Java 应用程序,我正在从 Google 联系人 API 迁移到人员 API。我有一些工作。例如,我可以检索联系信息。但是当我尝试创建新联系人时,出现以下错误:
com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
POST https://people.googleapis.com/v1/people:createContact
{
"code" : 403,
"details" : [ {
"@type" : "type.googleapis.com/google.rpc.ErrorInfo",
"reason" : "ACCESS_TOKEN_SCOPE_INSUFFICIENT"
} ],
"errors" : [ {
"domain" : "global",
"message" : "Insufficient Permission",
"reason" : "insufficientPermissions"
} ],
"message" : "Request had insufficient authentication scopes.",
"status" : "PERMISSION_DENIED"
}
相关代码如下:
protected void createContact() throws Exception {
Credential credential = authorize(PeopleServiceScopes.CONTACTS, "people");
PeopleService service = new PeopleService.Builder(
httpTransport, JSON_FACTORY, credential).setApplicationName(APPLICATION_NAME).build();
Person contactToCreate = new Person();
List<Name> names = new ArrayList<Name>();
names.add(new Name().setGivenName("John").setFamilyName("Doe"));
contactToCreate.setNames(names);
Person createdContact = service.people().createContact(contactToCreate).execute();
System.out.println("CREATED Contact: " + createdContact.getNames().get(0).getDisplayName());
}
protected Credential authorize(String scope, String subDir) throws Exception {
File dataStoreDir = new File(System.getProperty("user.home"), ".store/myapp/" + cfg.dataStore + "/" + subDir);
// initialize the transport
httpTransport = GoogleNetHttpTransport.newTrustedTransport();
// initialize the data store factory
dataStoreFactory = new FileDataStoreFactory(dataStoreDir);
// load client secrets
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY,
new InputStreamReader(SyncMgr.class.getResourceAsStream("/client_secrets.json")));
if (clientSecrets.getDetails().getClientId().startsWith("Enter")
|| clientSecrets.getDetails().getClientSecret().startsWith("Enter ")) {
System.out.println(
"Enter Client ID and Secret from https://code.google.com/apis/console/?api=calendar "
+ "into /client_secrets.json");
System.exit(1);
}
// set up authorization code flow
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
httpTransport, JSON_FACTORY, clientSecrets,
Collections.singleton(scope)).setDataStoreFactory(dataStoreFactory).build();
// authorize
return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize(cfg.gUser);
}
当我第一次 运行 它时,我将范围设置为 CONTACTS_READONLY。我得到了同意屏幕。但是当我添加代码以创建新联系人时,我将范围更改为 CONTACTS。那是我收到 ACCESS_TOKEN_SCOPE_INSUFFICIENT 错误的时候。
我在另一个 post 中看到,当您更改范围时,我需要强制您的应用重新授权用户,以便您再次获得同意屏幕。但我不确定该怎么做。有什么建议吗?
谢谢。
22 年 1 月 4 日更新
我尝试了 Gabriel 关于删除对应用程序的访问权限的建议。删除访问权限后,我再次 运行 应用程序。这次我在 execute() 调用中遇到了这个错误:
com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request
POST https://oauth2.googleapis.com/token
{
"error" : "invalid_grant",
"error_description" : "Token has been expired or revoked."
}
甚至以前用于检索联系人的 execute() 语句现在也出现同样的错误。
我的应用程序还使用了日历 API。我没有碰那个代码。但是当我尝试使用它时,我得到了同样的“invalid_grant”错误。我现在该怎么办?
如果您希望再次检索同意屏幕,您可以按照此 documentation and then try to authorize the app again. As you mentioned, the error received is due to the scope that was granted with authorization was CONTACTS_READONLY instead of CONTACTS when checking the authorization scope for this specific create contacts method 中的步骤从您的帐户设置中删除对您的应用程序的访问权限。
您似乎在使用 People.createContact 方法。如果我们查看文档,我们会发现此方法需要用户同意以下权限范围
现在,如果我们检查您的代码,您似乎正在使用
Credential credential = authorize(PeopleServiceScopes.CONTACTS, "people");
这正是需要的范围。但是您最初只读了那里。因此,当您的代码 运行 第一次授权用户访问只读范围而不是完整的联系人范围时,您就卡住了。
这里的关键是这段代码
// set up authorization code flow
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
httpTransport, JSON_FACTORY, clientSecrets,
Collections.singleton(scope)).setDataStoreFactory(dataStoreFactory).build();
// authorize
return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize(cfg.gUser);
请注意,我不是 Java 开发人员,我是 .net 开发人员。图书馆非常接近,多年来我一直在用两种语言帮助解决这个问题。
dataStoreFactory 是存储用户同意的地方。在您的目录结构中的某个位置应该有一个 json 文件,其中包含与之关联的用户名,这就是您的系统重新加载它的方式。当您的代码运行时,它将在该目录中查找名称为 cfg.gUser 的文件。
Java 客户端库中应该有一种方法可以强制它重新请求用户授权。提示类型强制。但我将不得不环顾四周,看看如何在 java 中做到这一点。
现在最简单的解决方案是找到该目录并删除该用户的文件,或者只是将用户名 cfg.gUser 更改为 cfg.gUser +"test" 或其他会导致该名称的名称更改和文件名。强制它再次提示用户授权。
这次当它请求同意时,请注意它请求的权限范围。
令牌已过期或撤销。
这可能是因为您的刷新令牌即将过期。当您的应用程序处于测试阶段时,刷新令牌会在 7 天后过期或由 google 自动撤销。
这是 Google 去年左右添加的新内容。不幸的是,如果刷新令牌以这种方式过期,则客户端库未设计为再次请求访问。