NetCore3.1 Json web token 中間件

十年河東,十年河西,莫欺少年窮

學無止境,精益求精

1、項目中引入jwt

2、創建token的實例代碼如下:

2.1、所需的實體類

    /// <summary>
    /// POCO類,用來存儲簽發或者驗證jwt時用到的信息
    /// </summary>
    public class TokenOptions
    {
        public static string Secret = "chenwolong_love_woman_2022";//私鑰 至少16個字符

        public static string Issuer = "webapi.cn";

        public static string Audience = "WebApi";

        public static int AccessExpiration = 180;//過期時間
         
    }

2.2、創建Token

        public dynamic UserLogin(string uname, string upwd)
        {
            var userinfo = new { uname = "陳臥龍", sex = "", age = 30, userrole = new List<string>() { "admin", "staff" }, city = "蘇州", love = "美女" };
            var expiresTime = DateTime.Now.AddMinutes(TokenOptions.AccessExpiration); 
            var claims = new[]
           {
                    new Claim(ClaimTypes.Name,uname),
                    new Claim(ClaimTypes.Role,ClaimTypes.Role ), // 
                    new Claim(ClaimTypes.Actor,"wuan"),
                    new Claim(ClaimTypes.Country,"China"),
                    new Claim(ClaimTypes.Expired,"China"),
                    new Claim(ClaimTypes.UserData,JsonConvert.SerializeObject(userinfo))
            };
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(TokenOptions.Secret));
            var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            var jwtToken = new JwtSecurityToken(TokenOptions.Issuer, TokenOptions.Audience, claims, expires: expiresTime, signingCredentials: credentials);
            
             var token = new JwtSecurityTokenHandler().WriteToken(jwtToken);
            //加上 "Bearer " 是爲了兼容swagger 
            return new { token = "Bearer "+ token, expiresTime = expiresTime.ToString("yyyy-MM-dd HH:mm:ss") };

        }

3、jwt 中間件

3.1、所需的實體

    public class CurrentUser
    {
        public string uname { get; set; }
        public string sex { get; set; }
        public int age { get; set; }
        public List<string> userrole { get; set; } = new List<string>();
        public string city { get; set; }
        public string love { get; set; }
    }

仔細看這個實體類,和我們創建token時定義的匿名變量是一致的

 

 3.2、中間件的編寫

using Microsoft.AspNetCore.Http;
using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using wuanModel;

namespace wuanIotApi.Middlewares
{

    public class JwtMiddlewares
    {
        private readonly RequestDelegate _next;

        public JwtMiddlewares(RequestDelegate next)
        {
            _next = next;
        }

        public async Task Invoke(HttpContext context)
        {
            context.Request.Headers.TryGetValue("Authorization", out var apiKeyHeaderValues);
            if (apiKeyHeaderValues.Count > 0)
            {
                //這裏是爲了兼容swagger
                var token = apiKeyHeaderValues.FirstOrDefault().Replace("Bearer ","");
                 
                AttachUserToContext(context, token);
            }

             await _next.Invoke(context);
        }

        private void AttachUserToContext(HttpContext context, string token)
        {
            try
            {
                var tokenHandler = new JwtSecurityTokenHandler();
                var key = Encoding.UTF8.GetBytes(TokenOptions.Secret); //獲取到用於生成token的加密key
               
                tokenHandler.ValidateToken(token, new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true, //是否驗證Key SecurityKey
                    IssuerSigningKey = new SymmetricSecurityKey(key), //拿到SecurityKey
                    ValidateIssuer = false, //是否驗證Issuer
                    ValidateAudience = false, //是否驗證Audience
                    ValidateLifetime = true, //是否驗證Token的失效時間
                }, out SecurityToken validatedToken); 

                var jwtToken = (JwtSecurityToken)validatedToken;
                //調試得知,ValidTo時間時區和北京時間相差8小時,通過這個時間,判斷Token是否過期
                var ValidTo = jwtToken.ValidTo.AddHours(8);
                if (ValidTo < DateTime.Now)
                { 
                    return; 
                }
                var userdata  = jwtToken.Claims.Where(A => A.Type.Contains("userdata")).ToList().FirstOrDefault().Value; 
                //寫入認證信息,方便業務類使用
                var claimsIdentity = new ClaimsIdentity(new Claim[] { new Claim("userdata", userdata) });
                Thread.CurrentPrincipal = new ClaimsPrincipal(claimsIdentity);

                //將Token中解析出來的用戶信息存入當前請求中
                context.Items["userdata"] = Newtonsoft.Json.JsonConvert.DeserializeObject<CurrentUser>(userdata);
            }
            catch (Exception ex)
            {
                context.Items["userdata"] = null;
            }
        }
    }
}


context.Items["userdata"]的使用

4、創建基礎控制器

4.1,基礎控制器

using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Newtonsoft.Json;
using wuanCommon;
using wuanModel;

namespace wuanIotApi.Controllers
{
    [Authorize]
    [Route("api/V1/[controller]")]
    [ApiExplorerSettings(GroupName = "V1")]
    public class BaseController : Controller
    {
        public CurrentUser user = new CurrentUser();
        public BaseController() { }
        /// <summary>
        /// 第2步執行基類構造函數
        /// 第3步 執行父類的異步方法  異步方法  似乎可以和OnActionExecuting同時執行
        /// </summary>
        /// <param name="context"></param>
        /// <param name="next"></param>
        /// <returns></returns>
        public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            return base.OnActionExecutionAsync(context, next);
        }

        /// <summary>
        /// 第4步 執行OnActionExecuting方法
        /// </summary>
        /// <param name="context"></param>
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            if (!Request.Headers.TryGetValue("Authorization", out var apiKeyHeaderValues))
            {
                user =null;
            }
            else
            {
                user = (CurrentUser)this.HttpContext.Items["userdata"];
            }
        }

        /// <summary>
        /// 第五步執行基類Action
        /// 第6步 Aciton執行完畢後 執行 OnActionExecuted
        /// </summary>
        /// <param name="context"></param>
        public override void OnActionExecuted(ActionExecutedContext context)
        {
            base.OnActionExecuted(context);
        }

        
    }
}

4.2 ,繼承自基礎控制器的其他webapi控制器

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using wuanInterface;

namespace wuanIotApi.Controllers
{
    public class UserController : BaseController
    {
        private readonly IUserService service;
        public UserController(IUserService _service)
        {
            this.service = _service;
        }
        /// <summary>
        /// 用戶登錄
        /// </summary>
        /// <returns></returns>
        [AllowAnonymous]
        [HttpPost]
        [Route("UserLogin")]
        public IActionResult UserLogin()
        { 
            var result = service.UserLogin("", "");
            return Ok(result);
        }

        [HttpPost]
        [Route("TokenTest")]
        public IActionResult TokenTest()
        { 
            return Ok(user);
        }
    }
}

當帶Token請求時,其中 TokenTest 會打印當前請求人的基本信息,也就是:陳臥龍  在蘇州 喜歡美女  這些

@天才臥龍的博客

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