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和身份验证搭建完毕

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值