.NET Core 6.0 配置自定义JWT鉴权

xjxue / 2023-07-30 / 原文

JWT授权配置

1、 安装Microsoft.IdentityModel.Tokens包;

2、 创建一个认证用户信息实体类UserInfo

3、 创建一个JWT配置类 JWTTokenOptions

    public class JwtTokenOptions

    {

        /// <summary>

        /// JWT 认证Key

        /// </summary>

        public string SecurityKey { get; set; }

 

        /// <summary>

        /// token 过期时间,单位为小时

        /// </summary>

        public int Expire { get; set; }

 

        /// <summary>

        /// 接受者受众者

        /// </summary>

        public string Audience { get; set; }

 

        /// <summary>

        /// 发行者

        /// </summary>

        public string Issuer { get; set; }

}

 

 

4、 在appsettings.json 配置文件添加 JWT Token 配置信息

"JwtTokenOptions": {

    "SecurityKey": "xxxeegwawegghtop6!@#$%%^", //用于生成token的秘钥 至少16位此处24位,可输入任意字符

    "Expire": "2", //单位小时

    "Audience": "",

    "Issuer": ""

  }

 

5、 创建Jwt管理接口用于创建Token

public interface IAuthManage

    {

        /// <summary>

        /// 生成JwtToken

        /// </summary>

        /// <param name="userInfo"></param>

        /// <returns></returns>

        string GenrateJwtToken(UserInfo userInfo);

    }

6、 创建Jwt管理接口实现类用于创建Token

using IPSP.DTO.Auth;

using Microsoft.IdentityModel.Tokens;

using System.IdentityModel.Tokens.Jwt;

using System.Security.Claims;

using System.Text;

using System.Text.Json;

 

namespace IPSP.Common.Auth

{

    //用于生成token的实现类

    public class JwtAuthManage : IAuthManage

    {

        private readonly JwtTokenOptions _jwtTokenOptions;

       

        public JwtAuthManage(JwtTokenOptions jwtTokenOptions)

        {

            _jwtTokenOptions = jwtTokenOptions;

        }

 

        public string GenrateJwtToken(UserInfo userInfo)

        {

            string hours = _jwtTokenOptions.Expire.ToString();

 

            var tokenHandler = new JwtSecurityTokenHandler();

 

            //获取用于生成Token的key

            var key = Encoding.ASCII.GetBytes(_jwtTokenOptions.SecurityKey);

            var tokenDescriptor = new SecurityTokenDescriptor

            {

                //获取或者设置身份信息

                Subject = new System.Security.Claims.ClaimsIdentity(new Claim[] {

                    new Claim("userInfo", JsonSerializer.Serialize(userInfo))

                }),

                //设置过期时间

                Expires = DateTime.UtcNow.AddHours(_jwtTokenOptions.Expire),

 

                //证书签名

                SigningCredentials = new SigningCredentials(

                    new SymmetricSecurityKey(key),

                    SecurityAlgorithms.HmacSha256Signature

                )

            };

 

            var token = tokenHandler.CreateToken(tokenDescriptor);

 

            return tokenHandler.WriteToken(token);

        }

    }

}

7、 创建JWT 中间件JwtMiddleware 用于验证Token

using IPSP.BLL.IService.SystemManage;

using IPSP.Common.Auth;

using IPSP.DTO.Auth;

using Microsoft.IdentityModel.Tokens;

using System.IdentityModel.Tokens.Jwt;

using System.Security.Claims;

using System.Text;

using System.Text.Json;

 

namespace IPSP.Middlewares

{

    public static class JwtMiddlewareExtension

    {

        public static IApplicationBuilder UseJwtMiddleware(this IApplicationBuilder builder)

        {

            return builder.UseMiddleware<JwtMiddleware>();

        }

    }

    public class JwtMiddleware

    {

        private readonly RequestDelegate _next;

        private readonly JwtTokenOptions _jwtTokenOptions;

 

        public JwtMiddleware(RequestDelegate next, JwtTokenOptions jwtTokenOptions)

        {

            _next = next;

            _jwtTokenOptions = jwtTokenOptions;

        }

 

        public async Task InvokeAsync(HttpContext context)

        {

            //从上下文提取token

            var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();

 

            if (token != null)

            {

 

            }

 

            //调用下一个中间件

            await _next(context);

        }

 

        public void AttacheUserToContext(HttpContext context,IUserService userService,string? token)

