验证 Azure 广告访问令牌时签名无效,但 id 令牌有效
Posted
技术标签:
【中文标题】验证 Azure 广告访问令牌时签名无效,但 id 令牌有效【英文标题】:Invalid signature while validating Azure ad access token, but id token works 【发布时间】:2018-01-01 04:44:43 【问题描述】:我在使用 jwt.io 验证我的 azure 广告访问令牌时收到无效签名。但是,我的 id 令牌验证得很好!
我已经看到并尝试了Invalid signature while validating Azure ad access token中建议的解决方案 和https://nicksnettravels.builttoroam.com/post/2017/01/24/Verifying-Azure-Active-Directory-JWT-Tokens.aspx 但两者都不适用于我的访问令牌。
访问和 Id 令牌是通过 Adal.js 生成的:
var endpoints =
"https://graph.windows.net": "https://graph.windows.net"
;
var configOptions =
tenant: "<ad>.onmicrosoft.com", // Optional by default, it sends common
clientId: "<app ID from azure portal>",
postLogoutRedirectUri: window.location.origin,
endpoints: endpoints,
window.authContext = new AuthenticationContext(configOptions);
为什么我可以验证我的 ID 令牌,但不能验证我的访问令牌?
【问题讨论】:
访问令牌是用句号(.)分隔的三部分吗? 请解码访问令牌,您在 HEADER 中看到过 nonce 吗? @RasmusW 两个令牌的格式都正确,我对每个令牌中的信息进行解码都没有问题。只有验证是个问题。 @NanYu 是的,随机数在标题中。 typ、alg、x5t 和 Kid 也是如此 看我的回复,nonce导致验证失败。 【参考方案1】:感谢Nan Yu,我设法获得了可以由任何公共jwt验证器验证的令牌,例如jwt.io (无法将我的评论放在 Nan Yu 答案下的 cmets 部分,因为它太长了)。
据我所知,Nan Yu 提到的discussion 中提到的一点是,默认情况下 Azure AD 为 Microsoft Graph 生成令牌,这些令牌使用特殊的签名机制,因此无法使用公共验证器验证签名(除了jwt.ms微软的验证器,很可能知道神秘的特殊处理是什么意思:))。
要获得可使用公共验证器验证的不用于 Microsoft Graph 的访问令牌,我必须:
删除任何与 Microsoft Graph 相关的范围(默认情况下,我只配置了一个范围User.Read
,因此在 appConfig > API 权限中将其删除)
为您的应用程序创建自定义范围(appConfig > 公开 API > 添加范围 ...)此范围将类似于 api://application-id/scope-name
在应用程序 API 权限中添加刚刚创建的范围(appConfig > API 权限 > 添加 api 权限 > 我的 API > 选择您的应用程序 > 委托权限 > 检查您的范围 > 添加权限)
然后在您的 openid 客户端范围中使用此范围,在我的情况下,我有:openid offline_access application-id/scope-name
请注意,在 openid 客户端配置中,新创建的范围使用不带 api:// 前缀(offline_access 我必须启用 refresh_token 如果不使用刷新令牌机制可以忽略)
【讨论】:
【参考方案2】:感谢@Antoine 我修复了我的代码。在这里,我将让我个人的适用于其他所有人的 vue.js 插件参考:
import PublicClientApplication from '@azure/msal-browser'
import Notify from 'quasar'
export class MsalService
_msal = null
_store = null
_loginRequest = null
constructor (appConfig, store)
this._store = store
this._msal = new PublicClientApplication(
auth:
clientId: appConfig.auth.clientId,
authority: appConfig.auth.authority
,
cache:
cacheLocation: 'localStorage'
)
this._loginRequest =
scopes: [`$appConfig.auth.clientId/.default`]
async handleResponse (response)
await this._store.dispatch('auth/setResponse', response)
const accounts = this._msal.getAllAccounts()
await this._store.dispatch('auth/setAccounts', accounts)
if (accounts.length > 0)
this._msal.setActiveAccount(accounts[0])
this._msal.acquireTokenSilent(this._loginRequest).then(async (accessTokenResponse) =>
// Acquire token silent success
// Call API with token
// let accessToken = accessTokenResponse.accessToken;
await this._store.dispatch('auth/setResponse', accessTokenResponse)
).catch((error) =>
Notify.create(
message: JSON.stringify(error),
color: 'red'
)
// Acquire token silent failure, and send an interactive request
if (error.errorMessage.indexOf('interaction_required') !== -1)
this._msal.acquireTokenPopup(this._loginRequest).then(async (accessTokenResponse) =>
// Acquire token interactive success
await this._store.dispatch('auth/setResponse', accessTokenResponse)
).catch((error) =>
// Acquire token interactive failure
Notify.create(
message: JSON.stringify(error),
color: 'red'
)
)
)
async login ()
// this._msal.handleRedirectPromise().then((res) => this.handleResponse(res))
// await this._msal.loginRedirect(this._loginRequest)
await this._msal.loginPopup(this._loginRequest).then((resp) => this.handleResponse(resp))
async logout ()
await this._store.dispatch('auth/setAccounts', [])
await this._msal.logout()
// "async" is optional;
// more info on params: https://quasar.dev/quasar-cli/boot-files
export default (
app,
store,
Vue
) =>
const msalInstance = new MsalService(
app.appConfig, store
)
Vue.prototype.$msal = msalInstance
app.msal = msalInstance
PD:使用 quasar 框架
【讨论】:
前端通常不应该验证令牌。它甚至不应该看它。因为知道它是一个有效的令牌,你会怎么做?您可能希望从 API 请求数据,并且 API 本身应该进行验证,否则,是什么阻止了某人调用您的 API 并声称令牌有效?文档中也有说明。 docs.microsoft.com/en-us/azure/active-directory/develop/…【参考方案3】:如果其他人有无效签名错误,您应该检查此评论:https://github.com/AzureAD/microsoft-authentication-library-for-js/issues/521#issuecomment-577400515
解决了我的配置问题。
本质上,如果您要获取访问令牌来访问您自己的资源服务器而不是 Graph API,则您的范围参数应该是 [CLIENT_ID]/.default
(如果您使用访问令牌来访问 Graph API,则不需要需要自己验证令牌)
【讨论】:
真正的救生员。由于有一个随机数,我多次重做了我的应用程序,但它不会验证【参考方案4】:请参考帖子:https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/609
但是如果查看 Jwt.Header 你会看到一个“nonce”。这意味着您需要特殊处理。正常处理会失败。
因此,如果访问令牌中包含随机数,使用 JWT.io 或 JwtSecurityToken 验证签名将不会成功。
【讨论】:
谢谢,那我就没有办法验证访问令牌了吗? 请提供令牌请求(删除租户和客户端ID等敏感信息),您可以使用提琴手或浏览器开发工具来捕获请求,我会检查为什么标头中包含nonce。此外,您无需验证 aad graph api 的访问令牌的签名。当使用 azure 广告访问令牌发送 api 调用时,graph api 服务器端将对其进行验证。如果您正在为自己的 api 获取令牌,您可以使用 owin 中间件验证访问令牌或手动验证 JWT 令牌。以上是关于验证 Azure 广告访问令牌时签名无效,但 id 令牌有效的主要内容,如果未能解决你的问题,请参考以下文章
JWT 令牌的签名无效 - Azure + Spring Boot
如何在 Java 中验证 Azure B2C id 令牌的 JWT 签名?