net6 项目搭建及引用框架记录(log4net,autofac,exception,api result,jwt,efcore)八、使用pfx证书RSA方式生成jwt签名的Token,公钥验证签名

关于JWT引用的补充

因为Ids5收费的缘故,因此原本打算引用ids的想法被放弃了。只能自己来实现了

生产环境下,肯定需要用证书来产生Token,所以我们先生成证书

本机安装openssl,然后打开openssl带的控制台,

 在openssl 控制台中顺序执行以下命令

具体命令的含义请自行百度

// 进入到准备好的证书文件夹
cd F:\NET6Demo_WebApi\NET6Demo_WebApi\Certificate
// 生成私钥key文件
openssl genrsa -out xxx_rsa_aes_private.key 2048
// 生成公钥key文件
openssl rsa -in xxx_rsa_aes_private.key  -pubout -out xxx_rsa_public.key
// 生成crt文件
openssl req -new -x509 -days 3650 -key xxx_rsa_aes_private.key -out xxx_cert.crt
// 生成pfx文件 需要设置证书密码
openssl pkcs12 -export -in xxx_cert.crt -inkey xxx_rsa_aes_private.key -out xxx.pfx
// 生成cer文件
openssl pkcs12 -nodes -nokeys -in xxx.pfx -passin pass:证书密码 -nokeys -out xxx.cer

 回到vs2022 项目中来,可以看到添加后的证书文件

 记得要设置文件属性

然后,修改appsetting.json文件,添加"Certificates",修改:"JWT"  

 

"Certificates": {
     "CertPath": "Certificate\\xxx.pfx",
    "Password": "CdPX05TW8rNiq2IE",
    "PublicCert": "Certificate\\xxx.cer"
  },
  
  "JWT": {
    "Issuer": "com.xxx.authService",
    "Audience": "oauth/com.xxx.authService",    
    "Expires": "7200"
  },

接下来我们对jwt部分进行改造

修改JwtHelper.cs的CreateJwtToken方法

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

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, string certPath, string certPassword) //修改了此方法
        {
            IJwtModel jwtModel = ConvertTo.ConvertModel<U, JwtModel>(jwt);
            var claimList = CreateClaimList<T>(user);


            // 这一句会产生500错误
            //var algorithm = signingKey.PrivateKey.SignatureAlgorithm;
            // 选择加密算法
            var algorithm = SecurityAlgorithms.RsaSha256;

            // 加载pfx证书
            X509Certificate2 authCert = new X509Certificate2(certPath, certPassword);
            X509SecurityKey signingKey = new X509SecurityKey(authCert);
            // 生成Credentials
            //var signingCredentials = new SigningCredentials(signingKey, "RS256");
            var signingCredentials = new SigningCredentials(signingKey, algorithm);
            JwtSecurityToken jwtSecurityToken = new JwtSecurityToken(
               jwtModel.Issuer,     //Issuer
               jwtModel.Audience,   //Audience
               claims: claimList,
               DateTime.Now,                    //notBefore
               DateTime.Now.AddSeconds(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;
        }


    }
}

修改Tokenhelper.cs

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using NET6Demo.IRepository;
using CommonCode.JWT;
using System.IdentityModel.Tokens.Jwt;
using System.Text;
using CommonCode.Helper;

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;
        }

        private static string basePath = AppContext.BaseDirectory; //添加
        // <summary>
        /// 创建加密JwtToken
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        public string CreateJwtToken(IUserInfo user) //修改
        {
            // 从 appsettings.json 中读取配置,采取pfx证书
            //var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JWT:SecretKey"]));
            var certPath = Path.Combine(basePath, AppsettingHelper.Get("Certificates:CertPath"));
            var certPassowrd = AppsettingHelper.Get("Certificates:Password");
            _tokenModel.Issuer = AppsettingHelper.Get("JWT:Issuer");
            _tokenModel.Audience = AppsettingHelper.Get("JWT:Audience");


            //需要从数据库中读取
            _tokenModel.Expires = Convert.ToDouble(_configuration["JWT:Expires"]);


            return JwtHelper.CreateJwtToken(_user, _tokenModel, certPath, certPassowrd);
        }


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

        public bool VerTokenAsync(string Token)
        {
            return true;
        }
    }
}

修改program.cs 中关于jwt的部分

#region 添加身份验证JWT

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


//添加jwt验证:
var publicCert = new X509Certificate2(Path.Combine(basePath, builder.Configuration["Certificates:PublicCert"]));
var publicKey = new X509SecurityKey(publicCert);

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 = publicKey,
    };
});
#endregion

修改一下Net6DemoAuthorizationMiddleware

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.Succeeded) //添加成功判断
            {
                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 { }
}

在controller修改GetTestResult,添加TestToken

[AllowAnonymous]
        [HttpGet("GetTest")]
        public async Task<IActionResult> GetTestResult(string userId)
        {
            Console.WriteLine("测试一下输出日志");
            _logger.LogInformation("日志输出了");
            _user = _provider.GetService<IUsers>().GetUser(userId);            

            return Ok(_tokenHelper.CreateJwtToken(_user));
            


        }
        [Authorize]
        [HttpGet("TestToken")]
        public async Task<IActionResult> TestToken()
        {
            Console.WriteLine("输出日志 TestToken");
            _logger.LogInformation("TestToken");
            return Ok();
        }

另外,这次对AppsettingHelper文件有了小小的修改

using Microsoft.Extensions.Configuration;

namespace CommonCode.Helper
{
    public class AppsettingHelper
    {
        //private static IConfiguration _config;
        //private static string _basePath;


        //public AppsettingHelper(IConfiguration config)
        //{
        //    _config = config;
        //    _basePath = AppContext.BaseDirectory;
        //}


        public static string? Get(string key)
        {

            var config = getConfigContainer();

            return config[key];
        }

        /// <summary>
        /// 读取实体信息
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="session"></param>
        /// <returns></returns>
        public static List<T> Get<T>(params string[] session)
        {
            List<T> list = new List<T>();
            var config = getConfigContainer();
            config.Bind(string.Join(":", session), list);
            return list;
        }

        private static IConfiguration getConfigContainer()
        {
            var basePath = AppContext.BaseDirectory;

            //引用Microsoft.Extensions.Configuration;
            var Configuration = new ConfigurationBuilder()
            .SetBasePath(basePath)
            .AddJsonFile("appsettings.json")
            .AddJsonFile("appsettings.test.json", true, reloadOnChange: true);

            var config = Configuration.Build();
            return config;
        }
    }
}
//要记得注销掉program.cs中的相关代码
//builder.Services.AddSingleton(new CommonCode.Helper.AppsettingHelper(config));

运行代码,在swagger中获取到token

 

 

注意:因为我多次运行,所以截图中的Token可能会不一样,不影响程序本身的运行结果

验证在swager进行

 

 

 

在postman中验证

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值