.net core webapi jwt 更为清爽的认证 ,续期很简单

发布时间:2019-05-25 14:46  浏览次数:39

 

 

我的方式非主流,控制却可以更加灵活,喜欢的朋友,不妨花一点时间学习一下


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; } /// <summary> /// 加密key /// </summary> public string
SecretKey { get; set; } /// <summary> /// 生命周期 /// </summary> public int
Lifetime { get; set; } /// <summary> /// 是否验证生命周期 /// </summary> public bool
ValidateLifetime { get; set; } /// <summary> /// 验证头字段 /// </summary> public
string HeadField { get; set; } /// <summary> /// jwt验证前缀 /// </summary> public
string Prefix { get; set; } /// <summary> /// 忽略验证的url /// </summary> public
List<string> 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(); } /// <summary>
/// 获取到加密串 /// </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> /// 生成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,//是否验证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; }/// <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.创建中间件:
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 { /// <summary> /// 权限检查
/// </summary> /// <param name="builder"></param> /// <returns></returns>
public static IApplicationBuilder UseJwt(this IApplicationBuilder builder) {
return builder.UseMiddleware<UseJwtMiddleware>(); } }
8.在Startup.Configure中使用中间件:

 app.UseJwt(); 

 

以1的配置为例:

除了请求 /auth/getToken 不需要加头信息外,其他的请求一律要求头信息中必须带着 

userless:prefix (从Auth/GetToken中获取到的token)

再提供一个demo的下载链接

链接: https://pan.baidu.com/s/1tLpZ-HbZJPp37HQVWew8Rg 提取码: 7n9g 

一些截图: 

1,在需要认证的的控制器中不需要做任何操作,可以通过httpcontext.item拿到存入clims中的信息



2.startup截图



 3.发放token

4.配置



 简单测试

 

直接请求  无权限

 

带着token去请求api/values得到响应



 




这里的exp就是该token的失效时间(unti时间戳),可以定义一个配置来确定什么时候要去重新生成token,这个动作在中间件中进行(比如给头信息中带上ReToken)客户端下次就用ReToken中的Token重新进行访问,很容易就做到了对token的续期操作

标签

归档

阅读排行