net6 项目搭建及引用框架记录(log4net,autofac,exception,api result,jwt,efcore)六添加身份验证,引入JWT

Posted 圆滚滚的胖狸

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了net6 项目搭建及引用框架记录(log4net,autofac,exception,api result,jwt,efcore)六添加身份验证,引入JWT相关的知识,希望对你有一定的参考价值。

首先添加Nuget包

1.在CommonCode项目中建立 JWTHelper

IJwtModel.cs

namespace CommonCode.JWT //注意命名空间和文件夹名不一致

    internal class IJwtModel
    
        public string Issuer  get; set; 
        public string Audience  get; set; 
        public double Expires  get; set; 
    

 JwtModel.cs

namespace CommonCode.JWT //注意命名空间和文件夹名不一致

    internal class JwtModel: IJwtModel
    
        public string Issuer  get; set; 
        public string Audience  get; set; 
        public double Expires  get; set; 
    

JwtHelper.cs

using CommonCode.Converts;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Reflection;
using System.Security.Claims;

namespace CommonCode.JWT

    /// <summary>
    /// 单例
    /// 用于产生Token和验证Token
    /// </summary>
    public class JwtHelper
    
        private readonly static JwtSecurityTokenHandler _jwtSecurityTokenHandler = new JwtSecurityTokenHandler();

        /// <summary>
        /// 创建加密JwtToken
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        public static string CreateJwtToken<T, U>(in T user,in U jwt, SymmetricSecurityKey secretKey)
        
            IJwtModel jwtModel = ConvertTo.ConvertModel<U,JwtModel>(jwt);
            var claimList = CreateClaimList<T>(user);


            //  选择加密算法
            var algorithm = SecurityAlgorithms.HmacSha256;

            // 生成Credentials
            var signingCredentials = new SigningCredentials(secretKey, algorithm);
            JwtSecurityToken jwtSecurityToken = new JwtSecurityToken(
               jwtModel.Issuer,     //Issuer
               jwtModel.Audience,   //Audience
               claims: claimList,
               DateTime.Now,                    //notBefore
               DateTime.Now.AddDays(jwtModel.Expires),   //expires
               signingCredentials               //Credentials
               );
            string jwtToken = _jwtSecurityTokenHandler.WriteToken(jwtSecurityToken);
            return jwtToken;
        

        public static T GetToken<T>(string Token)
        
            Type t = typeof(T);

            object objA = Activator.CreateInstance(t);
            var b = _jwtSecurityTokenHandler.ReadJwtToken(Token);
            foreach (var item in b.Claims)
            
                PropertyInfo _Property = t.GetProperty(item.Type);
                if (_Property != null && _Property.CanRead)
                
                    _Property.SetValue(objA, item.Value, null);
                

            
            return (T)objA;
        


        /// <summary>
        /// 创建包含用户信息的CalimList
        /// </summary>
        /// <param name="authUser"></param>
        /// <returns></returns>
        private static List<Claim> CreateClaimList<T>(T authUser)
        
            var Class = typeof(T);
            List<Claim> claimList = new List<Claim>();
            foreach (var item in Class.GetProperties())
            
                claimList.Add(new Claim(item.Name, Convert.ToString(item.GetValue(authUser))));
            
            return claimList;
        


    

这里用到了一个类转换的工具,需要建立一下

 

 ConverTo.cs

using System.Reflection;

namespace CommonCode.Converts

    public class ConvertTo
    
        /// <summary>
        /// 实体类转换,要求两个类中的成员一致        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="P"></typeparam>
        /// <param name="pModel"></param>
        /// <returns></returns>
        public static T ConvertModel<P,T>(in P pModel)
        
            T ret = System.Activator.CreateInstance<T>();

            List<PropertyInfo> p_pis = pModel.GetType().GetProperties().ToList();
            PropertyInfo[] t_pis = typeof(T).GetProperties();

            foreach (PropertyInfo pi in t_pis)
            
                //可写入数据
                if (pi.CanWrite)
                
                    //忽略大小写
                    var name = p_pis.Find(s => s.Name.ToLower() == pi.Name.ToLower());
                    if (name != null && pi.PropertyType.Name == name.PropertyType.Name)
                    
                        pi.SetValue(ret, name.GetValue(pModel, null), null);
                    

                
            

            return ret;
        
    

