基于.net、JWT的统一权限认证

什么是JWT
根据维基百科:JSON WEB Token(JWT,读作 [/dʒɒt/]),是一种基于JSON的、用于在网络上声明某种主张的令牌(token)。JWT通常由三部分组成: 头信息(header), 消息体(payload)和签名(signature)。

头信息指定了该JWT使用的签名算法:
header = ‘{“alg”:“HS256”,“typ”:“JWT”}’
HS256 表示使用了 HMAC-SHA256 来生成签名。

消息体包含了JWT的意图:
payload = new Dictionary<string, object>
{
{“userId”,userId},
{“exp”,secondsSinceEpoch},
};

未签名的令牌由base64url编码的头信息和消息体拼接而成(使用"."分隔),签名则通过私有的key计算而成:
key = ‘secretkey’
unsignedToken = encodeBase64(header) + ‘.’ + encodeBase64(payload)
signature = HMAC-SHA256(key, unsignedToken)

最后在未签名的令牌尾部拼接上base64url编码的签名(同样使用"."分隔)就是JWT了:
token = encodeBase64(header) + ‘.’ + encodeBase64(payload) + ‘.’ + encodeBase64(signature)

token看起来像这样: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dnZWRJbkFzIjoiYWRtaW4iLCJpYX

使用(建立mvc工程省略)

一、新建一个token工具类里面包括生成token的方法、验证token的有效性以及解析token的方法

  public class sp_token
    {
        const string secret = "GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrk";//密钥
        //生成token
        public string GetToken(string userId)
        {
            try 
            {
                IDateTimeProvider provider = new UtcDateTimeProvider();
                var now = provider.GetNow();
                var unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); // or use JwtValidator.UnixEpoch
                var secondsSinceEpoch = Math.Round((now - unixEpoch).TotalSeconds);
                secondsSinceEpoch = secondsSinceEpoch + 60 * 60 * 1000 * 4;//设置token的有效时间
                var payload = new Dictionary<string, object>
                        {
                              {"userId",userId}, 
                              {"exp",secondsSinceEpoch},
                        };
                IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
                IJsonSerializer serializer = new JsonNetSerializer();
                IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
                IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
                var token = encoder.Encode(payload, secret);
                return token;
            }
            catch(Exception ex)
            {
                Log.Error("生成Token失败", ex);
                return "生成Token失败";
            }
        }
        //解析token,由于要进行用户权限的验证,这里返回用户的ID
        public string AnalysisToken(string token)
        {         
            try
            {
                IJsonSerializer serializer = new JsonNetSerializer();
                IDateTimeProvider provider = new UtcDateTimeProvider();
                IJwtValidator validator = new JwtValidator(serializer, provider);
                IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
                IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder);
                string json = decoder.Decode(token, secret, verify: true);//token为之前生成的字符
                var userId = JObject.Parse(json)["userId"].ToString();
                return userId;
            }
            catch (Exception ex)
            {
                throw ex;
            }  
        }
        //验证token的有效性
        public  bool GetTokenInfo(string token)
        {
            bool result = false;
            try
            { 
                IJsonSerializer serializer = new JsonNetSerializer();
                IDateTimeProvider provider = new UtcDateTimeProvider();
                IJwtValidator validator = new JwtValidator(serializer, provider);
                IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
                IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder);
                string json = decoder.Decode(token, secret, verify: true);            
                result = true;
            }
            catch (Exception ex)
            {
                Log.Error("该token是无效的token:" + token, ex);
            }
            return result;
        }
    }

二、登录(登录无需权限控制,只需要继承Controller)
登录方法的具体实现

   public RequestMsg Logion(string desc,UserInfo userInfo)
        {
            RequestMsg msg = new RequestMsg(desc);//封装好的返回信息的类
            try
            {
                JObject obj = new JObject();
                string pswSql = string.Format("select MM from SP_USER where YHZH='{0}'", userInfo.userId);
                DataTable dt = ApplicationManager.DataConnections["oracleConnection"].QueryData(pswSql).Tables[0];
                //验证用户
                if (dt.Rows.Count == 0)
                {
                    msg.SetSuccess(false);
                    msg.message = "用户名username不存在,请检查用户名是否正确";
                    return msg;
                }
                //验证密码
                string encryptPassword = AESEncryptionUtils.Encrypt(userInfo.passWord);
                if (!encryptPassword.Equals(dt.Rows[0]["MM"].ToString()))
                {
                    msg.SetSuccess(false);
                    msg.message = "密码password错误";
                    return msg;
                }
                sp_token sp_token = new sp_token();
                string token=sp_token.GetToken(userInfo.userId);//获取token 
                obj.Add("Token",token);
                //登录成功获取所有权限
                string getPeimissionSql = string.Format("SELECT QXMS FROM sp_user_auth_vm WHERE YHZH='{0}'", userInfo.userId);
                DataTable dts = ApplicationManager.DataConnections["oracleConnection"].QueryData(getPeimissionSql).Tables[0];
                obj.Add("Permision",dts.ToJsonArray());
                msg.data = obj;
                msg.SetSuccess(true);
            }
            catch (Exception  ex)
            {
                msg.SetSuccess(false, ex);
                Log.Error(msg.message, ex);
            }
            return msg;
        }

三、新建一个BaseController将它继承Controller,其它的需要验证的接口再继承BaseController,这样用户在访问其他接口时都会进入BaseController进行Token以及权限的验证

   public class BaseController : Controller
    {
        protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            sp_token tokenDemo = new sp_token();
            string token = filterContext.HttpContext.Request.Headers["token"] ?? "";
            bool isLogin = tokenDemo.GetTokenInfo(token);
            string url = Request.RawUrl;
           /* 统一验证是否登录以及token是否有效 */
            if(!isLogin)
             {
                //未登陆
                base.OnActionExecuting(filterContext);
                filterContext.HttpContext.Response.Redirect(Url.Action("TimeOut", "Particular"));//重定向到超时
             }
             else
            {
            //登录信息有效进行权限的验证
                Dictionary<string, string> dic = new Dictionary<string, string>
                {
                    { "token", token },
                    { "url",  url }
                };
                string response = HttpClient.GetResponseString(HttpClient.CreatePostHttpResponse("http://localhost:15339/VerifyPermision/PriviligeVerify", dic));//这里权限验证写了另外的接口,需要向其发起一次请求,地址用的本地地址
                bool success = (bool)(JObject.Parse(response)["success"]);
                if (!success)
                {
                    base.OnActionExecuting(filterContext);
                    filterContext.HttpContext.Response.Redirect(Url.Action("VerifyFalse", "Particular"));//重定向到验证失败
                }
            }
        }
    }

大概过程就是这样了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值