From 4472e4aa6f2e85d31197a1743fde81bef73eb0fc Mon Sep 17 00:00:00 2001 From: chenchun Date: Thu, 7 Apr 2022 17:57:08 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84jwt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Yi.Framework.ApiMicroservice/key.pem | 28 ++++++++ .../Yi.Framework.ApiMicroservice/public.pem | 9 +++ .../Helper/RSAFileHelper.cs | 34 ++++++++++ .../IOCOptions/JWTTokenOptions.cs | 2 +- .../Yi.Framework.Core/JwtInvoker.cs | 65 +++++++++++++++++++ .../Yi.Framework.Core/MakeJwt.cs | 63 ------------------ .../MiddlewareExtend/JwtExtension.cs | 32 +++++---- 7 files changed, 155 insertions(+), 78 deletions(-) create mode 100644 Yi.Framework.Net6/Yi.Framework.ApiMicroservice/key.pem create mode 100644 Yi.Framework.Net6/Yi.Framework.ApiMicroservice/public.pem create mode 100644 Yi.Framework.Net6/Yi.Framework.Common/Helper/RSAFileHelper.cs create mode 100644 Yi.Framework.Net6/Yi.Framework.Core/JwtInvoker.cs delete mode 100644 Yi.Framework.Net6/Yi.Framework.Core/MakeJwt.cs diff --git a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/key.pem b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/key.pem new file mode 100644 index 00000000..3314ab6e --- /dev/null +++ b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC7VJTUt9Us8cKj +MzEfYyjiWA4R4/M2bS1GB4t7NXp98C3SC6dVMvDuictGeurT8jNbvJZHtCSuYEvu +NMoSfm76oqFvAp8Gy0iz5sxjZmSnXyCdPEovGhLa0VzMaQ8s+CLOyS56YyCFGeJZ +qgtzJ6GR3eqoYSW9b9UMvkBpZODSctWSNGj3P7jRFDO5VoTwCQAWbFnOjDfH5Ulg +p2PKSQnSJP3AJLQNFNe7br1XbrhV//eO+t51mIpGSDCUv3E0DDFcWDTH9cXDTTlR +ZVEiR2BwpZOOkE/Z0/BVnhZYL71oZV34bKfWjQIt6V/isSMahdsAASACp4ZTGtwi +VuNd9tybAgMBAAECggEBAKTmjaS6tkK8BlPXClTQ2vpz/N6uxDeS35mXpqasqskV +laAidgg/sWqpjXDbXr93otIMLlWsM+X0CqMDgSXKejLS2jx4GDjI1ZTXg++0AMJ8 +sJ74pWzVDOfmCEQ/7wXs3+cbnXhKriO8Z036q92Qc1+N87SI38nkGa0ABH9CN83H +mQqt4fB7UdHzuIRe/me2PGhIq5ZBzj6h3BpoPGzEP+x3l9YmK8t/1cN0pqI+dQwY +dgfGjackLu/2qH80MCF7IyQaseZUOJyKrCLtSD/Iixv/hzDEUPfOCjFDgTpzf3cw +ta8+oE4wHCo1iI1/4TlPkwmXx4qSXtmw4aQPz7IDQvECgYEA8KNThCO2gsC2I9PQ +DM/8Cw0O983WCDY+oi+7JPiNAJwv5DYBqEZB1QYdj06YD16XlC/HAZMsMku1na2T +N0driwenQQWzoev3g2S7gRDoS/FCJSI3jJ+kjgtaA7Qmzlgk1TxODN+G1H91HW7t +0l7VnL27IWyYo2qRRK3jzxqUiPUCgYEAx0oQs2reBQGMVZnApD1jeq7n4MvNLcPv +t8b/eU9iUv6Y4Mj0Suo/AU8lYZXm8ubbqAlwz2VSVunD2tOplHyMUrtCtObAfVDU +AhCndKaA9gApgfb3xw1IKbuQ1u4IF1FJl3VtumfQn//LiH1B3rXhcdyo3/vIttEk +48RakUKClU8CgYEAzV7W3COOlDDcQd935DdtKBFRAPRPAlspQUnzMi5eSHMD/ISL +DY5IiQHbIH83D4bvXq0X7qQoSBSNP7Dvv3HYuqMhf0DaegrlBuJllFVVq9qPVRnK +xt1Il2HgxOBvbhOT+9in1BzA+YJ99UzC85O0Qz06A+CmtHEy4aZ2kj5hHjECgYEA +mNS4+A8Fkss8Js1RieK2LniBxMgmYml3pfVLKGnzmng7H2+cwPLhPIzIuwytXywh +2bzbsYEfYx3EoEVgMEpPhoarQnYPukrJO4gwE2o5Te6T5mJSZGlQJQj9q4ZB2Dfz +et6INsK0oG8XVGXSpQvQh3RUYekCZQkBBFcpqWpbIEsCgYAnM3DQf3FJoSnXaMhr +VBIovic5l0xFkEHskAjFTevO86Fsz1C2aSeRKSqGFoOQ0tmJzBEs1R6KqnHInicD +TQrKhArgLXX4v3CddjfTRJkFWDbE/CkvKZNOrcf1nhaGCPspRJj2KUkj1Fhl9Cnc +dn/RsYEONbwQSjIfMPkvxF+8HQ== +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/public.pem b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/public.pem new file mode 100644 index 00000000..1c9b622d --- /dev/null +++ b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/public.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo +4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u ++qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyeh +kd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ +0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdg +cKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbc +mwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/Yi.Framework.Net6/Yi.Framework.Common/Helper/RSAFileHelper.cs b/Yi.Framework.Net6/Yi.Framework.Common/Helper/RSAFileHelper.cs new file mode 100644 index 00000000..62c4d028 --- /dev/null +++ b/Yi.Framework.Net6/Yi.Framework.Common/Helper/RSAFileHelper.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Common.Helper +{ + public class RSAFileHelper + { + public static RSA GetKey() + { + return GetRSA("key.pem"); + } + public static RSA GetPublicKey() + { + return GetRSA("public.pem"); + } + + private static RSA GetRSA(string fileName) + { + string rootPath = Directory.GetCurrentDirectory(); + string filePath = Path.Combine(rootPath, fileName); + if (!System.IO.File.Exists(filePath)) + throw new Exception("文件不存在"); + string key = System.IO.File.ReadAllText(filePath); + var rsa = RSA.Create(); + rsa.ImportFromPem(key.AsSpan()); + return rsa; + } + } +} diff --git a/Yi.Framework.Net6/Yi.Framework.Common/IOCOptions/JWTTokenOptions.cs b/Yi.Framework.Net6/Yi.Framework.Common/IOCOptions/JWTTokenOptions.cs index 9403d337..8c4601c4 100644 --- a/Yi.Framework.Net6/Yi.Framework.Common/IOCOptions/JWTTokenOptions.cs +++ b/Yi.Framework.Net6/Yi.Framework.Common/IOCOptions/JWTTokenOptions.cs @@ -10,7 +10,7 @@ namespace Yi.Framework.Common.IOCOptions public string Audience { get; set; } public string Issuer { get; set; } - + public string SecurityKey { get; set; } public string DefaultScheme { get; set; } diff --git a/Yi.Framework.Net6/Yi.Framework.Core/JwtInvoker.cs b/Yi.Framework.Net6/Yi.Framework.Core/JwtInvoker.cs new file mode 100644 index 00000000..3e71a3af --- /dev/null +++ b/Yi.Framework.Net6/Yi.Framework.Core/JwtInvoker.cs @@ -0,0 +1,65 @@ +using Microsoft.Extensions.Options; +using Microsoft.IdentityModel.JsonWebTokens; +using Microsoft.IdentityModel.Tokens; +using System; +using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; +using System.Linq; +using System.Security.Claims; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Common.IOCOptions; +using Yi.Framework.Model.Models; +using JwtRegisteredClaimNames = Microsoft.IdentityModel.JsonWebTokens.JwtRegisteredClaimNames; + +namespace Yi.Framework.Core +{ + public class JwtInvoker + { + private readonly JWTTokenOptions _JWTTokenOptions; + public JwtInvoker(IOptionsMonitor jwtTokenOptions) + { + this._JWTTokenOptions = jwtTokenOptions.CurrentValue; + } + public string GetRefreshToken(UserEntity user) + { + return this.GetToken(_JWTTokenOptions.ReExpiration, user, true); + } + + public string GetAccessToken(UserEntity user) + { + return this.GetToken(_JWTTokenOptions.Expiration, user); + } + + private string GetToken(int minutes, UserEntity user, bool isRefresh = false) + { + List claims = new List(); + claims.Add(new Claim(JwtRegisteredClaimNames.Nbf, $"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}")); + claims.Add(new Claim(JwtRegisteredClaimNames.Exp, $"{new DateTimeOffset(DateTime.Now.AddMinutes(minutes)).ToUnixTimeSeconds()}")); + claims.Add(new Claim(JwtRegisteredClaimNames.Sid, user.Id.ToString())); + //claims.Add(new Claim("TenantId", userRoleMenuEntity.user.TenantId.ToString())); + //claims.Add(new Claim("TenantName", userRoleMenuEntity.tenant.TenantName.ToString())); + //claims.Add(new Claim("Id", userRoleMenuEntity.user.Id.ToString())); + //claims.Add(new Claim("Name", userRoleMenuEntity.user.Name)); + //claims.Add(new Claim("TenantLevel", userRoleMenuEntity.tenant.TenantLevel.ToString())); + + if (isRefresh) + { + claims.Add(new Claim("Re", "true")); + } + + var creds = new SigningCredentials(new RsaSecurityKey(Common.Helper.RSAFileHelper.GetKey()), SecurityAlgorithms.RsaSha256); + var token = new JwtSecurityToken( + issuer: _JWTTokenOptions.Issuer, + audience: _JWTTokenOptions.Audience, + claims: claims, + expires: DateTime.Now.AddMinutes(minutes), + signingCredentials: creds); + var tokenData = new JwtSecurityTokenHandler().WriteToken(token); + + return tokenData; + + } + + } +} diff --git a/Yi.Framework.Net6/Yi.Framework.Core/MakeJwt.cs b/Yi.Framework.Net6/Yi.Framework.Core/MakeJwt.cs deleted file mode 100644 index 0fc12b33..00000000 --- a/Yi.Framework.Net6/Yi.Framework.Core/MakeJwt.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Microsoft.IdentityModel.JsonWebTokens; -using Microsoft.IdentityModel.Tokens; -using System; -using System.Collections.Generic; -using System.IdentityModel.Tokens.Jwt; -using System.Linq; -using System.Security.Claims; -using System.Text; -using System.Threading.Tasks; -using Yi.Framework.Common.Const; -using Yi.Framework.Model.Models; -using JwtRegisteredClaimNames = Microsoft.IdentityModel.JsonWebTokens.JwtRegisteredClaimNames; - -namespace Yi.Framework.Core -{ - - public class JwtUser - { - public UserEntity user { get; set; } - - } - - public class MakeJwt - { - - /// - /// user需关联所有roles,还有一个menuIds - /// - /// - /// - public static string app(JwtUser _user) - { - //通过查询权限,把所有权限加入进令牌中 - List claims = new List(); - claims.Add(new Claim(JwtRegisteredClaimNames.Nbf, $"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}")); - claims.Add(new Claim(JwtRegisteredClaimNames.Exp, $"{new DateTimeOffset(DateTime.Now.AddMinutes(30)).ToUnixTimeSeconds()}")); - claims.Add(new Claim(ClaimTypes.Name, _user.user.Name)); - claims.Add(new Claim(ClaimTypes.Sid, _user.user.Id.ToString())); - //现在不存放在jwt中,而存放在redis中 - //foreach (var k in _user?.menuIds) - //{ - // claims.Add(new Claim("menuIds",k.id.ToString())); - //} - //foreach (var k in _user.user.roles) - //{ - // claims.Add(new Claim(ClaimTypes.Role, k.role_name)); - //} - var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JwtConst.SecurityKey)); - var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); - - var token = new JwtSecurityToken( - issuer: JwtConst.Domain, - audience: JwtConst.Domain, - claims: claims, - expires: DateTime.Now.AddMinutes(30), - signingCredentials: creds); - var tokenData = new JwtSecurityTokenHandler().WriteToken(token); - - return tokenData; - } - - } -} diff --git a/Yi.Framework.Net6/Yi.Framework.WebCore/MiddlewareExtend/JwtExtension.cs b/Yi.Framework.Net6/Yi.Framework.WebCore/MiddlewareExtend/JwtExtension.cs index eb8b04a4..08e2fb92 100644 --- a/Yi.Framework.Net6/Yi.Framework.WebCore/MiddlewareExtend/JwtExtension.cs +++ b/Yi.Framework.Net6/Yi.Framework.WebCore/MiddlewareExtend/JwtExtension.cs @@ -6,6 +6,8 @@ using System; using System.IO; using System.Text; using Yi.Framework.Common.Const; +using Yi.Framework.Common.Helper; +using Yi.Framework.Common.IOCOptions; namespace Yi.Framework.WebCore.MiddlewareExtend { @@ -16,23 +18,25 @@ namespace Yi.Framework.WebCore.MiddlewareExtend { public static IServiceCollection AddJwtService(this IServiceCollection services) { + services.Configure(Appsettings.appConfiguration("JwtAuthorize")); + + var jwtOptions = Appsettings.app("JwtAuthorize"); services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) - .AddJwtBearer(options => - { - options.TokenValidationParameters = new TokenValidationParameters - { - ValidateIssuer = true,//是否验证Issuer - ValidateAudience = true,//是否验证Audience - ValidateLifetime = true,//是否验证失效时间 - ClockSkew = TimeSpan.FromDays(1), + .AddJwtBearer(options => + { + options.TokenValidationParameters = new TokenValidationParameters + { + ValidateIssuer = true,//是否验证Issuer + ValidateAudience = true,//是否验证Audience + ValidateLifetime = true,//是否验证失效时间 - ValidateIssuerSigningKey = true,//是否验证SecurityKey - ValidAudience = JwtConst.Domain,//Audience - ValidIssuer = JwtConst.Domain,//Issuer,这两项和前面签发jwt的设置一致 - IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JwtConst.SecurityKey))//拿到SecurityKey - }; - }); + ValidateIssuerSigningKey = true,//是否验证SecurityKey + ValidAudience = jwtOptions.Audience,//Audience + ValidIssuer = jwtOptions.Issuer,//Issuer,这两项和前面签发jwt的设置一致 + IssuerSigningKey = new RsaSecurityKey(RSAFileHelper.GetPublicKey()) + }; + }); return services; } }