2。然后在Utility项目中建立TokenHelper

在编写TokenHelper之前 ,我们需要在IRepository和Repository中建立 TokenModel,以实现依赖注入

创建ITokenModel

 ITokenModel.cs

namespace NET6Demo.IRepository //注意命名空间,不带文件夹名称

    public interface ITokenModel
    
        string Issuer  get; set; 
        string Audience  get; set; 
        double Expires  get; set; 
    

创建TokenModel

 TokenModel.cs

namespace NET6Demo.Repository

    public class TokenModel : ITokenModel, IDependency
    
        public string Issuer  get; set; 
        public string Audience  get; set; 
        public double Expires  get; set; 
    

创建TokenHelper

 TokenHelper.cs

using NET6Demo.IRepository;
using CommonCode.JWT;
using System.IdentityModel.Tokens.Jwt;
using System.Text;

namespace NET6Demo.Utility.Token

    public class TokenHelper
    
        private readonly IConfiguration _configuration;
        private readonly JwtSecurityTokenHandler _jwtSecurityTokenHandler;
        private readonly ILogger<TokenHelper> _logger;
        private ITokenModel _tokenModel;
        private IUserInfo _user;


        public TokenHelper(
            IConfiguration configuration,
            JwtSecurityTokenHandler jwtSecurityTokenHandler,
            ILogger<TokenHelper> logger,
            ITokenModel tokenModel

            IUserInfo user
            )
        
            _configuration = configuration;
            _jwtSecurityTokenHandler = jwtSecurityTokenHandler;
            _logger = logger;
            _tokenModel = tokenModel;

            _user = user;
        
        // <summary>
        /// 创建加密JwtToken
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        public string CreateJwtToken()
        
            //_user = user;
            // 从 appsettings.json 中读取配置
            var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JWT:SecretKey"]));

            _tokenModel.Expires = Convert.ToDouble(_configuration["JWT:Expires"]);
            _tokenModel.Issuer = _configuration["JWT:Issuer"];
            _tokenModel.Audience = _configuration["JWT:Audience"];

            return JwtHelper.CreateJwtToken(_user, _tokenModel, secretKey);
        


        public IUserInfo GetToken(string Token)
        
            return JwtHelper.GetToken<IUserInfo>(Token);
        

        public bool VerTokenAsync(string Token)
        
            //业务逻辑暂时没有写
            return true;
        
    

在Utility项目中的Autofac中,添加对TokenHelper的注册

 之前代码里其实已经有了这一句,只要去掉注释就好啦

// 用于Jwt的各种操作            
container.RegisterType<JwtSecurityTokenHandler>().InstancePerLifetimeScope();


//自己写的支持泛型存入Jwt 便于扩展
container.RegisterType<TokenHelper>().InstancePerLifetimeScope();

在appsetting.json中添加jwt的参数

"JWT": 
    "Issuer": "com.xxx.authService",
    "Audience": "oauth/com.xxx.authService",
    "SecretKey": "neAuTkkQv1xgXVyr",
    "Expires": "3"
  

3.开启Authorization

在Utility项目中创建Net6DemoAuthorizationMiddleware.

注意:这里需要给项目添加一个Nuget包,这个包不知道为什么自己认不上,需要手动安装

Net6DemoAuthorizationMiddleware.cs 

 

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Policy;
using Microsoft.AspNetCore.Http;

