【ASP.NET Core 认证】自定义Jwt token验证(ISecurityTokenValidator)

Core为我们提供了自定义token验证的接口,当我们需要使用自己的方式验证token时可以使用。
比如Jwt只能数据签名,不能加密。当需要校验加密的jwt token。在登录时将jwt token加密后传给客户端,客户端回传token。这时需要我们自定义token校验。

自定义token校验,实现ISecurityTokenValidator接口

    /// <summary>
    /// 自定义token校验
    /// </summary>
    public class MyTokenValidator : ISecurityTokenValidator
    {
        public int MaximumTokenSizeInBytes { get; set; }

        public bool CanReadToken(string securityToken)
        {
            return true;
        }
        public bool CanValidateToken
        {
            get
            {
                return true;
            }
        }

        //验证token
        public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
        {
            string jwtToken = AESCryptoHelper.Decrypt(securityToken);
            ClaimsPrincipal principal = new JwtSecurityTokenHandler().ValidateToken(jwtToken, validationParameters, out validatedToken);
            return principal;
        }
    }

配置文件中添加配置:

  "JwtTokenOptions": {
    "Issuer": "FAN.Issuer",
    "ValidateIssuer": true,
    "Audience": "FAN.Audience",
    "ValidateAudience": true,
    "RawSigningKey": "11111111-1111-1111-1111-111111111111",/*签名秘钥*/
    "ValidateIssuerSigningKey": true,
    "ValidateLifetime": false,
    "RequireExpirationTime": false,
    "JwtExpiresInMinutes": 6000,
    "ValidateIntervaltime": true,
    "IntervalExpiresInMinutes": 3000
  }

Startup.cs添加如下内容:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddScoped<TokenBuilder>();
            services.Configure<JwtTokenOptions>(Configuration.GetSection("JwtTokenOptions"));
            JwtTokenOptions tokenOptions = Configuration.GetSection("JwtTokenOptions").Get<JwtTokenOptions>();

            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                  //开启Bearer服务认证
                  .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
                  {
                      options.SaveToken = true;
                      options.TokenValidationParameters = tokenOptions.ToTokenValidationParams();
                      options.SecurityTokenValidators.Clear();
                      options.SecurityTokenValidators.Add(new MyTokenValidator());
                  });
         }
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseAuthentication();
        }

User:用户信息

    /// <summary>
    /// 登录用户信息
    /// </summary>
    public class User
    {
        public int UserID { get; set; }
        public string Email { get; set; }

        public string Name { get; set; }
        public string Role { get; set; }


        public User(int userID, string name, string email, string role)
        {
            this.UserID = userID;
            this.Name = name;
            this.Email = email;
            this.Role = role;
        }
    }

TokenBuilder:用于创建jwt token

/// <summary>
    /// token创建
    /// </summary>
    public class TokenBuilder
    {
        private JwtTokenOptions _tokenOptions = null;
        public TokenBuilder(IOptions<JwtTokenOptions> tokenOptions)
        {
            this._tokenOptions = tokenOptions.Value;
        }
        /// <summary>
        /// 创建加密JwtToken
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        public string CreateJwtToken(User user)
        {
            var claimList = this.CreateClaimList(user);
            JwtSecurityToken jwtSecurityToken = new JwtSecurityToken(
                issuer: this._tokenOptions.Issuer
                , audience: this._tokenOptions.Audience
                , claims: claimList
                //, notBefore: utcNow
                , expires: DateTime.Now.AddDays(3)
                , signingCredentials: new SigningCredentials(this._tokenOptions.SigningKey, SecurityAlgorithms.HmacSha256)
            );
            string jwtToken = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
            //加密jwtToken
            jwtToken = AESCryptoHelper.Encrypt(jwtToken);
            return jwtToken;
        }

        /// <summary>
        /// 创建包含用户信息的CalimList
        /// </summary>
        /// <param name="authUser"></param>
        /// <returns></returns>
        private List<Claim> CreateClaimList(User authUser)
        {
            //身份单元项项集合
            List<Claim> claimList = new List<Claim>()
                    {
                        new Claim(type: ClaimTypes.Email, value: authUser.Email), //身份单元项
                        new Claim(type: ClaimTypes.Name, value: authUser.Name),
                        new Claim(type: ClaimTypes.NameIdentifier, value: authUser.UserID.ToString()),
                        new Claim(type: ClaimTypes.Role, value: authUser.Role ?? string.Empty)
                    };
            return claimList;
        }
    }

