通过 AWS EC2 上的 Docker 容器发布时,Auth0 OWIN API 未验证 JWT 令牌

Posted

技术标签:

【中文标题】通过 AWS EC2 上的 Docker 容器发布时,Auth0 OWIN API 未验证 JWT 令牌【英文标题】:Auth0 OWIN API not validating JWT token when published via Docker Container on AWS EC2 【发布时间】:2017-06-25 04:16:33 【问题描述】:

托管在 EC2 上的我的 OWIN Web.API 2 不会授权 JWT 令牌。我已经在本地测试了该功能,没有出现问题,但是一旦我将其发布到托管在 EC2 上的 docker 容器,它就会以 401 响应。我使用的是默认的 RS256 算法和这些设置:

var domain = Environment.GetEnvironmentVariable("AUTH0_DOMAIN");
var audience = Environment.GetEnvironmentVariable("AUTH0_CLIENT_IDS");
var keyResolver = new OpenIdConnectSigningKeyResolver(domain);
appBuilder.UseJwtBearerAuthentication(
                new JwtBearerAuthenticationOptions
                
                    AuthenticationMode = AuthenticationMode.Active,
                    AllowedAudiences = new[]  audience ,
                    TokenValidationParameters = new TokenValidationParameters()
                    
                        ValidAudience = audience,
                        ValidIssuer = domain,
                        IssuerSigningKeyResolver = (token, securityToken, identifier, parameters) => keyResolver.GetSigningKey(identifier)
                    
                );

My Endpoint 仅说明您是否已通过身份验证。

[Authorize]
        [Route("secure")]
        public HttpResponseMessage GetSecured()
        
            var userId = ClaimsPrincipal.Current.Identity.GetUserId();
            return Request.CreateResponse($"Hello, userId! You are currently authenticated.");
        

这是我的启动配置:

public void Configuration(IAppBuilder appBuilder)
        
            appBuilder.UseCors(CorsOptions.AllowAll); //must be first
            Auth0Config.Register(appBuilder);
            var httpConfiguration = new HttpConfiguration();
            httpConfiguration.MapHttpAttributeRoutes();
            UnityConfig.Register(httpConfiguration);
            appBuilder.UseWebApi(httpConfiguration);
        

【问题讨论】:

我过去曾多次遇到此问题,通常归结为配置设置不正确。检查域是否正确(带有尾随的“/”)以及您的其他设置。还要确保您是否从已启用 CORS 的其他域(Angular SPA 等)调用此端点。 我已经确定我有斜杠,并在我的问题中添加了我的启动配置。 【参考方案1】:

我不再使用 OWIN 管道,但在以前的项目中,这是我配置它的方式。看起来你正在使用 OpenID,我没有。不确定这是否有帮助。

var issuer = AppSettings.Auth0Domain;
            var audience = AppSettings.Auth0ClientID;
            var secret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["Auth0ClientSecret"]);

            app.UseJwtBearerAuthentication(
                new JwtBearerAuthenticationOptions
                
                    AuthenticationMode = AuthenticationMode.Active,
                    AllowedAudiences = new[] audience,
                    IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
                    
                        new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)
                    ,
                    Provider = new Auth0AuthenticationProvider()
                );

编辑添加了 Auth0AuthenticationProvider

