1、建.NetCore的WebApi项目,安装包IdentityModel,Microsoft.AspNetCore.Authentication.JwtBearer,Microsoft.AspNetCore.Authorization
2、注册服务和中间件
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.Extensions.DependencyInjection; using Microsoft.IdentityModel.Tokens; using System; using System.Text; using System.Threading.Tasks; namespace WebApiJwt.Utils { public static class AuthorizationSetup { public static void AddAuthorizationSetup(this IServiceCollection services) { if (services == null) throw new ArgumentNullException(nameof(services)); // 策略 services.AddAuthorization(options => { options.AddPolicy("Admin", policy => policy.RequireRole("Admin", "System")); }); //读取配置文件 var symmetricKeyAsBase64 = ConfigHelper.GetSectionValue("JwtSetting:SecretKey"); var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64); var signingKey = new SymmetricSecurityKey(keyByteArray); var Issuer = ConfigHelper.GetSectionValue("JwtSetting:Issuer"); var Audience = ConfigHelper.GetSectionValue("JwtSetting:Audience"); // 令牌验证参数 var tokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true,//是否验证签名,不验证的画可以篡改数据,不安全 IssuerSigningKey = signingKey,//解密的密钥 ValidateIssuer = true,//是否验证发行人,就是验证载荷中的Iss是否对应ValidIssuer参数 ValidIssuer = Issuer,//发行人 ValidateAudience = true,//是否验证订阅人,就是验证载荷中的Aud是否对应ValidAudience参数 ValidAudience = Audience,//订阅人 ValidateLifetime = true,//是否验证过期时间,过期了就拒绝访问 ClockSkew = TimeSpan.Zero,//缓冲过期时间,真正过期时间=配置过期时间+缓冲过期时间,默认5分钟 RequireExpirationTime = true,//token需要设置过期时间 }; // 开启Bearer认证,添加JwtBearer服务 services.AddAuthentication(o => { o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(o => { o.TokenValidationParameters = tokenValidationParameters; o.Events = new JwtBearerEvents { OnAuthenticationFailed = context => { // 如果过期,则把<是否过期>添加到,返回头信息中 if (context.Exception.GetType() == typeof(SecurityTokenExpiredException)) { context.Response.Headers.Add("Token-Expired", "true"); } return Task.CompletedTask; } }; }); } } }
Startup.cs
注册服务:services.AddAuthorizationSetup();
添加中间件:app.UseAuthentication(); app.UseAuthorization();
3、生成Token
using Microsoft.IdentityModel.Tokens; using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; using System.Linq; using System.Security.Claims; using System.Text; using WebApiJwt.Models; namespace WebApiJwt.Utils { public class JwtHelper { /// <summary> /// 颁发JWT字符串 /// </summary> /// <param name="tokenModel"></param> /// <returns></returns> public static object IssueJwt(TokenModel tokenModel) { DateTime authTime = DateTime.UtcNow; string iss = ConfigHelper.GetSectionValue("JwtSetting:Issuer");//颁发者 string aud = ConfigHelper.GetSectionValue("JwtSetting:Audience");//可以给哪些客户端使用 string secret = ConfigHelper.GetSectionValue("JwtSetting:SecretKey");//加密的Key //token有效期 分钟 DateTime expiresAt = authTime.AddMinutes(Convert.ToDouble(ConfigHelper.GetSectionValue("JwtSetting:ExpireMinutes"))); //设置Claim var claims = new List<Claim> { //claim默认配置 new Claim(JwtRegisteredClaimNames.Jti, tokenModel.UserId.ToString()), new Claim(JwtRegisteredClaimNames.Iat, $"{new DateTimeOffset(authTime).ToUnixTimeSeconds()}"), new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(authTime).ToUnixTimeSeconds()}") , //过期时间,JWT有缓冲过期时间,所以过期时间到了会延迟一会儿再过期,影响不大。 new Claim(JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(expiresAt).ToUnixTimeSeconds()}"), new Claim(ClaimTypes.Expiration, expiresAt.ToString()), new Claim(JwtRegisteredClaimNames.Iss,iss),//颁发者 new Claim(JwtRegisteredClaimNames.Aud,aud),//可以给哪些客户端使用 new Claim(ClaimTypes.Name, tokenModel.UserName), new Claim(ClaimTypes.Email, tokenModel.Email) }; //设置Claim角色 claims.AddRange(tokenModel.Role.Split(',').Select(s => new Claim(ClaimTypes.Role, s))); //秘钥 (SymmetricSecurityKey 对安全性的要求,密钥的长度太短会报出异常) var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret)); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var jwtSecurityToken = new JwtSecurityToken(issuer: iss, claims: claims, signingCredentials: creds); var jwtHandler = new JwtSecurityTokenHandler(); var encodedJwt = jwtHandler.WriteToken(jwtSecurityToken); //存储 Token 信息 var jwt = new { UserId = tokenModel.UserId, Token = encodedJwt, Auths = new DateTimeOffset(authTime).ToUnixTimeSeconds(), Expires = new DateTimeOffset(expiresAt).ToUnixTimeSeconds(), Success = true }; return jwt; } /// <summary> /// 解析 /// </summary> /// <param name="jwtStr"></param> /// <returns></returns> public static TokenModel SerializeJwt(string jwtStr) { var jwtHandler = new JwtSecurityTokenHandler(); if (!jwtHandler.CanReadToken(jwtStr)) { return null; } string iss = ConfigHelper.GetSectionValue("JwtSetting:Issuer"); JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(jwtStr); if (jwtToken.Issuer != iss) { return null;//不正确 } if (jwtToken.ValidTo < DateTime.UtcNow) { return null;//过期 } object role, userName, email; try { jwtToken.Payload.TryGetValue(ClaimTypes.Role, out role); jwtToken.Payload.TryGetValue(ClaimTypes.Name, out userName); jwtToken.Payload.TryGetValue(ClaimTypes.Email, out email); } catch (Exception e) { Console.WriteLine(e); throw; } var tm = new TokenModel { UserId = jwtToken.Id.ToString(), Role = role != null ? role.ToString() : "", UserName = userName != null ? userName.ToString() : "", Email = email != null ? email.ToString() : "" }; return tm; } } }
配置
"JwtSetting": { "Issuer": "jwtIssuer", //颁发者 "Audience": "jwtAudience", //可以给哪些客户端使用 "SecretKey": "abcdabcdabcdabcdabcdabcdabcdabcd", //加密的Key,长度最少要32位,不然报错。 "ExpireMinutes": "3" //token有效期3分钟 }
辅助
using Microsoft.Extensions.Configuration; using System; namespace WebApiJwt.Utils { public class ConfigHelper { public readonly static IConfiguration configuration; static ConfigHelper() { configuration = new ConfigurationBuilder() .SetBasePath(Environment.CurrentDirectory) .AddJsonFile("appsettings.json", true, true) .AddInMemoryCollection() .Build(); } public static string GetSectionValue(string key) { return configuration[key]; } public static string connectionString { get { return configuration["ConnectionStrings:Default"]; } } } }
4、ApiController
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using WebApiJwt.Models; using WebApiJwt.Utils; namespace WebApiJwt.Controllers { [Route("api/[controller]/[action]")] [ApiController] public class AuthorizeController : ControllerBase { /// <summary> /// 生成令牌 /// </summary> /// <returns></returns> [HttpGet] public string GenToken() { TokenModel tokenModel = new TokenModel { UserId = "1001", Role = "Admin", Email = "908085411@qq.com", UserName = "邢帅杰" }; string jwtToken = JsonConvert.SerializeObject(JwtHelper.IssueJwt(tokenModel)); return jwtToken; } /// <summary> /// 需要Admin权限 /// </summary> /// <returns></returns> [HttpGet] [Authorize(Roles = "Admin")] //[Authorize(Policy = "Admin")]//使用策略来映射多个角色 public IActionResult Admin() { return Ok("admin........"); } /// <summary> /// 解析Token /// </summary> /// <returns></returns> [HttpGet] [Authorize] public IActionResult AnalysisToken() { var tokenHeader = HttpContext.Request.Headers["Authorization"].ToString().Replace("Bearer ", ""); var user = JwtHelper.SerializeJwt(tokenHeader); return Ok(user); } } }
5、 生成:https://localhost:44393/api/Authorize/GenToken,解析:https://localhost:44393/api/Authorize/AnalysisToken,在header中添加 Authorization:Bearer token
参考:
https://www.cnblogs.com/danvic712/p/10331976.html
https://blog.csdn.net/weixin_42045719/article/details/91973878
http://cn.voidcc.com/question/p-vckjdtzx-hv.html
https://www.cnblogs.com/danvic712/p/10331976.html
https://blog.csdn.net/baidu_35726140/article/details/84867520
https://www.cnblogs.com/xwc1996/p/14058115.html