Asp.net核心2.0 Jwt不会忽略AllowAnonymous

时间:2017-12-06 06:16:58

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

我正在使用.net core 2.0和jwt bearer身份验证(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();
        }

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

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

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

谢谢,

4 个答案:

答案 0 :(得分:0)

我认为,这是因为你要同时添加两个身份验证,一个使用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")
                ));
                })

您不需要配置两次授权。

答案 1 :(得分:0)

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

答案 2 :(得分:0)

而不是使用 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.");
    }
};

答案 3 :(得分:0)

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

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

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

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

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

您可以改用[OverrideAuthentication]