MSAL刷新令牌后访问Dynamics 365 OData遇AADSTS65001错误
我的Web应用基于ConfidentialClientApplication,为用户执行以下后台任务:
- 轮询电子邮件收件箱并导入新邮件——使用Microsoft Graph API(权限为
Mail.ReadWrite) - 轮询Dynamics 365 Finance and Operations的新增/删除/变更数据——使用OData端点,例如
$DYN365_BASE_URL/data/Companies(权限为Connector.FullAccess)
应用注册已配置对应权限,用户通过授权码流完成MS365租户授权后,我获取到access_token和refresh_token(使用MSAL for Java),此时可正常读取邮件和Dynamics 365 OData数据。
但60分钟后access_token过期,用refresh_token获取新令牌后,仍能正常读取邮件,访问Dynamics 365 OData时却抛出异常:
AADSTS65001: The user or administrator has not consented to use the application.
请问:
- 该异常产生的原因是什么?
- 如何修改以实现令牌刷新后仍能持续访问Dynamics 365 OData?
1. 异常产生的原因
- 权限范围不匹配:刷新令牌时请求的权限范围未包含Dynamics 365所需的
Connector.FullAccess,导致新生成的access_token没有访问Dynamics 365的权限。 - 权限同意状态差异:Microsoft Graph的权限在初始授权时已完成用户/管理员同意,但Dynamics 365的权限未被正确纳入同意范围,或者刷新令牌时未携带对应资源标识符,导致AAD无法识别该权限的已同意状态。
- 令牌受众错误:刷新时未指定Dynamics 365的资源URI(或scope),生成的
access_token受众仅为Microsoft Graph,无法用于Dynamics 365 OData请求。
2. 解决方法
方法一:刷新令牌时明确包含Dynamics 365的权限范围
使用MSAL for Java刷新令牌时,需在请求中指定包含Connector.FullAccess的scope集合,确保新令牌覆盖所有所需权限。示例代码逻辑:
// 构建包含所有所需权限的scope集合 Set<String> scopes = new HashSet<>(); scopes.add("https://dynamics.com/Connector.FullAccess"); // 替换为实际的Dynamics资源URI+权限 scopes.add("Mail.ReadWrite"); // 基于refresh_token获取包含完整权限的新令牌 IAuthenticationResult result = confidentialClientApplication .acquireToken(AcquireTokenParameters .builder(scopes) .refreshToken(refreshToken) .build()) .join();
方法二:初始授权时确保refresh_token包含所有权限
在用户首次授权的流程中,必须将Microsoft Graph和Dynamics 365的权限scope同时传入授权请求,且必须包含offline_access以获取可刷新的refresh_token。例如授权码流的请求URL需包含:scope=Mail.ReadWrite https://dynamics.com/Connector.FullAccess offline_access
方法三:针对不同资源单独请求令牌
如果两种资源的权限范围差异较大,可分开维护令牌:针对Microsoft Graph和Dynamics 365分别使用refresh_token获取对应资源的access_token,确保每个令牌的受众和权限完全匹配对应服务。
内容的提问来源于stack exchange,提问作者GameScripting