public class Auth0AuthenticationProvider : IOAuthBearerAuthenticationProvider

    private string token;

    public Task ApplyChallenge(OAuthChallengeContext context)
    
        return Task.FromResult<object>(null);
    

    public Task RequestToken(OAuthRequestTokenContext context)
    
        token = context.Token;
        return Task.FromResult<object>(null);
    

    public Task ValidateIdentity(OAuthValidateIdentityContext context)
    
        if (string.IsNullOrEmpty(token))
            return Task.FromResult<object>(null);

        var notPadded = token.Split('.')[1];
        var padded = notPadded.PadRight(notPadded.Length + (4 - notPadded.Length % 4) % 4, '=');
        var urlUnescaped = padded.Replace('-', '+').Replace('_', '/');
        var claimsPart = Convert.FromBase64String(urlUnescaped);

        var obj = JObject.Parse(Encoding.UTF8.GetString(claimsPart, 0, claimsPart.Length));

        // simple, not handling specific types, arrays, etc.
        foreach (var prop in obj.Properties().AsJEnumerable())
        
            switch (prop.Name)
            
                case "app_metadata":
                    SetAppMetadataClaims(context, prop.Value.ToString());
                    break;
            
        

        return Task.FromResult<object>(null);
    

    private static void SetAppMetadataClaims(OAuthValidateIdentityContext context, string jsonString)
    
        var appMetadata = JsonConvert.DeserializeObject<Auth0AppMetaDataModel>(jsonString);

        if(!context.Ticket.Identity.HasClaim("AccountId", appMetadata.accountId.ToString()))
            context.Ticket.Identity.AddClaim(new Claim("AccountId", appMetadata.accountId.ToString()));
        if (!context.Ticket.Identity.HasClaim("ClientId", appMetadata.clientId.ToString()))
            context.Ticket.Identity.AddClaim(new Claim("ClientId", appMetadata.clientId.ToString()));
        if (!context.Ticket.Identity.HasClaim("IsActive", appMetadata.isActive.ToString()))
            context.Ticket.Identity.AddClaim(new Claim("IsActive", appMetadata.isActive.ToString()));

        if (appMetadata.roles == null)
            return;

        foreach (var role in appMetadata.roles)
        
            if (context.Ticket.Identity.HasClaim(ClaimTypes.Role, role))
                continue;

            context.Ticket.Identity.AddClaim(new Claim(ClaimTypes.Role, role));
        
    

【讨论】:

您的 Auth0AuthenticationProvider 是什么样的?我正在用 HS256 试试这个。 好吧,我已经尝试使用 UseJwtBearerAuthentication 切换到 RS256,我可以毫无问题地进行调试,但我在 docker compose-up 上收到错误,如下所示: System.Reflection.TargetInvocationException: Exception has been throwed by调用的目标。 ---> System.TypeLoadException: 无法使用令牌 01000042 解析类型我正在使用 mono:onbuild 作为我的图像库。【参考方案2】:

问题不在于使用 HS256 或 RS256 的 Auth0,而在于我使用的基本映像。 Mono 默默地失败了,很可能阻止了我的令牌的验证。我已切换到 dotnet 核心以使用 docker 映像:microsoft/dotnet:latest

我的启动文件现在如下所示:

        public void ConfigureServices(IServiceCollection services)
        
            services.AddCors(options =>
            
                options.AddPolicy("CorsPolicy",
                    builder => builder.AllowAnyOrigin()
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowCredentials());
            );

            ...
        

        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        
            app.UseCors("CorsPolicy");
            var options = new JwtBearerOptions
            
                Audience = Configuration["Auth0:ApiIdentifier"],
                Authority = $"https://Configuration["Auth0:Domain"]/"
            ;
            app.UseJwtBearerAuthentication(options);

            ...
        

【讨论】:

以上是关于通过 AWS EC2 上的 Docker 容器发布时,Auth0 OWIN API 未验证 JWT 令牌的主要内容,如果未能解决你的问题,请参考以下文章

AWS Elastic Beanstalk 与 EC2 容器服务 (ECS) - Docker

AWS EC2 容器服务/Elastic Beanstalk Docker 容器端口 udp 绑定

Aws ec2 实例中 docker 容器内的“Composer update”命令内存不足错误

具有 Auto Scaling 与弹性容器服务 (ECS) 的 AWS EC2 - Docker

将夹具上传到在 AWS EC2 实例的 docker 容器中运行的 django

AWS beanstalk 中 docker 容器中的 JVM 内存设置