ASP.NET Core Authorize 属性不适用于 JWT
Posted
技术标签:
【中文标题】ASP.NET Core Authorize 属性不适用于 JWT【英文标题】:ASP.NET Core Authorize attribute not working with JWT 【发布时间】:2017-03-31 11:43:19 【问题描述】:我想在 ASP.Net Core 中实现基于 JWT 的安全性。目前,我想做的就是读取Authorization
标头中的不记名令牌,并根据我的标准对其进行验证。我不需要(也不想)包含 ASP.Net Identity。事实上,除非我真的需要它们,否则我会尽可能多地避免使用 MVC 添加的东西。
我创建了一个最小的项目来演示这个问题。要查看原始代码,只需查看编辑历史记录。我期待这个示例拒绝所有对/api/icons
的请求,除非它们为Authorization
HTTP 标头提供相应的不记名令牌。该示例实际上允许所有请求。
Startup.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Configuration;
using Microsoft.AspNetCore.Routing;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using System;
using Newtonsoft.Json.Serialization;
namespace JWTSecurity
public class Startup
public IConfigurationRoot Configuration get; set;
public Startup(IHostingEnvironment env)
IConfigurationBuilder builder = new ConfigurationBuilder().SetBasePath(env.ContentRootPath);
Configuration = builder.Build();
public void ConfigureServices(IServiceCollection services)
services.AddOptions();
services.AddAuthentication();
services.AddMvcCore().AddJsonFormatters(options => options.ContractResolver = new CamelCasePropertyNamesContractResolver());
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
loggerFactory.AddConsole();
app.UseJwtBearerAuthentication(new JwtBearerOptions
AutomaticAuthenticate = true,
AutomaticChallenge = true,
TokenValidationParameters = new TokenValidationParameters
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("supersecretkey")),
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
);
app.UseMvc(routes => routes.MapRoute("default", "controller=Home/action=Index/id?"));
控制器/图标控制器.cs
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace JWTSecurity.Controllers
[Route("api/[controller]")]
public class IconsController : Controller
[Authorize]
public IActionResult Get()
return Ok("Some content");
【问题讨论】:
你能显示你应用了授权属性的方法和类吗? 您的 JWT 令牌中间件在哪里?您的服务正在通过 /token 端点或类似的东西正确生成 JWT? 此时,我不关心生成令牌,我只关心拒绝任何在标头中不提供令牌的内容。 你现在拥有的和我拥有的非常相似,除了我有 ValidateIssuer = true 和 ValidateAudience = true,但我认为这些不是必需的。我没有 services.AddAuthentication();要么。 是的,我只是尝试添加它们,没有区别。一定有我想念的东西... 【参考方案1】:我刚刚遇到了类似的问题,结果发现控制器级别的 [AllowAnonymous]
属性会覆盖应用于该控制器内任何操作的任何 [Authorize]
属性。这是我以前不知道的。
【讨论】:
【参考方案2】:如果您使用自定义方案,则必须使用
[Authorize(AuthenticationSchemes="your custom scheme")]
【讨论】:
【参考方案3】:找到了这个问题的完美解决方案 您的配置服务类应如下所示
public void ConfigureServices(IServiceCollection services)
services.Configure<CookiePolicyOptions>(options =>
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
);
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>
(options => options.Stores.MaxLengthForKeys = 128)
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultUI()
.AddDefaultTokenProviders();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddAuthentication(options =>
//options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
//options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
//options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
//options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
)
.AddCookie(cfg => cfg.SlidingExpiration = true)
.AddJwtBearer(cfg =>
cfg.RequireHttpsMetadata = false;
cfg.SaveToken = true;
cfg.TokenValidationParameters = new TokenValidationParameters
ValidIssuer = Configuration["JwtIssuer"],
ValidAudience = Configuration["JwtIssuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JwtKey"])),
ClockSkew = TimeSpan.Zero // remove delay of token when expire
;
);
services.Configure<IdentityOptions>(options =>
// Password settings
options.Password.RequireDigit = true;
options.Password.RequiredLength = 8;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = true;
options.Password.RequireLowercase = false;
options.Password.RequiredUniqueChars = 6;
// Lockout settings
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
options.Lockout.MaxFailedAccessAttempts = 10;
options.Lockout.AllowedForNewUsers = true;
// User settings
options.User.RequireUniqueEmail = true;
);
services.AddAuthentication().AddFacebook(facebookOptions =>
facebookOptions.AppId = Configuration["Authentication:Facebook:AppId"];
facebookOptions.AppSecret = Configuration["Authentication:Facebook:AppSecret"];
);
//Seting the Account Login page
services.ConfigureApplicationCookie(options =>
// Cookie settings
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
options.LoginPath = "/Account/Login"; // If the LoginPath is not set here, ASP.NET Core will default to /Account/Login
options.LogoutPath = "/Account/Logout"; // If the LogoutPath is not set here, ASP.NET Core will default to /Account/Logout
options.AccessDeniedPath = "/Account/AccessDenied"; // If the AccessDeniedPath is not set here, ASP.NET Core will default to /Account/AccessDenied
options.SlidingExpiration = true;
);
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
您可以像下面这样对 Web API 控制器进行身份验证
[Route("api/[controller]")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[ApiController]
public class TaskerController : ControllerBase
[HttpGet("[action]")]
//[AllowAnonymous]
public IEnumerable<string> Get()
return new string[] "value1", "value2" ;
并且您可以像往常一样使用基于身份的授权属性,如下所示用于 MVC 控制器
public class TaskController : Controller
[Authorize]
public IActionResult Create()
关键解决方案是.AddCookie(cfg => cfg.SlidingExpiration = true)
在 JWT 身份验证之前添加,即 .AddJwtBearer(//removed for brevity)
将基于 Cookie 的授权设置为默认值,因此 [Authorize] 照常工作,每当您需要 JWT 时,您必须使用 [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
显式调用它
希望它能帮助那些希望将网站作为前端并将移动就绪的 Web API 作为后端的人。
【讨论】:
问题中的关键点之一是I don't need (and don't want) to include ASP.Net Identity
。使用标准配置设置 Asp.Net 很容易,但目标是创建一个使用 MvcCore 和 JwtAuthentication 的最小项目
答案涵盖了两种类型的身份验证机制,您可以根据需要跳过其中任何一种。您只需注释掉您不需要的部分@AndrewWilliamson
这不仅仅是注释掉不需要的部分的问题。您的ConfigureServices
方法调用.AddMvc()
而不是.AddMvcCore()
。我的整个问题是基于当我使用.AddMvcCore()
时身份验证不起作用,我必须通读.AddMvc()
的源代码才能弄清楚有什么区别。当您提供答案时,它应包含最少 量的更改以回答问题。否则用户仍然需要弄清楚你的代码的哪一部分解决了问题
感谢您愿意与他人分享您的经验 - 不要停下来,只记得专注于用最小的例子回答问题
感谢[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
属性。就我而言,对于 WebApi,我想使用 JWTAuth,对于 ViewController,我想使用 CookieAuth。然后我创建了双重 AddAuthentication()。但不幸的是,由于我使用的是[Authorize]
而不添加参数。未经授权的页面总是点击 JWTAuth 设置。但是在[Authorize]
上添加参数后,这解决了我的问题【参考方案4】:
对于那些甚至尝试了预览答案但没有解决问题的人,下面是我的问题是如何解决的。
[Authorize(AuthenticationSchemes="Bearer")]
【讨论】:
我想你可以查看这个答案***.com/a/63446357/4307338 没问题,伙计。编码愉快。【参考方案5】:找到了!
主要问题出在这一行:
services.AddMvcCore().AddJsonFormatters(options => options.ContractResolver = new CamelCasePropertyNamesContractResolver());
我注意到,通过从 AddMvcCore() 切换到 AddMvc(),授权突然开始工作!在挖掘了the ASP.NET source code 之后,看看AddMvc()
做了什么,我意识到我需要第二个电话给IMvcBuilder.AddAuthorization()
。
services.AddMvcCore()
.AddAuthorization() // Note - this is on the IMvcBuilder, not the service collection
.AddJsonFormatters(options => options.ContractResolver = new CamelCasePropertyNamesContractResolver());
【讨论】:
这也引起了我的注意(因为我使用的是AddMvcCore
)。对 AddAuthorization()
的调用添加了 AuthorizationApplicationModelProvider
,它在控制器上查找 Authorize/AllowAnonymous 并添加适当的策略。
不要忘记AddDataAnnotations
,如果您将它们用于请求验证!
Authorize 属性在使用services.AddMvcCore().AddAuthorization()
后开始工作
我想你可以查看这个答案***.com/a/63446357/4307338
@HoqueMDZahidul 目的是使用MvcCore
生成一个最小示例。您链接到的答案显示了一个有效的 asp 网络配置,但它没有显示 使令牌身份验证工作的最低配置。如果我只想让身份验证工作,我可以继续使用.AddMvc()
而不是.AddMvcCore()
。您的回答没有解决原来的问题【参考方案6】:
您也在使用身份验证,它隐式包含 cookie 验证。可能您使用身份方案登录并导致身份验证成功。
如果不需要身份认证,则删除身份认证(如果您只想要jwt认证),否则为Authorize
属性指定Bearer
方案,如下所示:
[Authorize(ActiveAuthenticationSchemes = "Bearer")]
【讨论】:
我明天回去工作的时候试试这个,希望你是对的。关于这一点,我使用身份的原因纯粹是为了隐藏/抽象密码散列。你会建议什么替代方案? Identity 是推荐的解决方案。如果你需要,那就去吧。据我了解,您想使用身份和 jwt 可选。在这种情况下,您应该指定要限制的身份验证方案。例如,如果您只需要 jwt 身份验证,则应该使用承载方案。 您不需要 ActiveAuthenticationSchemes 来使用 JWT。只要您正确发送令牌,就可以在没有它的情况下工作。 @SledgeHammer 当然,通常你不需要它。但我假设是由身份认证引起的问题,并且还假设 OP 只想进行 jwt 认证。 你是我的英雄以上是关于ASP.NET Core Authorize 属性不适用于 JWT的主要内容,如果未能解决你的问题,请参考以下文章
在 ASP.NET Core Identity 中使用 Authorize 属性检查多个策略之一
如何创建不依赖于 ASP.NET Core 声明的自定义 Authorize 属性?
JS Fetch API 不适用于具有 Authorize 属性的 ASP.NET Core 2 控制器
ASP.NET Core 2:使用 [Authorize] 对 API 的 Ajax 调用使预检请求失败
拦截asp.net core Authorize action,授权成功后执行自定义动作
在信号器集线器类上设置 [Authorize] 属性仅在连接到集线器时有效,而不是在集线器上的每个方法之前(ASP.NET Core 2.2)