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

nx7onnlm  于 2023-06-24  发布在  其他
关注(0)|答案(2)|浏览(185)

我正在使用可操作的消息(与Outlook Web应用程序)调用逻辑应用程序。因此,我在请求中获得了一个承载令牌:
“操作-授权”:“Bearer eye J0eXai...”
调用堆栈:Outlook web app -> Logic App -> my endpoint hosted in azure
现在,我试图通过www.example.com验证令牌jwt.io,但得到签名无效的问题。所以我试着用JwtSecurityTokenHandler在c#中验证它。
我试图将https://substrate.office.com/sts/添加到发行者列表中,但似乎验证甚至没有到达那里。
我使用以下代码验证www.example.com发布的jwt令牌office.com:

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/接受为有效的颁发者?

0qx6xfy6

0qx6xfy61#

异常显示“签名验证失败”。为了解决这个问题,我们不能只将想要的有效发行者添加到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..."]}
bvjxkvbb

bvjxkvbb2#

如果您使用的是OAuth规范JWT,那么验证票证的密钥可以通过'http://auth.myApplication.com/.well-know/jwks.json'检索,并且内置的JwtSecurityTokenHandler也可以使用,即使您使用的是旧的System. IdentityModel. Tokens. Jwt,它没有原生内置调用。
OWIN示例:

public static class AppBuilderExtensions
{
    /// <summary>
    /// Use JWT Authentication.
    /// </summary>
    /// <param name="app">The <see cref="IAppBuilder"/> to use.</param>
    /// <param name="audiences">The expected audiences.  Will be validated in the token.</param>
    /// <returns>The <see cref="IAppBuilder"/> instance.</returns>
    public static IAppBuilder UseJwtTokenAuthentication(
        this IAppBuilder app,
        params string[] audiences)
    {
        var validationParameters = new TokenValidationParameters
                                   {
                                       ValidateLifetime = true,
                                       ValidateAudience = true,
                                       ValidateIssuer = true,
                                       ValidateActor = true,
                                       ValidateIssuerSigningKey = true,
                                       ValidAudiences = audiences,
                                       ValidIssuer = Constants.Issuer,
                                       IssuerSigningKeyResolver = Constants.GetSigningKey,
                                   };

        var tokenHandler = new JwtSecurityTokenHandler();
        app.UseJwtBearerAuthentication(
            new JwtBearerAuthenticationOptions
            {
                AuthenticationMode = AuthenticationMode.Active,
                AllowedAudiences = audiences,
                TokenHandler = tokenHandler,
                TokenValidationParameters = validationParameters,
            });

        return app;
    }
}

public static class Constants
{
    /// <summary>
    /// The authentication issuer.
    /// </summary>
    public const string Issuer = "https://auth.myApplication.com/"; // custom domain for Auth0

    private static readonly OpenIdConnectKeyResolver KeyResolver;

    static Constants() { KeyResolver = new OpenIdConnectKeyResolver(Issuer, TimeSpan.FromHours(1), TimeSpan.FromSeconds(10)); }

    /// <summary>
    /// Gets the <see cref="IssuerSigningKeyResolver" /> delegate to provide to <see cref="JwtSecurityTokenHandler" />.
    /// </summary>
    public static IssuerSigningKeyResolver GetSigningKey => KeyResolver.GetSigningKey;
}

直接呼叫示例:

void ValidateToken(string authenticationToken)
        {
            var issuer = "https://auth.myApplication.com/"; // custom domain for Auth0
            var audiences = new[]
                            {
                                "https://secure.myApplication.com/",
                            };

            using (var signingKeyResolver = new OpenIdConnectKeyResolver(issuer, TimeSpan.Zero, TimeSpan.FromSeconds(10)))
            {
                var tokenHandler = new JwtSecurityTokenHandler();
                var validationParameters = new TokenValidationParameters
                                           {
                                               ValidateLifetime = true,
                                               ValidateAudience = true,
                                               ValidateIssuer = true,
                                               ValidateActor = true,
                                               ValidateIssuerSigningKey = true,
                                               ValidAudiences = audiences,
                                               ValidIssuer = issuer,
                                               IssuerSigningKeyResolver = signingKeyResolver.GetSigningKey,
                                           };

                var principal = tokenHandler.ValidateToken(authenticationToken, validationParameters, out var securityToken);

                if (principal == null || securityToken == null)
                {
                    throw new UnauthorizedAccessException();
                }
            }
        }

这需要一个签名密钥解析器,示例是使用第二个选项,因为这正是我所需要的:
它被烘焙到Microsoft.IdentityModel.Tokens中(参见此处的示例:https://github.com/auth0/auth0-aspnet-owin/blob/master/src/Auth0.Owin.OpenIdConnectSigningKeyResolver/OpenIdConnectSigningKeyResolver.cs)。
如果使用System.IdentityModel.Tokens.Jwt,则需要做更多的工作(请参见此处的示例:https://github.com/NaosProject/Naos.Auth/blob/main/Naos.Auth.Recipes.Jwt/OpenIdConnectKeyResolver.cs)我写了一段代码来完成这个任务,可以直接复制(MIT许可证),也可以使用包'Naos.Auth. Recipes.Jwt'作为mix-in安装。

相关问题