问题
I'm making a small new project using .net core 2.0 and jwt bearer authentication (https://github.com/aspnet/Security)
Here is my 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();
}
With these configurations, jwt has been enabled in my web application. But, there is one thing I'm currently facing with:
- With API doesn't require authentication (placed under [AllowAnonymous] attribute), if I pass Authorization header in my request, OnAuthenticationFailed event will be raised (due to no token is detected).
My question is: How can I make my jwt authentication automatically ignore methods or controller which is marked as AllowAnonymous ?
Thank you,
回答1:
Instead of using OnAuthenticationFailed, try putting it in 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.");
}
};
回答2:
I think , it's because you are adding two authentication at the same time, one with jwt and other one with this code.
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));
});
Keep just the jwt and if you want to add policies you can do it like this example
services.AddAuthorization(options =>
{
options.AddPolicy("CreateUser", policy => policy.AddRequirements(
new UserLevelRequirement("Admin")
));
})
You don't to configure twice the authorization.
回答3:
OnAuthenticationFailed event will allows be raised.But your API will return 406 Not Acceptable because this event will set the Response ContentType to "text/plain";. You can change your code c.Response.ContentType = "text/plain";
to c.Response.ContentType = "application/json";
.
回答4:
I found the solution here https://github.com/aspnet/Security/issues/1488
The call to AddAuthorization must be on the MvcCoreBuilder, not the service collection.
services
.AddMvcCore()
.AddAuthorization(...)
The drawback is that AddMvcCore() does not add all services that AddMvc() adds. Look at the source code of AddMvc() for the additional services to add.
EDIT
The above still does not work for me.
You can try [OverrideAuthentication]
instead
来源:https://stackoverflow.com/questions/47667949/asp-net-core-2-0-jwt-doesnt-ignore-allowanonymous