.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

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