Java应用使用ClientSecretCredential调用Microsoft Graph时遭遇Authorization_RequestDenied权限不足问题
我在Java应用里尝试用ClientSecretCredential(客户端密钥验证方式)调用Microsoft Graph的/users接口时,一直收到403 Forbidden错误,但换成DeviceCodeCredential(交互式用户登录)就能正常运行。以下是我的具体情况:
我的ClientSecretCredential代码
List SCOPES = Arrays.asList("https://graph.microsoft.com/.default"); final ClientSecretCredential credential = new ClientSecretCredentialBuilder() .clientId(applicationId) .clientSecret(secret) .tenantId(tenantId) .build(); final TokenCredentialAuthProvider authProvider_new = new TokenCredentialAuthProvider(SCOPES, credential); GraphServiceClient graphClient = GraphServiceClient .builder() .authenticationProvider(authProvider) .buildClient(); graphClient.users().buildRequest().get();
项目依赖
compile group: 'com.microsoft.azure', name: 'azure-spring-boot', version: '2.3.5' compile group: 'com.google.guava', name: 'guava', version: '28.2-jre' compile group: 'com.azure', name: 'azure-identity', version: '1.2.5' compile group: 'com.microsoft.graph', name: 'microsoft-graph', version: '3.5.0'
错误详情
SEVERE: Throwable detail: com.microsoft.graph.http.GraphServiceException: Error code: Authorization_RequestDenied
Error message: Insufficient privileges to complete the operation.
GET https://graph.microsoft.com/v1.0/users
SdkVersion : graph-java/v3.5.0
403 : Forbidden
已完成的操作
- 已经在Azure Active Directory里给应用添加了权限,并且完成了管理员同意
- 应用目前拥有Azure Rights Management Services的权限:
Application.Read.All、Content.DelegatedReader、Content.SuperUser
我希望用ClientSecretCredential而非交互式流程,请问该怎么解决这个403问题?
这里有几个你可以排查和修复的点:
1. 确认你添加的是Microsoft Graph的应用权限,不是委托权限
ClientSecretCredential用的是客户端凭据流,需要应用级别的权限;而DeviceCodeCredential是委托权限流,用的是当前登录用户的权限。你现在提到的权限都是Azure RMS的,没有针对Microsoft Graph的用户读取权限:
- 登录Azure门户,找到你的应用注册 -> 进入API权限页面
- 点击添加权限 -> 选择Microsoft Graph -> 切换到应用权限标签
- 搜索
User.Read.All权限并添加,然后点击授予管理员同意(确保是针对整个租户的同意)
2. 修复代码里的笔误
你代码里创建了authProvider_new,但构建GraphServiceClient的时候用的是authProvider,这会导致认证失败:
// 错误代码 final TokenCredentialAuthProvider authProvider_new = new TokenCredentialAuthProvider(SCOPES, credential); GraphServiceClient graphClient = GraphServiceClient .builder() .authenticationProvider(authProvider) // 这里应该用authProvider_new .buildClient(); // 修正后 final TokenCredentialAuthProvider authProvider = new TokenCredentialAuthProvider(SCOPES, credential); GraphServiceClient graphClient = GraphServiceClient .builder() .authenticationProvider(authProvider) .buildClient();
3. 验证Access Token是否包含正确权限
你可以解码获取到的access token(用jwt.ms工具就行),检查roles字段里是否有User.Read.All。如果没有,说明权限还没生效,或者管理员同意没成功:
- 可以先通过代码打印token,或者用Postman调用Azure AD的token端点获取token来验证
- 如果roles里没有目标权限,重新执行一次管理员同意操作,等待10-15分钟再测试
4. 确认权限范围是否正确
你的scope用的是https://graph.microsoft.com/.default,这个是对的,客户端凭据流里这个scope会自动包含所有已授予的应用权限,所以不用改这个。
按照这几个步骤排查,应该就能解决403的问题了。
内容的提问来源于stack exchange,提问作者RMonster

