如何验证来自不同发行者的 jwt 令牌

Posted

技术标签:

【中文标题】如何验证来自不同发行者的 jwt 令牌【英文标题】:How to validate jwt token from different issuer 【发布时间】:2019-09-24 19:20:06 【问题描述】:

我正在使用可操作消息(使用 Outlook Web 应用)来调用逻辑应用。因此,我在请求中获得了 Bearer 令牌:

"Action-Authorization": "Bearer eyJ0eXAi..."

调用栈: Outlook web app -> Logic App -> my endpoint hosted in azure

现在我尝试使用 jwt.io 验证令牌,但收到签名无效的问题。 所以我尝试在 c# 中使用JwtSecurityTokenHandler 对其进行验证。

我尝试将https://substrate.office.com/sts/ 添加到颁发者列表中,但似乎验证甚至没有到达那里。

我正在使用以下代码来验证 office.com 颁发的 jwt 令牌:

bool IsAuthorized(HttpActionContext actionContext)
        
            var valid = base.IsAuthorized(actionContext);

            // Custom handle for Bearer token, when invalid from base-class
            if (!valid && actionContext.Request.Headers.Authorization.Scheme == "Bearer")
            
                var jwt = actionContext.Request.Headers.Authorization.Parameter;
                var th = new JwtSecurityTokenHandler();
                var sjwt = th.ReadToken(jwt) as JwtSecurityToken;                

                var validationParameters = new TokenValidationParameters
                
                    ValidateIssuerSigningKey = false,
                    //IssuerSigningToken = sjwt,
                    ValidateActor = false,
                    ValidateAudience = false,
                    ValidateIssuer = true,
                    ValidateLifetime = true,
                    ValidIssuers = new[]  "https://substrate.office.com/sts/" ,
                    ValidAudiences = new[] "https://XXX.logic.azure.com"
        ;

                SecurityToken validatedToken;
                try
                
                    th.ValidateToken(jwt, validationParameters, out validatedToken);
                
                catch (Exception ex)
                
                    return false;
                
            

            return valid;
        

这是我的 JWT 令牌:

我遇到了异常:

IDX10500: Signature validation failed. Unable to resolve SecurityKeyIdentifier: 'SecurityKeyIdentifier
    (
    IsReadOnly = False,
    Count = 2,
    Clause[0] = X509ThumbprintKeyIdentifierClause(Hash = 0x818...),
    Clause[1] = System.IdentityModel.Tokens.NamedKeySecurityKeyIdentifierClause
    )
', ...

即使我设置了ValidateIssuerSigningKey = false

有没有办法接受https://substrate.office.com/sts/ 作为有效的颁发者?

【问题讨论】:

你能告诉我们你的代币是什么样的吗?发行者应该是“iss”声明中的值 ValidateIssuerSigningKey 也有不同的用途。在这里验证令牌是否已由right\wanted 授权服务器颁发。您不应将此属性设置为 false 我添加了令牌。 ValidateIssuerSigningKey=false 仅用于测试目的,我认为这会减轻我得到的异常。 【参考方案1】:

异常表示“签名验证失败”。 要解决这个问题,我们不能只将所需的有效颁发者添加到ValidIssuers,我们需要验证令牌是从颁发者本身颁发的。

特别是对于 office.com 作为发行者的这种情况,我在这里找到了预期的密钥 (JWK - JSON Web Key): https://substrate.office.com/sts/common/discovery/keys (也是https://substrate.office.com/sts/common/.well-known/openid-configuration)

这是工作代码:

bool IsAuthorized(HttpActionContext actionContext)
        
            var valid = base.IsAuthorized(actionContext);

            // Custom handle for Bearer token, when invalid from base-class
            if (!valid && actionContext.Request.Headers.Authorization.Scheme == "Bearer")
            
                var jwt = actionContext.Request.Headers.Authorization.Parameter;
                var th = new JwtSecurityTokenHandler();

                var validationParameters = new TokenValidationParameters
                
                    ValidateAudience = false,
                    ValidateLifetime = true,
                    ValidateIssuer = true,
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new JsonWebKey(GetJWK()),
                    ValidIssuers = new[]  "https://substrate.office.com/sts/" 
                ;

                Microsoft.IdentityModel.Tokens.SecurityToken validatedToken;
                try
                
                    var claims = th.ValidateToken(jwt, validationParameters, out validatedToken);
                    valid = true;
                
                catch (Exception ex)
                
                    valid = false;
                
            

            return valid;
        

        // Get the token from configuration
        private string GetJWK()
        
            return ConfigurationManager.AppSettings["ida:jwks_json"];
        

在 appsettings 中,我将网站上的 RSA 密钥用于验证令牌,如下所示:

"kty":"RSA","use":"sig","kid":"gY...","x5t":"gY...","n":"2w...","e":"AQAB","x5c":["MII..."]

【讨论】:

提示:您正在使用大量手动步骤,可以通过结合使用 Microsoft.IdentityModel.Token 和 Microsoft.IdentityModel.Protocols Nugets 来避免这些步骤。

以上是关于如何验证来自不同发行者的 jwt 令牌的主要内容,如果未能解决你的问题,请参考以下文章

如何为OAuth2 JWT验证共享公钥?

如何在 Go 中验证来自 AWS Cognito 的 JWT 令牌?

如何在 CodeIgniter 3.x 中为来自客户端的每个请求验证 JWT 令牌

如何跨不同 API 对 JSON Web 令牌 (JWT) 进行身份验证?

Microsoft 帐户 JWT 身份验证令牌如何签名?

openid connect owin 如何验证来自 Azure AD 的令牌?