JWT加密及认证

    技术2022-07-10  105

    什么是JWT呢?

    Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

    JWT的优点:无需在服务端存储用户数据,减轻服务端压力,轻量级,json风格,比较简单,跨语言;

    缺点:token一旦签发,无法修改(无法更新token有效期,用户登录状态刷新难以实现)

    使用JWT一般我们可以做一些用户认证,比如用户注册后需要发一封邮件让其激活账户,通常邮件中需要有一个链接,这个链接需要具备以下的特性:能够标识用户,该链接具有时效性(通常只允许几小时之内激活),不能被篡改以激活其他可能的账户…这种场景就和 jwt 的特性非常贴近,jwt 的 payload 中固定的参数:iss 签发者和 exp 过期时间正是为其做准备的。

    JWT包含三部分:Header(声明头),Payload(加密内容),VERIFY SIGNATURE(验证部分),

    通过登录服务器返回给客户端一个token值,当客户端再次请求服务端时带上token值,这样就可以校验客户端

    下面是简单代码示例:

    //客户端部分 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <script src="../JS/jquery.min.js"></script> <script> // $.get('http://localhost:52056/api/Values', function(data) { // console.log(data); // }); function btnLogin() { let name = document.getElementById('loginName').value; let pwd = document.getElementById('loginPwd').value; // $.post( // 'http://localhost:52056/api/values/login', // { LoginName: name, Pwd: pwd }, // function(data) { // console.log(data); // }, // ); $.ajax({ url: 'http://localhost:52056/api/Values/Login', type: 'post', data: { LoginName: name, Pwd: pwd, }, success(data) { if (data) { sessionStorage.setItem('token', data); } console.log(data); }, error(data) { console.log(data); }, }); } function btnGetUserInfo() { // if (!sessionStorage.getItem('token')) return; $.ajax({ url: 'http://localhost:52056/api/Values/getInfo', type: 'get', beforeSend: function(xhr) { xhr.setRequestHeader('token', sessionStorage.getItem('token')); }, success(data) { console.log(data); }, error(data) { console.log(data); }, }); } </script> </head> <body> <input type="text" id="loginName" /> <input type="text" id="loginPwd" /> <button onclick="btnLogin()">登录</button> <button onclick="btnGetUserInfo()">获取当前用户信息</button> <script></script> </body> </html> //jwt加密解密部分 public class JWTTool { public static string key = "jwttest"; public static string Endode(Dictionary<string, object> payload, string key) { IJwtAlgorithm algorithm = new HMACSHA256Algorithm(); IJsonSerializer serializer = new JsonNetSerializer(); IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder(); IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder); //添加一个jwt时效串 payload.Add("timeout", DateTime.Now.AddDays(1)); return encoder.Encode(payload, key); } public static Dictionary<string, object> Decode(string token, string key) { try { token = token.Replace('"', ' ').Trim(); IJsonSerializer serializer = new JsonNetSerializer(); IDateTimeProvider provider = new UtcDateTimeProvider(); IJwtValidator validator = new JwtValidator(serializer, provider); IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder(); IJwtAlgorithm algorithm = new HMACSHA256Algorithm(); IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder, algorithm); var json = decoder.Decode(token, key, true); var result = JsonConvert.DeserializeObject<Dictionary<string, object>>(json); if ((DateTime)result["timeout"] < DateTime.Now) { throw new Exception("jwt已经过期,请重新登录"); } result.Remove("timeout"); return result; } catch (TokenExpiredException) { throw new Exception("Token has expired"); } catch (SignatureVerificationException) { throw new Exception("签名验证失败,数据可能被篡改"); } } } //校验 public class MyAuthAttribute : Attribute, IAuthorizationFilter { public bool AllowMultiple { get; } public async Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation) { //actionContext.Request.Headers.Pragma; if (actionContext.Request.Headers.TryGetValues("token", out IEnumerable<string> token)) { string loginName = Tools.JWTTool.Decode(token.First(), Tools.JWTTool.key)["loginName"].ToString(); (actionContext.ControllerContext.Controller as ApiController).User = new Auth.ApplicationUser(loginName); return await continuation(); } return new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized); } }

    Processed: 0.010, SQL: 9