在 Google Apps 脚本中使用管理员服务帐户 API 和 OAuth2 库将用户添加到 Google 组
Using a Service Account for Admin API with OAuth2 library in Google Apps Script to Add A User to a Google Group
编辑:
URL 需要是 https://admin.googleapis.com/admin/directory/v1/groups/{groupKey}/members
而不是 https://admin.googleapis.com/admin/directory/v1/groups/{groupKey}/members/insert
(没有 insert
,即使它是 insert
方法)
我正在尝试使用 Google Apps 脚本构建一个脚本,该脚本能够将用户添加到具有服务帐户的 Google 组。现在,使用 AdminDirectory
服务很简单,所以这段代码有效:
const addUser = email => {
const member = AdminDirectory.Members.insert(
{ email, role: 'MEMBER' },
'test-group@domain.com'
);
};
但是此服务需要超级用户权限。因此我决定使用服务帐户。
我创建了服务帐户并完成了 the whole checklist:
- 我生成了 JSON 密钥
- 启用全域委派
- 在管理控制台 > 安全 > API 控制 > 全域授权中,我添加了以下范围:
- 然后我构建了这个使用 OAuth2 library:
的解决方案
const addUserWithServiceAccount = email => {
const serviceAccount = {
type: 'service_account',
project_id: 'my-tools-324016',
private_key_id: '021623b...',
private_key: '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----\n',
client_email: 'SERVICE-ACCOUNT-EMAIL',
client_id: '1059879019...',
auth_uri: 'https://accounts.google.com/o/oauth2/auth',
token_uri: 'https://oauth2.googleapis.com/token',
auth_provider_x509_cert_url: 'https://www.googleapis.com/oauth2/v1/certs',
client_x509_cert_url:
'https://www.googleapis.com/robot/v1/metadata/x509/...',
};
const _getAdminService = serviceAccount => {
return OAuth2.createService('admin-sdk-test')
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
.setPrivateKey(serviceAccount.private_key)
.setIssuer(serviceAccount.client_email)
.setPropertyStore(PropertiesService.getScriptProperties())
.setCache(CacheService.getUserCache())
.setLock(LockService.getUserLock())
.setScope([
'https://www.googleapis.com/auth/admin.directory.group',
'https://www.googleapis.com/auth/admin.directory.group.member',
'https://www.googleapis.com/auth/admin.directory.user',
]);
};
const _executeWithAuth2 = (groupKey, email) => {
console.log('_executeWithAuth2()');
const adminService = _getAdminService(serviceAccount);
if (!adminService.hasAccess()) {
Logger.log('ERROR n' + adminService.getLastError());
return;
}
const url = `https://admin.googleapis.com/admin/directory/v1/groups/${groupKey}/members/insert?memberKey=${email}`;
const headers = {
Authorization: `Bearer ${adminService.getAccessToken()}`,
// 'Content-Type': 'application/json',
};
const options = {
method: 'put',
headers,
contentType: 'application/json',
payload: JSON.stringify({
email,
role: 'MEMBER',
kind: 'admin#directory#member',
type: 'USER',
}),
muteHttpExceptions: true,
};
console.log(`fetch(${url}, ${JSON.stringify(options, null, 2)})`);
const result = UrlFetchApp.fetch(url, options).getContentText();
console.log(result);
return result;
};
return _executeWithAuth2('test-group@domain', email);
};
现在当我 运行 它时,我收到以下响应错误:
{
"error": {
"code": 403,
"message": "Not Authorized to access this resource/api",
"errors": [
{
"message": "Not Authorized to access this resource/api",
"domain": "global",
"reason": "forbidden"
}
]
}
}
当我将 PUT
切换为 POST
时,我得到:
The requested URL /admin/directory/v1/groups/test-group@domain.com/members/insert?memberKey=user@domain.com
was not found on this server.
但是这种方法使用服务帐户 。尽管我找不到特定于管理目录的解决方案,但我希望它能以同样的方式工作。
我在这里错过了什么?
服务帐户也没有超级用户权限
这就是您收到 Not Authorized
错误的原因。
- 服务帐户需要impersonate具有相应权限的超级用户。
- 为此,除了启用全域委派外,您还需要以编程方式指定模拟用户,方法是将他设置为 subject 和
.setSubject("EMAIL OF SUPER USER")
。
样本:
const _getAdminService = serviceAccount => {
return OAuth2.createService('admin-sdk-test')
.setSubject("EMAIL OF SUPER USER")
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
.setPrivateKey(serviceAccount.private_key)
.setIssuer(serviceAccount.client_email)
.setPropertyStore(PropertiesService.getScriptProperties())
.setCache(CacheService.getUserCache())
.setLock(LockService.getUserLock())
.setScope([
'https://www.googleapis.com/auth/admin.directory.group',
'https://www.googleapis.com/auth/admin.directory.group.member',
'https://www.googleapis.com/auth/admin.directory.user',
]);
};
编辑:
URL 需要是 https://admin.googleapis.com/admin/directory/v1/groups/{groupKey}/members
而不是 https://admin.googleapis.com/admin/directory/v1/groups/{groupKey}/members/insert
(没有 insert
,即使它是 insert
方法)
我正在尝试使用 Google Apps 脚本构建一个脚本,该脚本能够将用户添加到具有服务帐户的 Google 组。现在,使用 AdminDirectory
服务很简单,所以这段代码有效:
const addUser = email => {
const member = AdminDirectory.Members.insert(
{ email, role: 'MEMBER' },
'test-group@domain.com'
);
};
但是此服务需要超级用户权限。因此我决定使用服务帐户。
我创建了服务帐户并完成了 the whole checklist:
- 我生成了 JSON 密钥
- 启用全域委派
- 在管理控制台 > 安全 > API 控制 > 全域授权中,我添加了以下范围:
- 然后我构建了这个使用 OAuth2 library: 的解决方案
const addUserWithServiceAccount = email => {
const serviceAccount = {
type: 'service_account',
project_id: 'my-tools-324016',
private_key_id: '021623b...',
private_key: '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----\n',
client_email: 'SERVICE-ACCOUNT-EMAIL',
client_id: '1059879019...',
auth_uri: 'https://accounts.google.com/o/oauth2/auth',
token_uri: 'https://oauth2.googleapis.com/token',
auth_provider_x509_cert_url: 'https://www.googleapis.com/oauth2/v1/certs',
client_x509_cert_url:
'https://www.googleapis.com/robot/v1/metadata/x509/...',
};
const _getAdminService = serviceAccount => {
return OAuth2.createService('admin-sdk-test')
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
.setPrivateKey(serviceAccount.private_key)
.setIssuer(serviceAccount.client_email)
.setPropertyStore(PropertiesService.getScriptProperties())
.setCache(CacheService.getUserCache())
.setLock(LockService.getUserLock())
.setScope([
'https://www.googleapis.com/auth/admin.directory.group',
'https://www.googleapis.com/auth/admin.directory.group.member',
'https://www.googleapis.com/auth/admin.directory.user',
]);
};
const _executeWithAuth2 = (groupKey, email) => {
console.log('_executeWithAuth2()');
const adminService = _getAdminService(serviceAccount);
if (!adminService.hasAccess()) {
Logger.log('ERROR n' + adminService.getLastError());
return;
}
const url = `https://admin.googleapis.com/admin/directory/v1/groups/${groupKey}/members/insert?memberKey=${email}`;
const headers = {
Authorization: `Bearer ${adminService.getAccessToken()}`,
// 'Content-Type': 'application/json',
};
const options = {
method: 'put',
headers,
contentType: 'application/json',
payload: JSON.stringify({
email,
role: 'MEMBER',
kind: 'admin#directory#member',
type: 'USER',
}),
muteHttpExceptions: true,
};
console.log(`fetch(${url}, ${JSON.stringify(options, null, 2)})`);
const result = UrlFetchApp.fetch(url, options).getContentText();
console.log(result);
return result;
};
return _executeWithAuth2('test-group@domain', email);
};
现在当我 运行 它时,我收到以下响应错误:
{
"error": {
"code": 403,
"message": "Not Authorized to access this resource/api",
"errors": [
{
"message": "Not Authorized to access this resource/api",
"domain": "global",
"reason": "forbidden"
}
]
}
}
当我将 PUT
切换为 POST
时,我得到:
The requested URL
/admin/directory/v1/groups/test-group@domain.com/members/insert?memberKey=user@domain.com
was not found on this server.
但是这种方法使用服务帐户
我在这里错过了什么?
服务帐户也没有超级用户权限
这就是您收到 Not Authorized
错误的原因。
- 服务帐户需要impersonate具有相应权限的超级用户。
- 为此,除了启用全域委派外,您还需要以编程方式指定模拟用户,方法是将他设置为 subject 和
.setSubject("EMAIL OF SUPER USER")
。
样本:
const _getAdminService = serviceAccount => {
return OAuth2.createService('admin-sdk-test')
.setSubject("EMAIL OF SUPER USER")
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
.setPrivateKey(serviceAccount.private_key)
.setIssuer(serviceAccount.client_email)
.setPropertyStore(PropertiesService.getScriptProperties())
.setCache(CacheService.getUserCache())
.setLock(LockService.getUserLock())
.setScope([
'https://www.googleapis.com/auth/admin.directory.group',
'https://www.googleapis.com/auth/admin.directory.group.member',
'https://www.googleapis.com/auth/admin.directory.user',
]);
};