溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

C# 怎么實(shí)現(xiàn)Token的方法

發(fā)布時(shí)間:2021-03-15 11:15:05 來(lái)源:億速云 閱讀:237 作者:TREX 欄目:開(kāi)發(fā)技術(shù)

本篇內(nèi)容介紹了“C# 怎么實(shí)現(xiàn)Token的方法”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

什么是JWT

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認(rèn)證所顯露的問(wèn)題

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ī)制

基于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的主題上。

JWT的構(gòu)成

第一部分我們稱它為頭部(header),第二部分我們稱其為載荷(payload, 類似于飛機(jī)上承載的物品),第三部分是簽證(signature).

C# MVC實(shí)現(xiàn)token

1.在NuGet中引用JWT

C# 怎么實(shí)現(xiàn)Token的方法

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

C# 怎么實(shí)現(xiàn)Token的方法

10.客戶端將token放入header中達(dá)到攜帶token目的。

C# 怎么實(shí)現(xiàn)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的方法

“C# 怎么實(shí)現(xiàn)Token的方法”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問(wèn)一下細(xì)節(jié)

免責(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)容。

AI