使用Google API服务账号调用users.get遇401 Unauthorized错误求助
通过OAuth 2.0客户端应用直接调用users.get接口正常,但需要浏览器授权不符合需求。改用服务账号后,已完成域范围委派、创建JSON密钥,成功获取令牌但请求始终返回401错误。
错误信息
System.AggregateException HResult=0x80131500 Message=Um ou mais erros. Source=mscorlib StackTrace: at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification) at googleteste.Program.Main(String[] args) in \source\repos\googleteste\googleteste\Program.cs:line 36 Inner Exception 1: HttpRequestException: O código de status de resposta não indica êxito: 401 (Unauthorized).
相关代码
获取令牌的方法
public static async Task<string> GetAccessTokenFromJSONKeyAsync(string jsonKeyFilePath, params string[] scopes) { using (var stream = new FileStream(jsonKeyFilePath, FileMode.Open, FileAccess.Read)) { return await GoogleCredential .FromStream(stream) // Loads key file .CreateScoped(scopes) // Gathers scopes requested .UnderlyingCredential // Gets the credentials .GetAccessTokenForRequestAsync(); // Gets the Access Token } } public static string GetAccessTokenFromJSONKey(string jsonKeyFilePath, params string[] scopes) { return GetAccessTokenFromJSONKeyAsync(jsonKeyFilePath, scopes).Result; }
请求API的代码
var token = GoogleServiceAccount.GetAccessTokenFromJSONKeyAsync( "Keys/wneniac-2744e4a55337.json", new[] { "https://www.googleapis.com/auth/admin.directory.user", "https://www.googleapis.com/auth/admin.directory.user.security", "https://www.googleapis.com/auth/contacts", "https://www.googleapis.com/auth/gmail.modify" }); Console.WriteLine(new HttpClient().GetStringAsync($"https://admin-admin.googleapis.com/admin/directory/v1/users/usertosearch?access_token={token}&domain= ").Result);
解决方法
服务账号调用Admin Directory API时,必须模拟域内的管理员账号(Directory API需要管理员权限,服务账号本身无域内权限,需通过域范围委派模拟具体用户),这是导致401的核心原因。以下是具体修复步骤:
1. 修改令牌获取逻辑,添加用户模拟
在获取令牌时,通过CreateWithUser方法指定要模拟的域管理员邮箱(需为域内超级管理员账号)。修改后的方法:
public static async Task<string> GetAccessTokenFromJSONKeyAsync(string jsonKeyFilePath, string impersonateUserEmail, params string[] scopes) { using (var stream = new FileStream(jsonKeyFilePath, FileMode.Open, FileAccess.Read)) { return await GoogleCredential .FromStream(stream) .CreateScoped(scopes) .CreateWithUser(impersonateUserEmail) // 关键:添加用户模拟 .UnderlyingCredential .GetAccessTokenForRequestAsync(); } }
2. 修正API请求地址与参数
- 错误地址:
https://admin-admin.googleapis.com,正确地址为https://admin.googleapis.com domain参数不能留空,需填写实际域名- 避免用
.Result阻塞异步方法,全程使用async/await
修改后的请求代码:
// 替换为你的域管理员邮箱和实际域名 var adminEmail = "admin@yourdomain.com"; var domain = "yourdomain.com"; var token = await GoogleServiceAccount.GetAccessTokenFromJSONKeyAsync( "Keys/wneniac-2744e4a55337.json", adminEmail, new[] { "https://www.googleapis.com/auth/admin.directory.user" }); // 仅保留必要权限 using (var httpClient = new HttpClient()) { var url = $"https://admin.googleapis.com/admin/directory/v1/users/usertosearch?domain={domain}"; httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); var response = await httpClient.GetStringAsync(url); Console.WriteLine(response); }
3. 验证域范围委派配置
确认以下配置无误:
- 服务账号已在Google Cloud控制台开启域范围委派
- 在Google Workspace管理控制台(admin.google.com)的「安全 -> API控制 -> 域范围委派」中,已添加服务账号的客户端ID,并授权了所需的API范围(如
https://www.googleapis.com/auth/admin.directory.user) - 模拟的管理员账号为域内超级管理员,无API访问限制
内容的提问来源于stack exchange,提问作者Rodrigo da Silva Nascimento
相关产品推荐
相关产品推荐

