using Microsoft.Extensions.Options; 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 Ropin.Inspection.Model; using Ropin.Inspection.Model.ViewModel; namespace Ropin.Inspection.Api.Common.Token { public enum TokenType { AccessToken = 1, RefreshToken = 2 } public class TokenHelper : ITokenHelper { private readonly IOptions _options; public TokenHelper(IOptions options) { _options = options; } public Token CreateAccessToken(TsysUserDetailViewModel user) { Claim[] claims = { new Claim(ClaimTypes.NameIdentifier, user.C_UserID.ToString()), new Claim(ClaimTypes.Name, user.C_Name), new Claim(ClaimTypes.Role, user.RoleIds) ,new Claim(ClaimTypes.PrimaryGroupSid, user.C_OrgCode.ToString()) }; return CreateToken(claims, TokenType.AccessToken); } public ComplexToken CreateToken(TsysUserDetailViewModel user) { Claim[] claims = { new Claim(ClaimTypes.NameIdentifier, user.C_UserID.ToString()), new Claim(ClaimTypes.Name, user.C_Name), new Claim(ClaimTypes.Role, user.RoleNames??""), new Claim(ClaimTypes.Rsa, user.C_LicenseCode), new Claim(ClaimTypes.Sid, user.LicenseTypeCode), new Claim(ClaimTypes.Actor, user.OrgTypeCode), new Claim(ClaimTypes.PrimaryGroupSid, user.C_OrgCode.ToString())}; return new ComplexToken { AccessToken = CreateToken(claims, TokenType.AccessToken), RefreshToken = CreateToken(claims, TokenType.RefreshToken), User = user }; } /// /// 用于创建AccessToken和RefreshToken。 /// 这里AccessToken和RefreshToken只是过期时间不同 /// 因为RefreshToken只是用于刷新AccessToken,其内容可以简单一些。 /// 而AccessToken可能会附加一些其他的Claim。 /// /// /// /// private Token CreateToken(Claim[] claims, TokenType tokenType) { claims = claims.Append(new Claim("TokenType", tokenType.ToString())).ToArray(); var now = DateTime.Now; var expires = now.Add(TimeSpan.FromMinutes(tokenType.Equals(TokenType.AccessToken) ? _options.Value.AccessTokenExpiresMinutes : _options.Value.RefreshTokenExpiresMinutes)); var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_options.Value.IssuerSigningKey)); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var token = new JwtSecurityToken( issuer: _options.Value.Issuer, audience: _options.Value.Audience, claims: claims, notBefore: now, expires: expires, //签名证书 signingCredentials: creds); //signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_options.Value.IssuerSigningKey)), SecurityAlgorithms.HmacSha256)); return new Token { TokenContent = new JwtSecurityTokenHandler().WriteToken(token), Expires = expires }; } public ComplexToken RefreshTokenByClaimsPrincipal(ClaimsPrincipal claimsPrincipal) { if (claimsPrincipal!=null) { //claimsPrincipal.Claims.Any(m => m.Type.Equals("TokenType") && m.Value.Equals(TokenType.RefreshToken.ToString())) if (claimsPrincipal.Claims.Any(m => m.Type == ("TokenType") && m.Value == (TokenType.RefreshToken.ToString()))) { var code = claimsPrincipal.Claims.FirstOrDefault(m => m.Type.Equals(ClaimTypes.NameIdentifier)); var name = claimsPrincipal.Claims.FirstOrDefault(m => m.Type.Equals(ClaimTypes.Name)); var RoleNames = claimsPrincipal.Claims.FirstOrDefault(m => m.Type.Equals(ClaimTypes.Role)); var License = claimsPrincipal.Claims.FirstOrDefault(m => m.Type.Equals(ClaimTypes.Rsa)); var LicenseTypeCode = claimsPrincipal.Claims.FirstOrDefault(m => m.Type.Equals(ClaimTypes.Sid)); var OrgTypeCode = claimsPrincipal.Claims.FirstOrDefault(m => m.Type.Equals(ClaimTypes.Actor)); var PrimaryGroupSid = claimsPrincipal.Claims.FirstOrDefault(m => m.Type.Equals(ClaimTypes.PrimaryGroupSid)); if (null != code) { //return CreateAccessToken(new TsysUserDetailViewModel { C_UserID = Guid.Parse(code.Value) , C_Name = name.Value ,RoleNames = RoleNames.Value}); return CreateToken(new TsysUserDetailViewModel { C_UserID = Guid.Parse(code.Value), C_Name = name.Value, RoleNames = RoleNames.Value, C_OrgCode = Guid.Parse(PrimaryGroupSid.Value), C_LicenseCode = License.Value, LicenseTypeCode = LicenseTypeCode.Value, OrgTypeCode = OrgTypeCode.Value }); } } } return null; } public ComplexToken RefreshToken(string refreshToken) { ClaimsPrincipal claimsPrincipal = GetClaimsPrincipalByToken(refreshToken); return RefreshTokenByClaimsPrincipal(claimsPrincipal); } private ClaimsPrincipal GetClaimsPrincipalByToken(string token) { try { var tokenValidationParameters = new TokenValidationParameters { ValidateIssuer = false, ValidateAudience = false, ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_options.Value.IssuerSigningKey)), ClockSkew = TimeSpan.Zero, ValidateLifetime = false // 不验证过期时间!!! }; var jwtTokenHandler = new JwtSecurityTokenHandler(); var claimsPrincipal = jwtTokenHandler.ValidateToken(token, tokenValidationParameters, out var validatedToken); var validatedSecurityAlgorithm = validatedToken is JwtSecurityToken jwtSecurityToken && jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase); return validatedSecurityAlgorithm ? claimsPrincipal : null; } catch { return null; } } public Token RefreshToken(ClaimsPrincipal claimsPrincipal) { if (claimsPrincipal.Claims.Any(m => m.Type.Equals("TokenType") && m.Value.Equals(TokenType.RefreshToken.ToString()))) { var code = claimsPrincipal.Claims.FirstOrDefault(m => m.Type.Equals(ClaimTypes.NameIdentifier)); var name = claimsPrincipal.Claims.FirstOrDefault(m => m.Type.Equals(ClaimTypes.Name)); var RoleNames = claimsPrincipal.Claims.FirstOrDefault(m => m.Type.Equals(ClaimTypes.Role)); var PrimaryGroupSid = claimsPrincipal.Claims.FirstOrDefault(m => m.Type.Equals(ClaimTypes.PrimaryGroupSid)); var LicenseCode = claimsPrincipal.Claims.FirstOrDefault(m => m.Type.Equals(ClaimTypes.Rsa)); var LicenseTypeCode = claimsPrincipal.Claims.FirstOrDefault(m => m.Type.Equals(ClaimTypes.Sid)); var OrgTypeCode = claimsPrincipal.Claims.FirstOrDefault(m => m.Type.Equals(ClaimTypes.Actor)); if (null != code) { return CreateAccessToken(new TsysUserDetailViewModel { C_UserID = Guid.Parse(code.Value) ,C_LicenseCode = LicenseCode.Value, LicenseTypeCode = LicenseTypeCode.Value, C_Name = name.Value ,RoleNames = RoleNames.Value, C_OrgCode = Guid.Parse(PrimaryGroupSid.Value),OrgTypeCode = OrgTypeCode.Value }); } } return null; } } }