        {

            try

            {

                var tokenHandler = new JwtSecurityTokenHandler();

               

                //用于生产token

                var key = Encoding.ASCII.GetBytes(_jwtTokenOptions.SecurityKey);

                tokenHandler.ValidateToken(token, new Microsoft.IdentityModel.Tokens.TokenValidationParameters

                {

                    ValidateIssuerSigningKey = true,//是否验证key SecurityKey

                    IssuerSigningKey = new SymmetricSecurityKey(key),//获取SecurityKey

                    ValidateIssuer = false,//是否验证Issuer

                    ValidateAudience = false,//是否验证Audience

                    ValidateLifetime = true,//是否验证Token的失效时间

                },out SecurityToken validateToken);

 

                var jwtToken = (JwtSecurityToken)validateToken;

 

                //获取Token

                var userInfo = jwtToken.Claims.First(x=>x.Type == "userInfo").Value;

 

                var userModel = JsonSerializer.Deserialize<UserInfo>(userInfo);

 

                //写入认证信息,方便业务类使用

                var claimsIdentity = new ClaimsIdentity(new Claim[] {

                    new Claim("userInfo",jwtToken.Claims.First(x=>x.Type == "userInfo").Value)

                });

                Thread.CurrentPrincipal = new ClaimsPrincipal(claimsIdentity);

 

                //将Token中解析出来的用户信息存入当前请求中

                context.Items["UserInfo"] = userModel;

            }

            catch (Exception)

            {

 

                context.Items["UserInfo"] = null;

            }

        }

    }

}

8、 创建自定义全局权限认证过滤器

using Microsoft.AspNetCore.Authorization;

using Microsoft.AspNetCore.Mvc;

using Microsoft.AspNetCore.Mvc.Authorization;

using Microsoft.AspNetCore.Mvc.Filters;

 

namespace IPSP.Common.Auth

{

    /// <summary>

    /// 鉴权、身份认证授权的过滤器

    /// </summary>

    public class CustomAuthorizeAttribute : IAuthorizationFilter

    {

        public void OnAuthorization(AuthorizationFilterContext context)

        {

           var user = context.HttpContext.Items["UserInfo"];

 

            //验证是否需要授权和授权信息

            if (HasAllowAnonymous(context) == false && user == null)

            {

                context.Result = new JsonResult(new { message = "Token验证失败或已过期请重新登录并获取!!" })

                {

                    StatusCode = StatusCodes.Status401Unauthorized

                };

            }

       

        }

 

        private static bool HasAllowAnonymous(AuthorizationFilterContext context)

        {

            var filters = context.Filters;

 

            if (filters.OfType<IAllowAnonymousFilter>().Any())

            {

                return true;

            }

 

            var endpoint = context.HttpContext.GetEndpoint();

            return endpoint?.Metadata?.GetMetadata<IAllowAnonymous>() != null;

        }

    }

}

9、 在Program.cs 文件中读取JWT配置,并将JWT配置对象 jwtTokenOptions,JwtAuthManage依赖注入

var builder = WebApplication.CreateBuilder(args);

 

//读取配置文件中的JwtTokenOptions字段

builder.Services.Configure<JwtTokenOptions>(builder.Configuration.GetSection("JwtTokenOptions"));

 

//将字段中的值赋值给JwtTokenOptions 类

JwtTokenOptions tokenOptions = new JwtTokenOptions();

builder.Configuration.Bind("JwtTokenOptions",tokenOptions);

#region IOC

// Add services to the container.

 

//依赖注入 将配置注入

builder.Services.AddSingleton(tokenOptions);

builder.Services.AddSingleton<IAuthManage>(new JwtAuthManage(tokenOptions));

10、在Program.cs 文件中启用JWT中间件 JwtMiddleware

//在授权前调用验证token中间件

app.UseJwtMiddleware();

app.UseAuthorization();

 

注意:在授权前调用验证token中间件

 

11、使用token

    [Route("api/[controller]")]

    [ApiController]

    public class LoginController : ControllerBase

    {

        private IUserService _userservice;

        private readonly ILogger<LoginController> _logger;

        private readonly IAuthManage _authManage;

        private readonly JwtTokenOptions _jwtTokenOptions;

 

        public LoginController(IUserService userService,ILogger<LoginController> logger,IAuthManage authManage,IOptionsMonitor<JwtTokenOptions> jwtTokenOptions) {

            _userservice= userService;

            _logger = logger;

            _authManage= authManage;

            _jwtTokenOptions = jwtTokenOptions.CurrentValue;

        }

 

        [HttpGet]

        public async Task<IActionResult> UserLogin([FromQuery]LoginModel model)

        {

            User user = new User();

            user.Badge = model.Badge;

            user.Password = model.Password;

 

            UserInfo userInfo = await _userservice.Login(user.Badge,user.Password);

           

 

            if (userInfo != null)

            {

                string token = _authManage.GenrateJwtToken(userInfo);//生成token

                _logger.LogInformation($"{userInfo.Badge}-{userInfo.CName}在{DateTime.Now.ToString("yyyy-dd-MM HH:mm:ss")}登入了IPSP系统!");

 

                var result = new

                {

                    user= userInfo,

                    token=token

                };

 

                return Ok(result);

            }

            return Ok(userInfo);

        }

}