ASP.NETCore-中间件Middleware(六)_认证+授权中间件-JWT

  先随便贴点代码

1、引用JwtBearer Nuget包

2、Program.cs启用JWT

using fly_chat1_net7.Middlewares;
using fly_chat1_net7.Middlewares.UserLoginAuthorizations;
using fly_webapi.IService.UserService.LoginAuthorization;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.CookiePolicy;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using System;
using System.Net.Http;
using System.Text;
using System.Threading;

namespace fly_chat1_net7
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // try前也可能报错,但是错误是可控的。实际项目中使用时可以再加个try,只记录日志到文件中。
            var configuration = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())  // 设置“configuration”的查找目录为程序目录
                .AddJsonFile("appsettings.json")  // 设置“configuration”的读取文件
                .Build();  // 获取配置
            
                var builder = WebApplication.CreateBuilder(args);
                // 中间件知识https://learn.microsoft.com/zh-cn/aspnet/core/fundamentals/middleware/?view=aspnetcore-6.0#order

                #region 容器Services
                builder.Services.AddControllers();            // 添加Controller
                builder.Services.AddHttpContextAccessor();    // 操作Http上下文;比如:AOP里面可以获取IOC对象
                builder.Services.AddEndpointsApiExplorer();   // ASP.NET Core自身提供;Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle

                #region JWT
                IUserAuthorization userAuthorization = new UserAuthorization_JWT();
                builder.Services.AddSingleton(userAuthorization);  // JWT认证中间件
                builder.Services.AddAuthentication(options => {
                    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                })
                    .AddJwtBearer(options => {  // 配置Authentication用的JWT
                        options.TokenValidationParameters = new TokenValidationParameters
                        {
                            ValidateIssuerSigningKey = true,
                            ValidIssuer = configuration["Jwt:Issuer"],
                            ValidAudience = configuration["Jwt:Audience"],
                            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["Jwt:SecurityKey"] ?? "a48fafeefd334237c2ca207e842afe0b")),
                            ClockSkew = TimeSpan.Zero
                        };
                    });
                #endregion JWT
                #endregion 容器Services

                var app = builder.Build();
            
                app.UseHttpsRedirection();
                app.UseStaticFiles();  // 在UseRouting()前
                app.UseRouting();

                app.UseAuthentication();  // 认证
                app.UseAuthorization();   // 授权

                app.MapControllers();
                app.Run();
        }
    }
}

3、JWT的配置(appsettings.json中)

{
  "Jwt": {
    "Issuer": "yunyistars.com", // token 的颁发者
    "Audience": "yunyistars.com", // token 的接收者
    "SecurityKey": "a48fafeefd334237c2ca207e842afe0b", // 加密 token的key值(32位)
    "ExpireMinutes": "20" // token 的过期时间(单位分钟)
  },
}

4、JWT登录认证中间件

using fly_webapi.IService.UserService.LoginAuthorization;
using fly_webapi.ViewModel.Users;
using Microsoft.Extensions.Primitives;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Net;
using System.Security.Claims;
using System.Text;

namespace fly_chat1_net7.Middlewares.UserLoginAuthorizations
{
    /// <summary>
    /// 用户认证_JWT
    /// </summary>
    public class UserAuthorization_JWT : IUserAuthorization
    {
        /// <summary>
        /// 配置文件
        /// </summary>
        IConfigurationRoot _configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())  // 设置“configuration”的查找目录为程序目录
.AddJsonFile("appsettings.json")  // 设置“configuration”的读取文件
.Build();  // 获取配置