namespace NET6Demo.Utility.Authorize

    public class Net6DemoAuthorizationMiddleware : IAuthorizationMiddlewareResultHandler
    
        private readonly AuthorizationMiddlewareResultHandler defaultHandler = new();
        public async Task HandleAsync(
            RequestDelegate next,
            HttpContext context,
            AuthorizationPolicy policy,
            PolicyAuthorizationResult authorizeResult)
        
            
            if (authorizeResult.Forbidden
                && authorizeResult.AuthorizationFailure!.FailedRequirements
                    .OfType<Show404Requirement>().Any())
            
                // Return a 404 to make it appear as if the resource doesn't exist.

                throw new KeyNotFoundException();
            
            
            throw new ApplicationException("Invalid token");
        


    
    public class Show404Requirement : IAuthorizationRequirement  

在program.cs中添加

#region 添加身份验证JWT

builder.Services.AddSingleton<
    IAuthorizationMiddlewareResultHandler, Net6DemoAuthorizationMiddleware>();


//添加jwt验证:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>

    options.TokenValidationParameters = new TokenValidationParameters()
    
        ValidateIssuer = true,
        ValidIssuer = builder.Configuration["JWT:Issuer"],
        ValidateAudience = true,
        ValidAudience = builder.Configuration["JWT:Audience"],
        ValidateLifetime = true,
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["JWT:SecretKey"]))
    ;
);
#endregion
#region 启用身份验证
//下面的app添加这个  和这个长得很像  app.UseAuthorization();
app.UseAuthentication();//在前
app.UseAuthorization();//在后
#endregion

现在修改TestController,添加JwtSecurityTokenHandler,TokenHelper的依赖注入

public class TestController : BaseController
    
        private ILogger<TestController> _logger;
        private readonly IServiceProvider _provider;        
        private IUserInfo _user;
        private JwtSecurityTokenHandler _jwtHandler;
        private TokenHelper _tokenHelper;

        public TestController(
            ILogger<TestController> logger,
            IServiceProvider provider,
            IUserInfo user,
            JwtSecurityTokenHandler jwtSecurityTokenHandler,
            TokenHelper tokenHelper)
        
            _logger = logger;
            _provider = provider;
            _user = user;
            _jwtHandler = jwtSecurityTokenHandler;
            _tokenHelper = tokenHelper;
        

        [AllowAnonymous]
        [HttpGet("GetTest")]
        public async Task<IActionResult> GetTestResult(string userId)
        
            Console.WriteLine("测试一下输出日志");
            _logger.LogInformation("日志输出了");
            _user = _provider.GetService<IUsers>().GetUser(userId);
            //throw new Exception("Test exception");
            //return Ok(_user);
            //return BadRequest();
            return Ok(_tokenHelper.CreateJwtToken(_user)); 

        

    

运行项目,在swagger中得到结果

 可以拿到JWT的官网去检验一下

 

至于解析和检验的方法,按照API中写就可以了。就不再多说

至此JWT和身份验证搭建完毕

以上是关于net6 项目搭建及引用框架记录(log4net,autofac,exception,api result,jwt,efcore)六添加身份验证,引入JWT的主要内容,如果未能解决你的问题,请参考以下文章

net6 项目搭建及引用框架记录(log4net,autofac,exception,api result,jwt,efcore)二配置log4net

net6 项目搭建及引用框架记录(log4net,autofac,exception,api result,jwt,efcore)六添加身份验证,引入JWT

net6 项目搭建及引用框架记录(log4net,autofac,exception,api result,jwt,efcore)六添加身份验证,引入JWT

net6 项目搭建及引用框架记录(log4net,autofac,exception,api result,jwt,efcore)六添加身份验证,引入JWT

net6 项目搭建及引用框架记录(log4net,autofac,exception,api result,jwt,efcore)一建立项目,使用Swagger

net6 项目搭建及引用框架记录(log4net,autofac,exception,api result,jwt,efcore)一建立项目,使用Swagger