.Net webapi使用JWT实现安全验证

 

JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案,本文介绍它的用法。

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章