AESCryptoHelper:使用AES对jwttoken的加密解密

    /// <summary>
    /// AES加密解密
    /// </summary>
    public class AESCryptoHelper
    {
        /// <summary>
        /// AES加密解密Key,Key必须十六位
        /// </summary>
        private static readonly string AESKey = "1111111111111111";
        /// <summary>
        ///  AES 加密
        /// </summary>
        /// <param name="plainText"></param>
        /// <returns></returns>
        public static string Encrypt(string plainText)
        {
            return Encrypt(plainText, AESKey);
        }
        /// <summary>
        ///  AES 加密
        /// </summary>
        /// <param name="plainText"></param>
        /// <param name="key">密码必须是16位,否则会报错哈</param>
        /// <returns></returns>
        public static string Encrypt(string plainText, string key)
        {
            string result = null;
            if (string.IsNullOrEmpty(plainText))
            {
                return result;
            }
            byte[] plainTextArray = Encoding.UTF8.GetBytes(plainText);
            using (MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider())
            {
                using (RijndaelManaged rijndaelManaged = new RijndaelManaged
                {
                    Key = provider.ComputeHash(Encoding.UTF8.GetBytes(key)),
                    //Key = Encoding.UTF8.GetBytes(key),
                    Mode = CipherMode.ECB,
                    Padding = PaddingMode.PKCS7
                })
                {
                    using (ICryptoTransform cryptoTransform = rijndaelManaged.CreateEncryptor())
                    {
                        byte[] resultArray = cryptoTransform.TransformFinalBlock(plainTextArray, 0, plainTextArray.Length);
                        result = Convert.ToBase64String(resultArray, 0, resultArray.Length);
                        Array.Clear(resultArray, 0, resultArray.Length);
                        resultArray = null;
                    }
                }
            }
            Array.Clear(plainTextArray, 0, plainTextArray.Length);
            plainTextArray = null;
            return result;
        }
        /// <summary>
        ///  AES 解密
        /// </summary>
        /// <param name="encryptText"></param>
        /// <returns></returns>
        public static string Decrypt(string encryptText)
        {
            return Decrypt(encryptText, AESKey);
        }
        /// <summary>
        ///  AES 解密
        /// </summary>
        /// <param name="encryptText"></param>
        /// <param name="key">密码必须是16位,否则会报错哈</param>
        /// <returns></returns>
        public static string Decrypt(string encryptText, string key)
        {
            string result = null;
            if (string.IsNullOrEmpty(encryptText))
            {
                return result;
            }
            byte[] encryptTextArray = Convert.FromBase64String(encryptText);
            using (MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider())
            {
                using (RijndaelManaged rijndaelManaged = new RijndaelManaged
                {
                    Key = provider.ComputeHash(Encoding.UTF8.GetBytes(key)),
                    //Key = Encoding.UTF8.GetBytes(key),
                    Mode = CipherMode.ECB,
                    Padding = PaddingMode.PKCS7
                })
                {
                    using (ICryptoTransform cryptoTransform = rijndaelManaged.CreateDecryptor())
                    {
                        byte[] resultArray = cryptoTransform.TransformFinalBlock(encryptTextArray, 0, encryptTextArray.Length);
                        result = Encoding.UTF8.GetString(resultArray);
                        Array.Clear(resultArray, 0, resultArray.Length);
                        resultArray = null;
                    }
                }
            }
            Array.Clear(encryptTextArray, 0, encryptTextArray.Length);
            encryptTextArray = null;
            return result;
        }
    }

控制器:

    [Route("api/[controller]/[action]")]
    [ApiController]
    public class ValuesController : ControllerBase
    {
        private TokenBuilder _tokenBuilder = null;
        public ValuesController(TokenBuilder tokenBuilder)
        {
            this._tokenBuilder = tokenBuilder;
        }
        /// <summary>
        /// 登录,生成加密token
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public ActionResult<string> Login()
        {
            //省略登录逻辑。。。。
            var user = new User(1, "fan", "410577910@qq.com", "admin");
            string signToken = this._tokenBuilder.CreateJwtToken(user);
            return signToken;
        }
        /// <summary>
        /// 创建订单,需要校验token
        /// </summary>
        /// <returns></returns>
        [Authorize]
        [HttpPost]
        public ActionResult<string> CreateOrder()
        {
            if (base.User.Identity.IsAuthenticated)
            {
                string userName = base.User.Identity.Name;
            }
            //省略创建订单逻辑。。。
            return "生成订单成功";
        }
    }

测试

登录:(获取token)

http://localhost:5000/api/values/CreateOrder

创建订单:(带上token,才能授权通过)

http://localhost:5000/api/values/CreateOrder POST
Headers添加:
Key: Authorization
Value: Bearer 2FrDOaIT8r9n7axl4ARhe2dp7S7bWS5+eCcErbkeIIzVbutYr+LmMI1HBEWCLwgwS80adJlwDGW9iNtL2Kp4y+twxHmEpPJfhmg8X1uzgYReh6Nd7XcJmQh9zXvma9gfySU8DcEOijD79wellmRqPNh8ZYX7C0DqKx55L8DVgkJ4emOHIyni/V7qs3xqgU6RstCCxOAI4tHS7v67jmtQJks2x88iBntAJWsPwr7jRChvdWXHpsMeOzyZDjEwiT/XZIFHwB6wyUOfGqqkpdj3s36XwaKEvEBJzwSL2LCUEpMJUr7SQ0r4ZJNnPEBsFoiA/s35nbhgt9OU5w4Z+9MUJ2hBW/eTRlhwtcUR48nitE+PyJS9Ipan+wngvKkkX64BU0l4aLQ9b+REmjf9NZ1RD1UGCL2bmP5XDeoHtYM8uEGYCXu4vvZ1C16oy7AJv/PEEUtL1WNEwJ0Pf9A3DV0o0UxR1q1T5x5nFHftmUu/wrgL2R6GJkUKvWOFWJgAILRk1jHd6HueuqTdTZWdPIDmUH6XwaKEvEBJzwSL2LCUEpMATTE2c3Sw+06USRWWJ3+pIYWS7pM632cOahyPj5iyAihGleXc3bFgjTH/9zlUnJAz3FTrFdRLjj4Vy/UTQDwUKLZEcPWXcYFTPtfuMuR1rwrzIXJOa8ywA/qdbn0XTHtCbTPTHADBaqPEzK8NxMQdCrtgfuCjJ4kPrmVxOaf784RiHgDmcvJ+2Xtazf09hYo+gKtSy8xLTktDZHxfniAtfZP8QU18rpGNsOcKl/E7rA==

posted @ 2020-07-14 22:15  .Neterr  阅读(5526)  评论(0编辑  收藏  举报