Aspnet Mvc 前后端分离项目手记(二)关于token认证
在前后端分離的項目中,首先我們要解決的問題就是身份認證
以往的時候,我們使用cookie+session,或者只用cookie來保持會話。
?
一,先來復習一下cookie和session
首先我們來復習一下在aspnet中cookie和session的關系,做一個簡單試驗
這是一個普通的view沒有任何處理
?
可以看到,沒有任何東西(cookie),然后當我們寫入一個session之后
?
會發現多了一個名為ASP.NET_SessionId的cookie。我們都知道在aspnet中,session是保存在服務器端的內存中的,而http協議是無狀態的,那么他是怎么確定不同請求的session
沒錯,session是借助cookie來實現的:cookie中保存著 session的key,當我們清除掉瀏覽器緩存時,會發現session也找不到了,就是這個原因。
使用session來保持會話有幾個很嚴重的缺點:1 session容易丟失;2無法支持分布式;3,cookie 對跨域的支持不好
?
所以就用到了我們今天說的token
二,token?
1,token的產生
一般是用戶登錄成功,服務器端產生一個token并返給前端,前端將token保存在cookie或者localStorage里面,然后每次請求時都帶上這個token,一般都帶在請求頭里面
?2,token的內容
一般的token里面必須有的是:1,會話用戶的標識:比如userid。2,token的過期時間,如果想更完整一點,可以加上token的頒發者,簽名等等
3,token的生成算法,一般是由服務器端將token的主要內容,過期時間等等做非對稱加密,然后進行簽名算法(防止客戶端更改),具體看后面jwt
?
4,token校驗
當服務器端收到請求時,首先會校驗token,校驗有兩種不同的方式
?一, token產生后保存在服務器端(redis或者其他比較速度快的緩存中) 。優點:可控性強,可以用這個來做單點登錄,比如另一個地方登錄,就remove掉之前的token。缺點:實現麻煩一點,而且要占服務器壓力
二,?token產生后服務器端不保存,只負責校驗。 優點:大大降低了服務器的壓力,實現起來,也要相對簡單一點。缺點:token一旦頒發,服務器端就不可控了,只能等它過期。
? ? 具體用哪種看具體的需求。如果不是做可控性要求很強,個人建議第二種。
?
5 jwt?
jwt 全名Json Web Tokens,算是一種token的規范吧
園子里面有很不不錯的介紹 ,比如這篇:阮一峰 jwt介紹? ?http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html
?
組成有三部分
- Header(頭部,一般包含了token的簽名方式)
- Payload(負載,也就是具體的有效部分)
- Signature(簽名,將前兩部分進行簽名算法,防止客戶端篡改)
實現方式,將header部分和payload部分分別進行base64算法,然后用點號“.”隔開拼接,然后進行簽名算法,然后在將三部分拼接(點號隔開)就得到了jwt
注意 ,jwt默認是采用base64編碼的,也就是說 客戶端也能解碼得出具體內容的,所以除非特殊情況,重要敏感字段一定不能放在token中
?
?以下是具體實現
using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Web;namespace Rk.JWT {public class Jwt{//參考自 阮一峰 jwt介紹 http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.htmlpublic static string SALT = "OXpcRP8jmCfMKumY";/// <summary>////// </summary>/// <param name="ExraPayload">額外的信息</param>/// <returns></returns>public static string Create(Dictionary<string,object> ExraPayload){var Header = new Dictionary<string, string>();Header.Add("tp", "MD5");var Payload = new Dictionary<string, object>();//JWT 規定了7個官方字段,供選用。Payload.Add("iss", "signBy"); //頒發人Payload.Add("jti", Guid.NewGuid().ToString()); //jwt的idPayload.Add("exp",System.DateTime.Now.AddMinutes(20));//過期時間Payload.Add("nbf", System.DateTime.Now);//生效時間Payload.Add("iat", System.DateTime.Now);//簽發時間Payload.Add("sub", "subject");//主題Payload.Add("aud", "audience");//受眾foreach (var item in ExraPayload){if (Payload.ContainsKey(item.Key)){throw new Exception($"{item.Key}鍵值已被占用 不能使用 ");}else{Payload.Add(item.Key, item.Value);}}string base64Header = Base64Url(Newtonsoft.Json.JsonConvert.SerializeObject(Header));string base64Payload = Base64Url(Newtonsoft.Json.JsonConvert.SerializeObject(Payload));string tmp = base64Header + "." + base64Payload;string sign = Md5(tmp+ SALT);//加鹽,重要return base64Header+"."+ base64Payload+"."+ sign;}//校驗是否合法,是否過期public static bool Check(string token){string base64Header = token.Split('.')[0];string base64Payload = token.Split('.')[1];string sign = token.Split('.')[2];string tmp = base64Header + "." + base64Payload;var signCheck = Md5(base64Header + "." + base64Payload + SALT);if(signCheck!= sign){return false;}var dic = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(Base64UrlDecode(base64Payload));if( Convert.ToDateTime(dic["exp"])<System.DateTime.Now){//過期了return false;}return true;}//校驗是否合法,是否過期public static Dictionary<string,object> GetPayLoad(string token){string base64Payload = token.Split('.')[1];var dic = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(Base64UrlDecode(base64Payload));return dic;}public static string Base64Url(string input){//JWT 作為一個令牌(token),有些場合可能會放到 URL(比如 api.example.com/?token=xxx)。//Base64 有三個字符+、/和=,在 URL 里面有特殊含義,所以要被替換掉:=被省略、+替換成-,/替換成_ 。string output = "";byte[] bytes = Encoding.UTF8.GetBytes(input);try{output = Convert.ToBase64String(bytes).Replace('+', '-').Replace('/', '_').TrimEnd('=') ;}catch (Exception e){throw e;}return output;}public static string Base64UrlDecode(string input){string output = "";input = input.Replace('-', '+').Replace('_', '/');switch (input.Length % 4){case 2:input += "==";break;case 3:input += "=";break;}byte[] bytes = Convert.FromBase64String(input);try{output = Encoding.UTF8.GetString(bytes);}catch{output = input;}return output;}public static string Md5(string input,int bit=16){MD5CryptoServiceProvider md5Hasher = new MD5CryptoServiceProvider();byte[] hashedDataBytes;hashedDataBytes = md5Hasher.ComputeHash(Encoding.GetEncoding("gb2312").GetBytes(input));StringBuilder tmp = new StringBuilder();foreach (byte i in hashedDataBytes){tmp.Append(i.ToString("x2"));}if (bit == 16)return tmp.ToString().Substring(8, 16);elseif (bit == 32) return tmp.ToString();//默認情況else return string.Empty;}}}
?
使用方式
public class HomeController : BaseController{public ActionResult Login(string username, string pwd){/// 1, todo 驗證用戶名密碼正確//2,//在token中加入用戶id,創建tokenvar dic = new Dictionary<string, object>();dic.Add("userid", "20125521225858");string token = JWT.Jwt.Create(dic);//驗證token是否正確是否過期var isChecked = JWT.Jwt.Check(token);return Content("");}}
?
下一篇我們將會聊一聊 rest 風格url在前后端分離項目中的使用
轉載于:https://www.cnblogs.com/wahson2019/p/10860973.html
總結
以上是生活随笔為你收集整理的Aspnet Mvc 前后端分离项目手记(二)关于token认证的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电信宽带,改桥接,设置端口转发,TCP,
- 下一篇: 研究人员利用黑猩猩改进动物模拟技术 效果