Skip to content

JWT验证集成

Henry edited this page Sep 10, 2019 · 1 revision

API数据交互过程中往往需要安全验证,但组件并不直接提供这方向面的支持;由于组件是基于标准HTTP协议的实现,所有基于这协议的验证规则都可以根据实际情况来扩展。以下是针对JWT验证的一个扩展,并添加的服务应用中。为了实现这一验证功能需要添加一个相关组件System.IdentityModel.Tokens.Jwt

实现JWT Helper

    public class JWTHelper
    {
        private string mIssuer = null;

        private string mAudience = null;

        private SecurityKey mSecurityKey;

        private SigningCredentials mSigningCredentials;

        private TokenValidationParameters mTokenValidation = new TokenValidationParameters();

        private JwtSecurityTokenHandler mJwtSecurityTokenHandler = new JwtSecurityTokenHandler();

        public JWTHelper() : this(null, null)
        {

        }

        public JWTHelper(string issuer, string audience, string key = "2qyg4coej88uqrono0xdmx4y0il5dn5y7b72tlb3imba677ht1p1xlfcnh36mk5u3xzjktfara29axvzk85apfplun7oslbe1m20c148p5d519kja5wvg7lmn5v4a5ou")
        {
            mIssuer = issuer;
            mAudience = audience;
            mSecurityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
            if (string.IsNullOrEmpty(mIssuer))
            {
                mTokenValidation.ValidateIssuer = false;
            }
            else
            {
                mTokenValidation.ValidIssuer = mIssuer;
            }
            if (string.IsNullOrEmpty(mAudience))
            {
                mTokenValidation.ValidateAudience = false;
            }
            else
            {
                mTokenValidation.ValidAudience = mAudience;
            }
            mTokenValidation.IssuerSigningKey = mSecurityKey;
            mSigningCredentials = new SigningCredentials(mSecurityKey, SecurityAlgorithms.HmacSha256);
            Expires = 60 * 24;
        }

        public int Expires { get; set; }

        public string CreateToken(string name, string role)
        {
            ClaimsIdentity claimsIdentity = new ClaimsIdentity();
            claimsIdentity.AddClaim(new Claim("Name", name));
            claimsIdentity.AddClaim(new Claim("Role", role));
            var item = mJwtSecurityTokenHandler.CreateEncodedJwt(mIssuer, mAudience, claimsIdentity, DateTime.Now.AddMinutes(-5),
                DateTime.Now.AddMinutes(100), DateTime.Now,
               mSigningCredentials);
            return item;
        }

        public ClaimsPrincipal ValidateToken(string token)
        {
            return mJwtSecurityTokenHandler.ValidateToken(token, mTokenValidation, out var securityToken);
        }

        public UserInfo GetUserInfo(string token)
        {
            UserInfo userInfo = new UserInfo();
            if (!string.IsNullOrEmpty(token))
            {
                var info = ValidateToken(token);
                ClaimsIdentity identity = info?.Identity as ClaimsIdentity;
                userInfo.Name = identity?.Claims?.FirstOrDefault(c => c.Type == "Name")?.Value;
                userInfo.Role = identity?.Claims?.FirstOrDefault(c => c.Type == "Role")?.Value;
            }
            return userInfo;
        }

        public struct UserInfo
        {
            public string Name;

            public string Role;
        }
    }

以上封装只是简单地提供了用户名称和角色两项信息,不过一般情况这两信息可以满足普通验证的需要;如果有更多的信息需求可以根据实际情况添加,不过信息越多那对应的Token内容就越大。

创建Token

var token=JWTHelper.CreateToken(name, role);

通过以上代码创建一个JWTToken

定义组件验证过虑器

可以通过虑器的方式引入到组件中,这样就可以在不修改控制器逻辑的情况进行安全验证。过虑器实现如下:

    public class JWTFilter : FilterAttribute
    {
        public override bool Executing(ActionContext context)
        {
            string token = context.HttpContext.Request.Header[HeaderTypeFactory.AUTHORIZATION];
            var user = Program.JWTHelper.GetUserInfo(token);
            if (!string.IsNullOrEmpty(user.Name))
            {
                return true;
            }
            else
            {
                context.Result = new TextResult("token not found");
                return false;
            }
        }
    }

重写Executing方法,获取请求头相关Token信息并获取相关用户信息,当获取的用户名是正确的情况则返回true继续执行,否则返回一个相关的错误信息。

使用

        public object GetToken(string name, string role)
        {
            return new TextResult(JWTHelper.CreateToken(name, role));
        }
        [JWTFilter]
        public object GetTime()
        {
            return DateTime.Now;
        }

以上有两个方法,一个是不需要验证创建并返回一个Token,而另一个获取时间的方法则需要验证通过后才能获取。