.Net webapi使用JWT实现安全验证
JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案,本文介绍它的用法。
1、nuget中安装jwt
2、新建3个实体
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace Web.Models { /// <summary> /// 登录后的口令信息 /// </summary> public class LoginResult { /// <summary> /// 是否成功 /// </summary> public bool Success { get; set; } /// <summary> /// 令牌 /// </summary> public string Token { get; set; } /// <summary> /// 错误信息 /// </summary> public string Message { get; set; } } public class LoginRequest { public string UserName { get; set; } public string Password { get; set; } } /// <summary> /// 身份验证信息(模拟JWT的payload) /// </summary> public class AuthInfo { /// <summary> /// 用户名 /// </summary> public string UserName { get; set; } /// <summary> /// 角色 /// </summary> public List<string> Roles { get; set; } /// <summary> /// 是否管理员 /// </summary> public bool IsAdmin { get; set; } /// <summary> /// 过期时间 /// </summary> public DateTime? ExpiryDateTime { get; set; } } }
3、新建过滤器
using JWT; using JWT.Serializers; using Model; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web; using System.Web.Http; using System.Web.Http.Controllers; using Web.Models; namespace Web.Filter { /// <summary> /// webapi权限验证(jwt) /// </summary> public class ApiAuthorizeAttribute : AuthorizeAttribute { /// <summary> /// 指示指定的控件是否已获得授权 /// </summary> /// <param name="actionContext"></param> /// <returns></returns> protected override bool IsAuthorized(HttpActionContext actionContext) { var authHeader = from t in actionContext.Request.Headers where t.Key == "auth" select t.Value.FirstOrDefault(); if (authHeader != null) { string token = authHeader.FirstOrDefault(); if (!string.IsNullOrEmpty(token)) { try { //string secureKey = System.Configuration.ConfigurationManager.AppSettings["SecureKey"]; const string secret = "webapi";//随意设置,或者放入web.config中 //secret需要加密 IJsonSerializer serializer = new JsonNetSerializer(); IDateTimeProvider provider = new UtcDateTimeProvider(); IJwtValidator validator = new JwtValidator(serializer, provider); IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder(); IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder); var json = decoder.DecodeToObject<AuthInfo>(token, secret, verify: true); if (json != null) { //判断口令过期时间 if (json.ExpiryDateTime < DateTime.Now) { return false; } //供controller调用: //AuthInfo authInfo = this.RequestContext.RouteData.Values["auth"] as AuthInfo; //authInfo.Roles actionContext.RequestContext.RouteData.Values.Add("auth", json); return true; } return false; } catch (Exception ex) { return false; } } } return false; } /// <summary> /// 处理授权失败的请求 /// </summary> /// <param name="actionContext"></param> protected override void HandleUnauthorizedRequest(HttpActionContext actionContext) { //var erModel = new //{ // Success = "false", // ErrorCode = "401" //}; ResponseMessage res = new ResponseMessage(401, "无访问权限"); actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.OK, res, "application/json"); } } }
4、登录api
public LoginResult Login([FromBody]LoginRequest request) { LoginResult rs = new LoginResult(); //这是是获取用户名和密码的,这里只是为了模拟 if (request.UserName == "zhangsan" && request.Password == "123456") { AuthInfo info = new AuthInfo { UserName = "zhangsan", Roles = new List<string> { "Admin", "Manage" }, IsAdmin = true, ExpiryDateTime = DateTime.Now.AddHours(2) }; try { const string secret = "webapi";//口令加密秘钥 //secret需要加密 IJwtAlgorithm algorithm = new HMACSHA256Algorithm();//加密方式 IJsonSerializer serializer = new JsonNetSerializer();//序列化Json IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();//base64加解密 IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);//JWT编码 var token = encoder.Encode(info, secret);//生成令牌 rs.Message = "成功"; rs.Token = token; rs.Success = true; } catch (Exception ex) { rs.Message = ex.Message; rs.Success = false; } } else { rs.Message = "用户信息为空"; rs.Success = false; } return rs; }
5、获取数据api
[HttpGet] [ApiAuthorize] public ResponseMessage GetData(int id) { //do }
6、前端登录
//login $("#btn_login").click(function () { $.ajax({ url: '/api/Users/login', type: "post", data: { UserName: "zhangsan", Password: "123456"}, success: function (data) { console.log(data) if (data.Success) { //演示,将token保存在全局变量中。 //实现项目中应该保存在cookie或者webStorage中 window.token = data.Token; alert("登录成功"); } else { alert("登录失败:" + data.Message); } }, error: function () { alert("程序错误"); } }) return false; })
7、前端调用api获取数据
//get $("#btn_get").click(function () { $.ajax({ url: '/api/Users/getData/1', type: "get", headers: { "auth": window.token },//通过请求头来发送token success: function (res) { console.log(res) if (res.code == 0) { alert("操作成功"); } else { alert("操作失败:"+res.msg); } }, error: function (res) { alert("程序错误"); } }) return false; })
//over
//成功一定有方法,失败一定有原因。