您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“C# 怎么實(shí)現(xiàn)Token的方法”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
JWT:Json web token (JWT), 是為了在網(wǎng)絡(luò)應(yīng)用環(huán)境間傳遞聲明而執(zhí)行的一種基于JSON的開(kāi)放標(biāo)準(zhǔn)((RFC 7519).該token被設(shè)計(jì)為緊湊且安全的,特別適用于分布式站點(diǎn)的單點(diǎn)登錄(SSO)場(chǎng)景。JWT的聲明一般被用來(lái)在身份提供者和服務(wù)提供者間傳遞被認(rèn)證的用戶身份信息,以便于從資源服務(wù)器獲取資源,也可以增加一些額外的其它業(yè)務(wù)邏輯所必須的聲明信息,該token也可直接被用于認(rèn)證,也可被加密。
傳統(tǒng)的session認(rèn)證
我們知道,http協(xié)議本身是一種無(wú)狀態(tài)的協(xié)議,而這就意味著如果用戶向我們的應(yīng)用提供了用戶名和密碼來(lái)進(jìn)行用戶認(rèn)證,那么下一次請(qǐng)求時(shí),用戶還要再一次進(jìn)行用戶認(rèn)證才行,因?yàn)楦鶕?jù)http協(xié)議,我們并不能知道是哪個(gè)用戶發(fā)出的請(qǐng)求,所以為了讓我們的應(yīng)用能識(shí)別是哪個(gè)用戶發(fā)出的請(qǐng)求,我們只能在服務(wù)器存儲(chǔ)一份用戶登錄的信息,這份登錄信息會(huì)在響應(yīng)時(shí)傳遞給瀏覽器,告訴其保存為cookie,以便下次請(qǐng)求時(shí)發(fā)送給我們的應(yīng)用,這樣我們的應(yīng)用就能識(shí)別請(qǐng)求來(lái)自哪個(gè)用戶了,這就是傳統(tǒng)的基于session認(rèn)證。
但是這種基于session的認(rèn)證使應(yīng)用本身很難得到擴(kuò)展,隨著不同客戶端用戶的增加,獨(dú)立的服務(wù)器已無(wú)法承載更多的用戶,而這時(shí)候基于session認(rèn)證應(yīng)用的問(wèn)題就會(huì)暴露出來(lái).
Session: 每個(gè)用戶經(jīng)過(guò)我們的應(yīng)用認(rèn)證之后,我們的應(yīng)用都要在服務(wù)端做一次記錄,以方便用戶下次請(qǐng)求的鑒別,通常而言session都是保存在內(nèi)存中,而隨著認(rèn)證用戶的增多,服務(wù)端的開(kāi)銷會(huì)明顯增大。
擴(kuò)展性: 用戶認(rèn)證之后,服務(wù)端做認(rèn)證記錄,如果認(rèn)證的記錄被保存在內(nèi)存中的話,這意味著用戶下次請(qǐng)求還必須要請(qǐng)求在這臺(tái)服務(wù)器上,這樣才能拿到授權(quán)的資源,這樣在分布式的應(yīng)用上,相應(yīng)的限制了負(fù)載均衡器的能力。這也意味著限制了應(yīng)用的擴(kuò)展能力。
CSRF: 因?yàn)槭腔赾ookie來(lái)進(jìn)行用戶識(shí)別的, cookie如果被截獲,用戶就會(huì)很容易受到跨站請(qǐng)求偽造的攻擊。
基于token的鑒權(quán)機(jī)制類似于http協(xié)議也是無(wú)狀態(tài)的,它不需要在服務(wù)端去保留用戶的認(rèn)證信息或者會(huì)話信息。這就意味著基于token認(rèn)證機(jī)制的應(yīng)用不需要去考慮用戶在哪一臺(tái)服務(wù)器登錄了,這就為應(yīng)用的擴(kuò)展提供了便利。
流程上是這樣的:
用戶使用用戶名密碼來(lái)請(qǐng)求服務(wù)器
服務(wù)器進(jìn)行驗(yàn)證用戶的信息
服務(wù)器通過(guò)驗(yàn)證發(fā)送給用戶一個(gè)token
客戶端存儲(chǔ)token,并在每次請(qǐng)求時(shí)附送上這個(gè)token值
服務(wù)端驗(yàn)證token值,并返回?cái)?shù)據(jù)
這個(gè)token必須要在每次請(qǐng)求時(shí)傳遞給服務(wù)端,它應(yīng)該保存在請(qǐng)求頭里, 另外,服務(wù)端要支持CORS(跨來(lái)源資源共享)策略,一般我們?cè)诜?wù)端這么做就可以了Access-Control-Allow-Origin: *。
那么我們現(xiàn)在回到JWT的主題上。
第一部分我們稱它為頭部(header),第二部分我們稱其為載荷(payload, 類似于飛機(jī)上承載的物品),第三部分是簽證(signature).
1.在NuGet中引用JWT
2.創(chuàng)建一個(gè)實(shí)體 UserInfo類
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace WebApplication1.model { public class UserInfo { public string UserName { get; set; } public string Pwd { get; set; } } }
3.創(chuàng)建JWT幫助類
using JWT; using JWT.Algorithms; using JWT.Serializers; using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace WebApplication1.model { public class JwtHelp { //私鑰 web.config中配置 //"GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrk"; private static string secret = "GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrk"; //ConfigurationManager.AppSettings["Secret"].ToString(); /// <summary> /// 生成JwtToken /// </summary> /// <param name="payload">不敏感的用戶數(shù)據(jù)</param> /// <returns></returns> public static string SetJwtEncode(Dictionary<string, object> payload) { //格式如下 //var payload = new Dictionary<string, object> //{ // { "username","admin" }, // { "pwd", "claim2-value" } //}; 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; } /// <summary> /// 根據(jù)jwtToken 獲取實(shí)體 /// </summary> /// <param name="token">jwtToken</param> /// <returns></returns> public static UserInfo GetJwtDecode(string token) { IJsonSerializer serializer = new JsonNetSerializer(); IDateTimeProvider provider = new UtcDateTimeProvider(); IJwtValidator validator = new JwtValidator(serializer, provider); IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder(); var algorithm = new HMACSHA256Algorithm(); IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder, algorithm); var userInfo = decoder.DecodeToObject<UserInfo>(token, secret, verify: true);//token為之前生成的字符串 return userInfo; } } }
4.創(chuàng)建一個(gè)編碼類DESCryption
using System; using System.Text; using System.Security.Cryptography; using System.IO; using System.Configuration; namespace JWT.MvcDemo.Help { public class DESCryption { /// <summary> /// //注意了,是8個(gè)字符,64位 /// </summary> private static string PrivateRsa = ConfigurationManager.AppSettings["PrivateRsa"]; /// <summary> /// //注意了,是8個(gè)字符,64位 /// </summary> private static string PublicRsa = ConfigurationManager.AppSettings["PublicRsa"]; /// <summary> /// 加密 /// </summary> /// <param name="data"></param> /// <returns></returns> public static string Encode(string data) { byte[] byKey = Encoding.ASCII.GetBytes(PrivateRsa); byte[] byIV = Encoding.ASCII.GetBytes(PublicRsa); DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider(); int i = cryptoProvider.KeySize; MemoryStream ms = new MemoryStream(); CryptoStream cst = new CryptoStream(ms, cryptoProvider.CreateEncryptor(byKey, byIV), CryptoStreamMode.Write); StreamWriter sw = new StreamWriter(cst); sw.Write(data); sw.Flush(); cst.FlushFinalBlock(); sw.Flush(); return Convert.ToBase64String(ms.GetBuffer(), 0, (int)ms.Length); } /// <summary> /// 解密 /// </summary> /// <param name="data"></param> /// <returns></returns> public static string Decode(string data) { byte[] byKey = Encoding.ASCII.GetBytes(PrivateRsa); byte[] byIV = Encoding.ASCII.GetBytes(PublicRsa); byte[] byEnc; try { byEnc = Convert.FromBase64String(data); } catch { return null; } DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider(); MemoryStream ms = new MemoryStream(byEnc); CryptoStream cst = new CryptoStream(ms, cryptoProvider.CreateDecryptor(byKey, byIV), CryptoStreamMode.Read); StreamReader sr = new StreamReader(cst); return sr.ReadToEnd(); } } }
5.創(chuàng)建一個(gè)返回消息類
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace JWT.MvcDemo.Models { public class DataResult { /// <summary> /// /// </summary> public string Token { get; set; } public bool Success { get; set; } public string Message { get; set; } } }
6.創(chuàng)建一個(gè)控制器用于生產(chǎn)token
using JWT.MvcDemo.Models; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using WebApplication1.model; namespace WebApplication1.Controllers { public class JwtController : Controller { // GET: Jwt public ActionResult Index() { return View(); } /// <summary> /// 創(chuàng)建jwtToken /// </summary> /// <param name="username"></param> /// <param name="pwd"></param> /// <returns></returns> public ActionResult CreateToken(string username, string pwd) { DataResult result = new DataResult(); //假設(shè)用戶名為"admin",密碼為"123" if (username == "admin" && pwd == "123") { var payload = new Dictionary<string, object> { { "username",username }, { "pwd", pwd } }; result.Token = JwtHelp.SetJwtEncode(payload); result.Success = true; result.Message = "成功"; } else { result.Token = ""; result.Success = false; result.Message = "生成token失敗"; } //return Json(result); //get請(qǐng)求需要修改成這樣 return Json(result,JsonRequestBehavior.AllowGet); } } }
7.創(chuàng)建一個(gè)自定義過(guò)濾器
using JWT.MvcDemo.Help; using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Security; using WebApplication1.model; namespace JWT.MvcDemo.App_Start { public class MyAuthorizeAttribute : AuthorizeAttribute { private readonly string TimeStamp = ConfigurationManager.AppSettings["TimeStamp"]; /// <summary> /// 驗(yàn)證入口 /// </summary> /// <param name="filterContext"></param> public override void OnAuthorization(AuthorizationContext filterContext) { base.OnAuthorization(filterContext); } /// <summary> /// 驗(yàn)證核心代碼 /// </summary> /// <param name="httpContext">fbc8ZBLd5ZbtCogcY9NUVV4HZbPln1lb</param> /// <returns></returns> protected override bool AuthorizeCore(HttpContextBase httpContext) { //前端請(qǐng)求api時(shí)會(huì)將token存放在名為"auth"的請(qǐng)求頭中 var authHeader = httpContext.Request.Headers["auth"]; if (authHeader == null) return false; //請(qǐng)求參數(shù) string requestTime = httpContext.Request["rtime"]; //請(qǐng)求時(shí)間經(jīng)過(guò)DESC簽名 if (string.IsNullOrEmpty(requestTime)) return false; //模擬生成rtime 時(shí)間戳,即登錄的時(shí)間,加密. //實(shí)際生產(chǎn)中這段代碼應(yīng)該在請(qǐng)求段。此處只為了程序驗(yàn)證通過(guò) string r= DESCryption.Encode(DateTime.Now.ToString()); requestTime = r; //請(qǐng)求時(shí)間RSA解密后加上時(shí)間戳的時(shí)間即該請(qǐng)求的有效時(shí)間 DateTime Requestdt = DateTime.Parse(DESCryption.Decode(requestTime)).AddMinutes(int.Parse(TimeStamp)); DateTime Newdt = DateTime.Now; //服務(wù)器接收請(qǐng)求的當(dāng)前時(shí)間 if (Requestdt < Newdt) { return false; } else { if (authHeader != null) { //進(jìn)行其他操作 var userinfo = JwtHelp.GetJwtDecode(authHeader); //舉個(gè)例子 生成jwtToken 存入redis中 //這個(gè)地方用jwtToken當(dāng)作key 獲取實(shí)體val 然后看看jwtToken根據(jù)redis是否一樣 if (userinfo.UserName == "admin" && userinfo.Pwd == "123") return true; } } return false; } /// <summary> /// 驗(yàn)證失敗處理 /// </summary> /// <param name="filterContext"></param> protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { base.HandleUnauthorizedRequest(filterContext); filterContext.Result = new RedirectResult("/Error"); filterContext.HttpContext.Response.Redirect("/Home/Error"); } } }
8.在要需要過(guò)濾的控制器方法上添加標(biāo)簽,標(biāo)簽就是自定義過(guò)濾器名稱。
using JWT.MvcDemo.App_Start; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace WebApplication1.Controllers { public class HomeController : Controller { public ActionResult Index() { return View(); } [HttpPost] [MyAuthorize] public string About() { string rtJson = "{\"code\": 0}"; try { rtJson = "{\"code\":0,\"data\":[],\"msg\":\"Your application description page.\",\"count\":1}"; } catch { rtJson = "{\"code\": 0}"; } return rtJson; } public ActionResult Contact() { ViewBag.Message = "Your contact page."; return View(); } } }
9.測(cè)試獲取token
10.客戶端將token放入header中達(dá)到攜帶token目的。
11.需要在web.config 中添加設(shè)置值
<add key="Secret" value="GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrk"/> <add key="PrivateRsa" value="GQDstcKs"/> <add key="PublicRsa" value="DVvVBrkx0"/> <add key="TimeStamp" value="2"/>
“C# 怎么實(shí)現(xiàn)Token的方法”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。