我的方式非主流, 控制却可以更加灵活, 喜欢的朋友, 不妨花一点时间学习一下
jwt 认证分为两部分, 第一部分是加密解密, 第二部分是灵活的应用于中间件, 我的处理方式是将获取 token 放到 API 的一个具体的 controller 中, 将发放 token 与验证分离, token 的失效时间, 发证者, 使用者等信息存放到 config 中.
1. 配置:
在 appsettings.JSON 中增加配置
- "Jwt": {
- "Issuer": "issuer",// 随意定义
- "Audience": "Audience",// 随意定义
- "SecretKey": "abc",// 随意定义
- "Lifetime": 20, // 单位分钟
- "ValidateLifetime": true,// 验证过期时间
- "HeadField": "useless", // 头字段
- "Prefix": "prefix", // 前缀
- "IgnoreUrls": [ "/Auth/GetToken" ]// 忽略验证的 url
- }
2: 定义配置类:
- internal class JwtConfig
- {
- public string Issuer { get; set; }
- public string Audience { get; set; }
- ///
- /// 加密 key
- ///
- public string SecretKey { get; set; }
- ///
- /// 生命周期
- ///
- public int Lifetime { get; set; }
- ///
- /// 是否验证生命周期
- ///
- public bool ValidateLifetime { get; set; }
- ///
- /// 验证头字段
- ///
- public string HeadField { get; set; }
- ///
- /// jwt 验证前缀
- ///
- public string Prefix { get; set; }
- ///
- /// 忽略验证的 url
- ///
- public List IgnoreUrls { get; set; }
- }
3. 加密解密接口:
- public interface IJwt
- {
- string GetToken(Dictionary<string, string> Clims);
- bool ValidateToken(string Token,out Dictionary<string ,string> Clims);
- }
4. 加密解密的实现类:
- install-package System.IdentityModel.Tokens.Jwt
- public class Jwt : IJwt
- {
- private IConfiguration _configuration;
- private string _base64Secret;
- private JwtConfig _jwtConfig = new JwtConfig();
- public Jwt(IConfiguration configration)
- {
- this._configuration = configration;
- configration.GetSection("Jwt").Bind(_jwtConfig);
- GetSecret();
- }
- ///
- /// 获取到加密串
- ///
- private void GetSecret()
- {
- var encoding = new System.Text.ASCIIEncoding();
- byte[] keyByte = encoding.GetBytes("salt");
- byte[] messageBytes = encoding.GetBytes(this._jwtConfig.SecretKey);
- using (var hmacsha256 = new HMACSHA256(keyByte))
- {
- byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
- this._base64Secret= Convert.ToBase64String(hashmessage);
- }
- }
- ///
- /// 生成 Token
- ///
- ///
- ///
- public string GetToken(Dictionary<string, string> Claims)
- {
- List<Claim> claimsAll = new List<Claim>();
- foreach (var item in Claims)
- {
- claimsAll.Add(new Claim(item.Key, item.Value));
- }
- var symmetricKey = Convert.FromBase64String(this._base64Secret);
- var tokenHandler = new JwtSecurityTokenHandler();
- var tokenDescriptor = new SecurityTokenDescriptor
- {
- Issuer = _jwtConfig.Issuer,
- Audience = _jwtConfig.Audience,
- Subject = new ClaimsIdentity(claimsAll),
- NotBefore = DateTime.Now,
- Expires = DateTime.Now.AddMinutes(this._jwtConfig.Lifetime),
- SigningCredentials =new SigningCredentials(new SymmetricSecurityKey(symmetricKey),
- SecurityAlgorithms.HmacSha256Signature)
- };
- var securityToken = tokenHandler.CreateToken(tokenDescriptor);
- return tokenHandler.WriteToken(securityToken);
- }
- public bool ValidateToken(string Token, out Dictionary<string, string> Clims)
- {
- Clims = new Dictionary<string, string>();
- ClaimsPrincipal principal = null;
- if (string.IsNullOrWhiteSpace(Token))
- {
- return false;
- }
- var handler = new JwtSecurityTokenHandler();
- try
- {
- var jwt = handler.ReadJwtToken(Token);
- if (jwt == null)
- {
- return false;
- }
- var secretBytes = Convert.FromBase64String(this._base64Secret);
- var validationParameters = new TokenValidationParameters
- {
- RequireExpirationTime = true,
- IssuerSigningKey = new SymmetricSecurityKey(secretBytes),
- ClockSkew = TimeSpan.Zero,
- ValidateIssuer = true,// 是否验证 Issuer
- ValidateAudience = true,// 是否验证 Audience
- ValidateLifetime = this._jwtConfig.ValidateLifetime,// 是否验证失效时间
- ValidateIssuerSigningKey = true,// 是否验证 SecurityKey
- ValidAudience = this._jwtConfig.Audience,
- ValidIssuer = this._jwtConfig.Issuer
- };
- SecurityToken securityToken;
- principal = handler.ValidateToken(Token, validationParameters, out securityToken);
- foreach (var item in principal.Claims)
- {
- Clims.Add(item.Type, item.Value);
- }
- return true;
- }
- catch (Exception ex)
- {
- return false;
- }
- }
- }
5. 定义获取 Token 的 Controller:
在 Startup.ConfigureServices 中注入 IJwt
- services.AddTransient<IJwt, Jwt>();//Jwt 注入
- [Route("[controller]/[action]")]
- [ApiController]
- public class AuthController : ControllerBase
- {
- private IJwt _jwt;
- public AuthController(IJwt jwt)
- {
- this._jwt = jwt;
- }
- ///
- /// getToken
- ///
- ///
- [HttpPost]
- public IActionResult GetToken()
- {
- if (true)
- {
- Dictionary<string, string> clims = new Dictionary<string, string>();
- clims.Add("userName", userName);
- return new JsonResult(this._jwt.GetToken(clims));
- }
- }
- }
6. 创建中间件:
- public class UseJwtMiddleware
- {
- private readonly RequestDelegate _next;
- private JwtConfig _jwtConfig =new JwtConfig();
- private IJwt _jwt;
- public UseJwtMiddleware(RequestDelegate next, IConfiguration configration,IJwt jwt)
- {
- _next = next;
- this._jwt = jwt;
- configration.GetSection("Jwt").Bind(_jwtConfig);
- }
- public Task InvokeAsync(HttpContext context)
- {
- if (_jwtConfig.IgnoreUrls.Contains(context.Request.Path))
- {
- return this._next(context);
- }
- else
- {
- if (context.Request.Headers.TryGetValue(this._jwtConfig.HeadField, out Microsoft.Extensions.Primitives.StringValues authValue))
- {
- var authstr = authValue.ToString();
- if (this._jwtConfig.Prefix.Length> 0)
- {
- authstr = authValue.ToString().Substring(this._jwtConfig.Prefix.Length+1, authValue.ToString().Length -(this._jwtConfig.Prefix.Length+1));
- }
- if (this._jwt.ValidateToken(authstr, out Dictionary<string, string> Clims))
- {
- foreach (var item in Clims)
- {
- context.Items.Add(item.Key, item.Value);
- }
- return this._next(context);
- }
- else
- {
- context.Response.StatusCode = 401;
- context.Response.ContentType = "application/json";
- return context.Response.WriteAsync("{\"status\":401,\"statusMsg\":\"auth vaild fail\"}");
- }
- }
- else
- {
- context.Response.StatusCode = 401;
- context.Response.ContentType = "application/json";
- return context.Response.WriteAsync("{\"status\":401,\"statusMsg\":\"auth vaild fail\"}");
- }
- }
- }
- }
7. 中间件暴露出去
- public static class UseUseJwtMiddlewareExtensions
- {
- ///
- /// 权限检查
- ///
- ///
- ///
- public static IApplicationBuilder UseJwt(this IApplicationBuilder builder)
- {
- return builder.UseMiddleware<UseJwtMiddleware>();
- }
- }
8. 在 Startup.Configure 中使用中间件:
App.UseJwt();
以 1 的配置为例:
除了请求 /auth/getToken 不需要加头信息外, 其他的请求一律要求头信息中必须带着
userless:prefix (从 Auth/GetToken 中获取到的 token)
来源: http://www.bubuko.com/infodetail-3071211.html