Asp.net core 2.0 Jwt 不会忽略 AllowAnonymous
Posted
技术标签:
【中文标题】Asp.net core 2.0 Jwt 不会忽略 AllowAnonymous【英文标题】:Asp.net core 2.0 Jwt doesn't ignore 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 的方法或控制器?
谢谢,
【问题讨论】:
【参考方案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.");
;
【讨论】:
此事件在这种特殊情况下不会触发。 我的情况与这篇文章的原始问题完全相同。我花了几天时间才找到这个解决方案,它非常适合我的两个项目。在什么特殊情况下它不起作用?请说明或给出您的解决方案,而不是投反对票。我只是想帮忙。这是我在 *** 上的第一个答案,现在你让我气馁了。 ManWaiLorentzYip,您不应该因互联网投票而气馁。如果你让它来找你,你会气馁很多。继续提供帮助并提供信息,我们都会从中学习。我在这个线程中有同样的问题,你的建议似乎有效,但我不知道为什么。我不知道为什么将代码放在 OnChallenge 与 OnAuthenticationFailed 中会产生如此不同,因为我所做的只是捕获身份验证失败并将其映射到我自己的响应中。文档没有帮助,您知道这些事件实际上是做什么的吗?谢谢 @BayoO'liliJason',非常感谢您的鼓励。实际上,让我失望的是有人没有尝试就对我的解决方案投了反对票。无论如何,我还发现 asp.net 核心文档不是很有帮助。然后在this的The 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]
【讨论】:
以上是关于Asp.net core 2.0 Jwt 不会忽略 AllowAnonymous的主要内容,如果未能解决你的问题,请参考以下文章
Asp.net Core 2.0 基本 JWT 缺少 ApplicationCookie
asp.net core 2.0 授权在身份验证(JWT)之前触发
asp.net core 2.0 web api基于JWT自定义策略授权