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 会打印当前请求人的基本信息,也就是:陈卧龙  在苏州 喜欢美女  这些

@天才卧龙的博客

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