Asp.Net Core混合使用cookie和JwtBearer认证方案
参照:https://www.cnblogs.com/sunnytrudeau/p/9693512.html
MVC部分的登录不赘述,主要是JwtBearer混合部分的问题。
- 创建JwtSettings类:
/// <summary> /// JWT授权的配置项 /// </summary> public class JwtSettings { public JwtSettings() { //CreateKey(); } /// <summary> /// 谁颁发的 /// </summary> public string Issuer { get; set; } /// <summary> /// 颁发给谁 /// </summary> public string Audience { get; set; } /// <summary> /// 令牌密码 /// </summary> public string SecurityKey { get; set; } public int ExpiresMinute { get; set; } = 1440; //默认一天 ///对称秘钥 public SymmetricSecurityKey Key { get { return new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecurityKey)); } } ///数字签名 public SigningCredentials Credentials { get { return new SigningCredentials(Key, SecurityAlgorithms.HmacSha256); } } ///修改密码,重新创建数字签名 public void SetSecurityKey(string value) { SecurityKey = value; //CreateKey(); } //private void CreateKey() //{ // Key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecurityKey)); // Credentials = new SigningCredentials(Key, SecurityAlgorithms.HmacSha256); //} } }
- appsettings.json中加入配置信息
"JwtSettings": {
"Issuer": "server",
"Audience": "client",
"ExpiresMinute": 10080, //超时分钟数,7天
"SecurityKey": "69f48e18-3409-40ce-b7a7-8c0362245cf8" //不少于16位长度
},
- 修改Startup.cs中认证内容
#region Authentication var jwtSettings = Configuration.GetSection("JwtSettings").Get<JwtSettings>(); services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, opts => { opts.AccessDeniedPath = "/Account/Login"; opts.Cookie.HttpOnly = true; opts.LoginPath = "/Account/Login"; opts.Cookie.Name = MyConsts.AuthCookieName; }) .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, opts => { opts.RequireHttpsMetadata = false; //无需https //x.SaveToken = true; opts.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = jwtSettings.Key, ValidateIssuer = true, ValidIssuer = jwtSettings.Issuer, ValidateAudience = true, ValidAudience = jwtSettings.Audience, ValidateLifetime = true, ClockSkew = TimeSpan.FromMinutes(5) }; }); #endregion
- APIController中增加一个Login方法的Controller,用于登录并返回token
[Route("api/[controller]")] [ApiController] public class AccountController : ControllerBase { .... /// <summary> /// 登录方法,默认7天超时 /// </summary> /// <param name="UserName">用户名</param> /// <param name="Password">密码</param> /// <returns></returns> [HttpGet,HttpPost] [Route("Login")] public async Task<IActionResult> LoginAsync(string UserName, string Password) { ..... var claims = new Claim[] { new Claim(ClaimTypes.Sid, UserName), new Claim(ClaimTypes.Name, UserName), new Claim(ClaimTypes.Role, "user"), new Claim("guid",user.Id.ToString()), new Claim("avatar",""), //new Claim("displayName",user.NameDisplay), //new Claim("loginName",user.Account), //new Claim("emailAddress",""), //new Claim("userType",IsAdmin ? "1": "0") }; var token = JwtBearerAuthenticationExtension.GetJwtAccessToken(claims); rp.SetData(token); return Ok(rp); } }
- 加入api的路由
#region 路由 app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}") .RequireAuthorization(); endpoints.MapControllerRoute( name: "apiDefault", pattern: "api/{controller=Home}/{action=Index}/{id?}"); }); #endregion
- 为ValuesController加入登录验证,并使用HttpContext获取当前登录用户
[Route("api/[controller]")] [ApiController] [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] public class ValuesController : ControllerBase { /// <summary> /// 获取所有values,GET api/values /// </summary> /// <returns></returns> [HttpGet] public ActionResult<IEnumerable<string>> Get() { var current = MyHttpContext.Current; return new string[] { current.User.Identity.Name, current.User.Claims.Count().ToString() }; } }
验证,以下是Swagger的截图,Postman等也一样:
- 未登录时:
- 登录获取Token
- 将该Token前面加Bearer作为传入Header中的Authorization中,
- 再次执行Values
调用成功。
总结:MVC的Controller使用
.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie
块的逻辑,ApiController使用AddJwtBearer部分逻辑,具体可以在Controller的Attribute
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
上切换。