【问题标题】:Asp.net core 2.0 Jwt doesn't ignore AllowAnonymousAsp.net core 2.0 Jwt 不会忽略 AllowAnonymous
【发布时间】:2018-05-19 23:02:28
【问题描述】:

我正在使用 .net core 2.0 和 jwt 不记名身份验证 (https://github.com/aspnet/Security) 制作一个小型新项目

这是我的 Startup.cs

        /// <summary>
        ///     This method gets called by the runtime. Use this method to add services to the container.
        /// </summary>
        /// <param name="services"></param>
        public void ConfigureServices(IServiceCollection services)
        {
            // Add entity framework to services collection.
            var sqlConnection = Configuration.GetConnectionString("SqlServerConnectionString");
            services.AddDbContext<RelationalDatabaseContext>(
                options => options.UseSqlServer(sqlConnection, b => b.MigrationsAssembly(nameof(Main))));

            // Injections configuration.
            services.AddScoped<IUnitOfWork, UnitOfWork>();
            services.AddScoped<DbContext, RelationalDatabaseContext>();
            services.AddScoped<IEncryptionService, EncryptionService>();
            services.AddScoped<IIdentityService, IdentityService>();
            services.AddScoped<ITimeService, TimeService>();
            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

            // Requirement handler.
            services.AddScoped<IAuthorizationHandler, SolidAccountRequirementHandler>();
            services.AddScoped<IAuthorizationHandler, RoleRequirementHandler>();

            // Load jwt configuration from setting files.
            services.Configure<JwtConfiguration>(Configuration.GetSection(nameof(JwtConfiguration)));
            services.Configure<ApplicationSetting>(Configuration.GetSection(nameof(ApplicationSetting)));

            // Build a service provider.
            var serviceProvider = services.BuildServiceProvider();
            var jwtBearerSettings = serviceProvider.GetService<IOptions<JwtConfiguration>>().Value;

            // Cors configuration.
            var corsBuilder = new CorsPolicyBuilder();
            corsBuilder.AllowAnyHeader();
            corsBuilder.AllowAnyMethod();
            corsBuilder.AllowAnyOrigin();
            corsBuilder.AllowCredentials();

            // Add cors configuration to service configuration.
            services.AddCors(options => { options.AddPolicy("AllowAll", corsBuilder.Build()); });
            services.AddOptions();

            // This can be removed after https://github.com/aspnet/IISIntegration/issues/371
            var authenticationBuilder = services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            });

            authenticationBuilder.AddJwtBearer(o =>
            {
                // You also need to update /wwwroot/app/scripts/app.js
                o.Authority = jwtBearerSettings.Authority;
                o.Audience = jwtBearerSettings.Audience;
                o.RequireHttpsMetadata = false;

                o.SecurityTokenValidators.Clear();
                o.SecurityTokenValidators.Add(new JwtBearerValidator());

                o.Events = new JwtBearerEvents()
                {
                    OnAuthenticationFailed = c =>
                    {
                        c.NoResult();

                        c.Response.StatusCode = 500;
                        c.Response.ContentType = "text/plain";
                        if ("dev".Equals(Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")))
                        {
                            // Debug only, in production do not share exceptions with the remote host.
                            return c.Response.WriteAsync(c.Exception.ToString());
                        }
                        return c.Response.WriteAsync("An error occurred processing your authentication.");
                    }
                };
            });

            #region Mvc builder

            // Construct mvc options.
            var mvcBuilder =
                services.AddMvc(mvcOptions =>
                {
                    //only allow authenticated users
                    var policy = new AuthorizationPolicyBuilder()
                        .RequireAuthenticatedUser()
                        .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
                        .AddRequirements(new SolidAccountRequirement())
                        .Build();

                    mvcOptions.Filters.Add(new AuthorizeFilter(policy));
                });

            // Add json configuration/
            mvcBuilder.AddJsonOptions(options =>
            {
                options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            });

            #endregion
        }

        /// <summary>
        ///     This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        /// </summary>
        /// <param name="app"></param>
        /// <param name="env"></param>
        /// <param name="loggerFactory"></param>
        /// <param name="serviceProvider"></param>
        public void Configure(IApplicationBuilder app,
            IHostingEnvironment env,
            ILoggerFactory loggerFactory, IServiceProvider serviceProvider)
        {
            // Enable logging.
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            loggerFactory.AddDebug();

            // Use JWT Bearer authentication in the system.
            app.UseAuthentication();

            // Enable cors.
            app.UseCors("AllowAll");

            // Enable MVC features.
            app.UseMvc();
        }

通过这些配置,jwt 已在我的 Web 应用程序中启用。但是,我目前面临一件事:

  • 使用 API 不需要身份验证(放置在 [AllowAnonymous] 属性下),如果我在请求中传递 Authorization 标头,OnAuthenticationFailed将引发事件(由于未检测到令牌)。

我的问题是:如何让我的 jwt 身份验证自动忽略标记为 AllowAnonymous 的方法或控制器

谢谢,

【问题讨论】:

    标签: asp.net-core asp.net-core-mvc jwt asp.net-core-2.0 asp.net-core-webapi


    【解决方案1】:

    不要使用 OnAuthenticationFailed,而是尝试将其放入 OnChallenge

    o.Events = new JwtBearerEvents()
    {
        OnChallenge = c =>
        {
            c.HandleResponse();
            c.Response.StatusCode = 500;
            c.Response.ContentType = "text/plain";
            return c.Response.WriteAsync("An error occurred processing your authentication.");
        }
    };
    

    【讨论】:

    • 此事件在这种特殊情况下不会触发。
    • 我的情况与这篇文章的原始问题完全相同。我花了几天时间才找到这个解决方案,它非常适合我的两个项目。在什么特殊情况下它不起作用?请说明或给出您的解决方案,而不是投反对票。我只是想帮忙。这是我在 stackoverflow 上的第一个答案,现在你让我气馁了。
    • ManWaiLorentzYip,您不应该因互联网投票而气馁。如果你让它来找你,你会气馁很多。继续提供帮助并提供信息,我们都会从中学习。我在这个线程中有同样的问题,你的建议似乎有效,但我不知道为什么。我不知道为什么将代码放在 OnChallenge 与 OnAuthenticationFailed 中会产生如此不同,因为我所做的只是捕获身份验证失败并将其映射到我自己的响应中。文档没有帮助,您知道这些事件实际上是做什么的吗?谢谢
    • @BayoO'liliJason',非常感谢您的鼓励。实际上,让我失望的是有人没有尝试就对我的解决方案投了反对票。无论如何,我还发现 asp.net 核心文档不是很有帮助。然后在thisThe JwtBearerHandler HandleUnauthorisedAsync方法部分找到了一些线索,
    • source code 的第 215 行。所以 HandleChallengeAsync 似乎是身份验证失败时设置状态码 401 的地方。这就是我尝试 OnChallenge 并且成功的原因。老实说,我不知道这是否是正确的方法,但至少它解决了我的问题。希望这可以帮助。 ?
    【解决方案2】:

    我认为,这是因为您同时添加了两个身份验证,一个使用 jwt,另一个使用此代码。

     var mvcBuilder =
                    services.AddMvc(mvcOptions =>
                    {
                        //only allow authenticated users
                        var policy = new AuthorizationPolicyBuilder()
                            .RequireAuthenticatedUser()
                            .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
                            .AddRequirements(new SolidAccountRequirement())
                            .Build();
    
                        mvcOptions.Filters.Add(new AuthorizeFilter(policy));
                    });
    

    只保留 jwt,如果你想添加策略,你可以像这个例子那样做

    services.AddAuthorization(options =>
                    {
                        options.AddPolicy("CreateUser", policy => policy.AddRequirements(
                        new UserLevelRequirement("Admin")
                    ));
                    })
    

    您不要配置两次授权。

    【讨论】:

    • OnAuthenticationFailed 异常仍然被触发 :(
    【解决方案3】:

    OnAuthenticationFailed 事件将允许引发。但您的 API 将返回 406 Not Acceptable,因为此事件会将 Response ContentType 设置为“text/plain”;。您可以将代码c.Response.ContentType = "text/plain"; 更改为c.Response.ContentType = "application/json";

    【讨论】:

      【解决方案4】:

      我在这里找到了解决方案https://github.com/aspnet/Security/issues/1488

      对 AddAuthorization 的调用必须在 MvcCoreBuilder 上,而不是在服务集合上。

      services
          .AddMvcCore()
          .AddAuthorization(...)
      

      缺点是 AddMvcCore() 不会添加 AddMvc() 添加的所有服务。查看 AddMvc() 的源代码以了解要添加的附加服务。

      编辑
      以上对我仍然不起作用。

      你可以试试[OverrideAuthentication]

      【讨论】:

        猜你喜欢
        • 2020-04-06
        • 2020-03-16
        • 2018-04-12
        • 2014-10-16
        • 2018-03-30
        • 1970-01-01
        • 2018-01-24
        • 2019-09-04
        • 2013-11-09
        相关资源
        最近更新 更多