Vert.x后端验证Microsoft Graph API JWT令牌失败及方案咨询
我有一个基于Vert.x 4.4.2的Web应用后端,目标是通过Azure AD完成用户认证并获取JWT令牌,以此调用Microsoft Graph API。当前采用OAuth2授权码流程(Vert.x OAuth2客户端),流程如下:
- 应用调用后端HTTP认证端点发起认证
- 后端将用户重定向至SSO
- SSO向后端发送授权码
- 后端调用SSO的HTTP端点获取令牌
- 后端验证令牌
- 后端携带令牌重定向回应用
使用默认范围(clientId/.default)时运行正常,但切换为Team.ReadBasic.All、Chat.ReadWrite、ChatMessage.Read等范围后,后端令牌验证出现签名错误:
11:38:26.199 [vert.x-eventloop-thread-15] ERROR io.vertx.ext.web.RoutingContext - Unhandled exception in router
java.lang.RuntimeException: Signature verification failed
at io.vertx.ext.auth.impl.jose.JWT.decode(JWT.java:312)
at io.vertx.ext.auth.impl.jose.JWT.decode(JWT.java:177)
据了解,用于访问Graph API的JWT令牌不应被验证,因此咨询两个问题:
- 是否可在Vert.x中禁用令牌验证以使用不同范围?
- 若不可行,最佳实践是什么?是否使用默认范围令牌访问应用,再由应用单独请求另一令牌调用Graph API?
1. 在Vert.x中禁用令牌验证
可以通过配置Vert.x的JWT认证提供者跳过签名验证。具体是在创建JWTAuth实例时,设置skipSignatureValidation参数为true:
JWTAuthOptions options = new JWTAuthOptions() .setSkipSignatureValidation(true); JWTAuth jwtAuth = JWTAuth.create(vertx, options);
但要注意,这种方式会关闭所有令牌的签名验证,存在安全风险,仅适合在明确知晓令牌来源绝对可信的场景下临时使用,不建议用于生产环境。
2. 生产环境最佳实践
更安全合理的方案是采用双令牌模式:
- 身份令牌(ID Token):使用
openid、profile这类基础范围获取,用于后端验证用户身份,完成应用自身的认证流程。这个令牌是Azure AD颁发给你的应用的,签名可以正常验证。 - 访问令牌(Access Token):单独请求带有Graph API权限范围(
Team.ReadBasic.All、Chat.ReadWrite等)的令牌,专门用来调用Microsoft Graph API。这个令牌是颁发给Graph API的,后端无需验证其签名,直接携带它调用接口即可。
在Vert.x的OAuth2流程中,你可以在一次授权码请求中同时获取身份令牌和访问令牌,也可以分两次请求:
- 第一次授权码流程请求
openid、profile范围,拿到ID Token完成用户身份验证; - 第二次利用刷新令牌或重新发起授权,请求Graph API的权限范围,拿到Access Token用于调用API。
这种方式既保证了应用自身认证的安全性,又能正常获取调用Graph API所需的令牌。
内容的提问来源于stack exchange,提问作者horak90