        /// <summary>
        /// 生成用户信息-创建Token
        /// 从JWT中读取信息var name = HttpContext.User.FindFirst(JwtRegisteredClaimNames.Name)?.Value;
        /// </summary>
        /// <param name="userInfoVModel">用户信息</param>
        public AuthorizationObject Create(UserInfoVModel userInfoVModel)
        {
            DateTime expiresAt = DateTime.UtcNow.AddMinutes(Convert.ToDouble(_configuration["Jwt:ExpireMinutes"]));  // token 的过期时间

            // 签发一个加密后的用户信息凭证ClaimsPrincipal,用来标识用户的身份
            IEnumerable<Claim> claims = new Claim[] {  // 将用户信息添加到 Claim 中
                new Claim(ClaimTypes.Name,userInfoVModel.UserName),            // 用户名
                new Claim(ClaimTypes.Role,userInfoVModel.RoleId.ToString()),   // 角色ID
                new Claim(ClaimTypes.MobilePhone,userInfoVModel.MobilePhone),  // 手机号
                new Claim(ClaimTypes.Email,userInfoVModel.Email),              // 邮箱号
                new Claim(ClaimTypes.Expiration,expiresAt.ToString())  // 过期日期
            };
            //var identity = new ClaimsIdentity(claims, JwtBearerDefaults.AuthenticationScheme);
            //_httpContextAccessor.HttpContext.SignInAsync(JwtBearerDefaults.AuthenticationScheme, new ClaimsPrincipal(identity));

            // 设置 SecurityTokenDescriptor
            SymmetricSecurityKey key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:SecurityKey"] ?? "a48fafeefd334237c2ca207e842afe0b"));  // 加密 token 的key值
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(claims),       // 用户信息
                Issuer = _configuration["Jwt:Issuer"],      // Jwt token 的签发者
                Audience = _configuration["Jwt:Audience"],  // Jwt token 的接收者
                Expires = expiresAt,                        // 过期时间
                SigningCredentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256),  //创建 token
            };

            JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
            var token = tokenHandler.CreateToken(tokenDescriptor);  // 创建Token

            //存储 Token 信息
            var jwt = new AuthorizationObject
            {
                //UserId = userInfoVModel.UserId,  // 用户的Id
                AuthorizationType=AuthorizationObjectType.Jwt_Microsoft,  // AuthorizationObject类型为Jwt_Microsoft
                Token = tokenHandler.WriteToken(token),                   // 获取创建完的Token
                Expiration= expiresAt                                     // 过期时间
            };

            // 把Token存放到MemoryCache或Redis中

            return jwt;
        }

        /// <summary>
        /// 停用Token
        /// </summary>
        /// <param name="token">Token</param>
        /// <returns></returns>
        public async Task<bool> DeactivateAsync(string token)
        {
            // 修改Token信息

            // 把Token从MemoryCache或Redis中删除

            return true;
        }

        /// <summary>
        /// 停用当前Token
        /// </summary>
        /// <param name="token">Token</param>
        /// <returns></returns>
        public async Task<bool> DeactivateCurrentAsync(HttpContext httpContext) => await DeactivateAsync(GetCurrentAsync(httpContext));

        /// <summary>
        /// 刷新 Token
        /// </summary>
        /// <param name="token">Token</param>
        /// <param name="dto">用户信息数据传输对象</param>
        /// <returns></returns>
        public async Task<AuthorizationObject> RefreshAsync(string token, UserInfoVModel userInfoVModel)
        {
            var jwtOld =await IsActiveAsync(token);  // 判断 Token 是否有效
            if (!jwtOld)
            {
                throw new Exception("未获取到当前用户信息!");
            }

            // 将旧的Token从MemoryCache或Redis中删除


            var jwt = Create(userInfoVModel);

            // 将新的Token存放到MemoryCache或Redis中


            return jwt; 
        }

        /// <summary>
        /// 判断 Token 是否有效
        /// </summary>
        /// <param name="token">Token</param>
        /// <returns></returns>
        public async Task<bool> IsActiveAsync(string token)
        {
            // 检验1-Token是否有效(Token格式正常+未过期)

            // 检验2-MemoryCache或Redis中是否存在(可以防伪造Token)

            return true;
        }

        /// <summary>
        /// 判断当前 Token 是否有效
        /// </summary>
        /// <returns></returns>
        public async Task<bool> IsActiveCurrentAsync(HttpContext httpContext)=> await IsActiveAsync(GetCurrentAsync(httpContext));

        #region private方法
        /// <summary>
        /// 获取 HTTP 请求的 Token 值
        /// </summary>
        /// <returns></returns>
        private string GetCurrentAsync(HttpContext httpContext)
        {
            //http header
            var authorizationHeader = httpContext.Request.Headers["authorization"];

            //token
            return authorizationHeader == StringValues.Empty? string.Empty: authorizationHeader.Single().Split(" ").Last();  // bearer tokenvalue
        }
        #endregion private方法
    }
}
posted @   ꧁执笔小白꧂  阅读(90)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
历史上的今天:
2021-06-08 JS 倒计时弹窗
点击右上角即可分享
微信分享提示