前言:
早期时有涉及过单点登录,一直未有比较清晰直观的理解权限认证这块的东西,本文将从概念到项目中的运用详细讲解(含项目中部分代码)PS:ASE加密解密方法未贴出
正文:
JWT 是什么?
JWT的全称是:Json-web-Token,从字面是上我们不难理解,即web端的一个json类型的token,各方之间的安全json访问对象
JWT分为三部分
1.head
head里面的内容是json串,有两个参数,type:jwt alg:RSA或者ASE等,这里是代表需要用什么算法进行加密解密
2Payload
payload也是json串,这里用来写一些注册信息,公开以及私有的一些方法
3Signature
Signature 签名,这一步部分是head+payload里的信息整合进行签名,具体是将head的json进行加密、将payload的json进行加密,这两部信息中间用点(.)进行分割,然后再同一将整合的内容进行再次加密,得到的就是最终的token
JWT使用过程
client端向认证服务器发起认证授权请求,认证通过后,会向client客户端发送一个token串,客户端拿到token串后再去访问服务器即可
JWT认证优缺点
优点:
认证通过的情况下,资源服务器不必再次做校检token正确与否,只要资源服务器能将token串解密开就可以了,可以减轻认证授权中心的压力
缺点:
JWT的token串里的内容多,会很影响性能,安全性能比较弱,一般设置过期的时间不宜太长,而且这个token串在client端是需要存储的
项目使用案例:
之前在项目中有开始接触企业微信,需要使用到token做权限验证,即企业微信平台提供一个json串的token,进行加密以及解密操作
这里企业微信会有两个操作,第一次做一个验证URL的操作,发起一个Get请求,在请求中带入特定的参数,然后使用ASE加密解密算法对参数进行处理,验证通过后,用户发送信息,服务端发起一个Post的请求
操作与第一步类似,只是在这里会把发送的信息以xml的格式包含在请求head里,此时需要取出然后进行解密再进行拆分,即可获取发送信息,然后再将信息加密后推送至另一端。
第一次验证操作
//Controllers里的方法
CallBackService callBack = new CallBackService(); msg_signature = HttpContext.Current.Request.QueryString["msg_signature"]; timestamp = HttpContext.Current.Request.QueryString["timestamp"]; nonce = HttpContext.Current.Request.QueryString["nonce"]; echostr = HttpContext.Current.Request.QueryString["echostr"]; return callBack.CallBackCheck(msg_signature, timestamp, nonce, echostr);
//Service里的方法
string sVerifyMsgSig = QYVXHttpHelper.ParseUrl("msg_signature"); string sVerifyTimeStamp = QYVXHttpHelper.ParseUrl("timestamp"); string sVerifyNonce = QYVXHttpHelper.ParseUrl("nonce"); QYWeixinHelper.CreateLog("sVerifyMsgSig" + sVerifyMsgSig + "</br>" + "sVerifyTimeStamp:" + sVerifyTimeStamp + "</br>" + "sVerifyNonce:" + sVerifyNonce); //这里注意解码 由于很多验证需要用到密文,解析的时候一定要注意 //直接使用UrlDecode会导致+号丢失 string sVerifyEchoStrtemp = QYVXHttpHelper.ParseUrl("echostr"); string sVerifyEchoStrtemp22 = System.Web.HttpUtility.UrlEncode(sVerifyEchoStrtemp); string sVerifyEchoStr = System.Web.HttpUtility.UrlDecode(sVerifyEchoStrtemp22); QYWeixinHelper.CreateLog("sVerifyEchoStr" + sVerifyEchoStr); string sEchoStr = ""; try { //如果验证通过,把明文作为Get请求的返回值, if (CheckSignature(sToken, sCorpID, sEncodingAESKey, sVerifyMsgSig, sVerifyTimeStamp, sVerifyNonce, sVerifyEchoStr, ref sEchoStr)) { QYWeixinHelper.CreateLog("权限验证通过了"); HttpContext.Current.Response.ContentEncoding = Encoding.UTF8; HttpContext.Current.Response.Write(sEchoStr); return QYVXHttpHelper.ToHttpMsgForWeChat(sEchoStr); } else { return QYVXHttpHelper.ToHttpMsgForWeChat("验证失败,检查CallBackCheck方法"); } } catch (Exception ex) { return QYVXHttpHelper.ToHttpMsgForWeChat(ex.ToString()); }
第二次发送信息(Post 请求) //1.验证消息的真实性,并进行解密 //2 根据发送内容不同,指定不同的回复格式
//3把回复的数据再次加密,返回 public static HttpResponseMessage CallBackSend(string sReqMsgSig, string sReqTimeStamp, string sReqNonce, string sReqData) { string sToken = ReadConfigHelper.ReadBackConfig("Token"); //"swygRd6"; string sCorpID = ReadConfigHelper.ReadBackConfig("corpid"); // "wx5823bf96d3bd56c7"; string sEncodingAESKey = ReadConfigHelper.ReadBackConfig("EncodingAESKey"); //"QReQh5qrKlyxNg2NPdH1S6MJSVF8f2LMWI6vrlOV7X6"; // Post请求的密文数据 WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(sToken, sEncodingAESKey, sCorpID); string sMsg = ""; // 解析之后的明文 int ret = wxcpt.DecryptMsg(sReqMsgSig, sReqTimeStamp, sReqNonce, sReqData, ref sMsg); //ret==0表示解密验证成功 if (ret != 0) { return QYVXHttpHelper.ToHttpMsgForWeChat("CallBackSend验证失败"); } XmlDocument doc = new XmlDocument(); doc.LoadXml(sMsg); XmlNode root = doc.FirstChild; #region 回复消息格式 string MsgType = root["MsgType"].InnerText; #endregion string Content = string.Empty; string PicUrl = string.Empty; string MediaId = string.Empty; string ResponseResult = string.Empty; if (MsgType == "text") { QYWeixinHelper.CreateLog("进入文本判断"); ResponseResult = BackTextXml.ReadTextXml(sMsg); } //企业需要将发送的信息返回 // 加密成功,企业需要将加密之后的sEncryptMsg返回 string sEncryptMsg = ""; //xml格式的密文 ret = wxcpt.EncryptMsg(ResponseResult, sReqTimeStamp, sReqNonce, ref sEncryptMsg); if (ret != 0) { return QYVXHttpHelper.ToHttpMsgForWeChat("发送的信息加密失败"); } //验证成功,再次解密当前的数据,然后发送 QYWeixinHelper.CreateLog("ret=0成功,否则失败" + ret); DmUserExEntity ex = new DmUserExEntity(); foreach (var item in root) { ex.Reqid = 580005; ex.FromSource = 6; ex.AgentName = root["FromUserName"].InnerText;//消息回复方 ex.AgentId = root["AgentID"].InnerText; ex.Content = root["Content"].InnerText; } HttpContext.Current.Response.ContentEncoding = Encoding.UTF8; HttpContext.Current.Response.Write(sEncryptMsg); return QYVXHttpHelper.ToHttpMsgForWeChat("OK"); }