My way is not mainstream, but I can control it more flexibly. My favorite friend may as well take a moment to learn
jwt authentication is divided into two parts. The first part is encryption and decryption. The second part is flexible application to middleware. My processing method is to put the obtained token into a specific controller of the api, separate the issued token from the verification, and store the information such as the expiration time of the token, the issuer and the user in config.
1. configuration:
Add configuration in appsettings.json
"Jwt": { "Issuer": "issuer",//Random definition "Audience": "Audience",//Random definition "SecretKey": "abc",//Random definition "Lifetime": 20, //Unit minute "ValidateLifetime": true,//Validation expiration time "HeadField": "useless", //Header field "Prefix": "prefix", //prefix "IgnoreUrls": [ "/Auth/GetToken" ]//Ignore authenticated url }
2: define configuration class:
internal class JwtConfig { public string Issuer { get; set; } public string Audience { get; set; } /// <summary> //Encryption key /// </summary> public string SecretKey { get; set; } /// <summary> ///Life cycle /// </summary> public int Lifetime { get; set; } /// <summary> ///Verify lifecycle or not /// </summary> public bool ValidateLifetime { get; set; } /// <summary> ///Validation header field /// </summary> public string HeadField { get; set; } /// <summary> ///jwt validation prefix /// </summary> public string Prefix { get; set; } /// <summary> ///Ignore authenticated url /// </summary> public List<string> IgnoreUrls { get; set; } }
3. Encryption and decryption interface:
public interface IJwt { string GetToken(Dictionary<string, string> Clims); bool ValidateToken(string Token,out Dictionary<string ,string> Clims); }
4. Implementation class of encryption and decryption:
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(); } /// <summary> /// Get encrypted string /// </summary> 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); } } /// <summary> /// generate Token /// </summary> /// <param name="Claims"></param> /// <returns></returns> 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,//Is it verified? Issuer ValidateAudience = true,//Is it verified? Audience ValidateLifetime = this._jwtConfig.ValidateLifetime,//Whether to verify the failure time ValidateIssuerSigningKey = true,//Is it verified? 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. Define the Controller to get Token:
Inject IJwt in Startup.ConfigureServices
Services. Addtransient < ijwt, JWT > (); / / JWT injection
[Route("[controller]/[action]")] [ApiController] public class AuthController : ControllerBase { private IJwt _jwt; public AuthController(IJwt jwt) { this._jwt = jwt; } /// <summary> /// getToken /// </summary> /// <returns></returns> [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. Create middleware:
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. Middleware exposed
public static class UseUseJwtMiddlewareExtensions { /// <summary> ///Authority check /// </summary> /// <param name="builder"></param> /// <returns></returns> public static IApplicationBuilder UseJwt(this IApplicationBuilder builder) { return builder.UseMiddleware<UseJwtMiddleware>(); } }
8. Use middleware in Startup.Configure:
app.UseJwt();
Take the configuration of 1 as an example:
In addition to the request / auth/getToken, no additional header information is required. All other requests must be accompanied by
userless:prefix (token obtained from Auth/GetToken)