C# 如何实现Token

什么是JWT

JWT:Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

传统的session认证

我们知道,http协议本身是一种无状态的协议,而这就意味着如果用户向我们的应用提供了用户名和密码来进行用户认证,那么下一次请求时,用户还要再一次进行用户认证才行,因为根据http协议,我们并不能知道是哪个用户发出的请求,所以为了让我们的应用能识别是哪个用户发出的请求,我们只能在服务器存储一份用户登录的信息,这份登录信息会在响应时传递给浏览器,告诉其保存为cookie,以便下次请求时发送给我们的应用,这样我们的应用就能识别请求来自哪个用户了,这就是传统的基于session认证。

但是这种基于session的认证使应用本身很难得到扩展,随着不同客户端用户的增加,独立的服务器已无法承载更多的用户,而这时候基于session认证应用的问题就会暴露出来.

基于session认证所显露的问题

Session: 每个用户经过我们的应用认证之后,我们的应用都要在服务端做一次记录,以方便用户下次请求的鉴别,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大。

扩展性: 用户认证之后,服务端做认证记录,如果认证的记录被保存在内存中的话,这意味着用户下次请求还必须要请求在这台服务器上,这样才能拿到授权的资源,这样在分布式的应用上,相应的限制了负载均衡器的能力。这也意味着限制了应用的扩展能力。

CSRF: 因为是基于cookie来进行用户识别的, cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击。

基于token的鉴权机制

基于token的鉴权机制类似于http协议也是无状态的,它不需要在服务端去保留用户的认证信息或者会话信息。这就意味着基于token认证机制的应用不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利。

流程上是这样的:

  • 用户使用用户名密码来请求服务器
  • 服务器进行验证用户的信息
  • 服务器通过验证发送给用户一个token
  • 客户端存储token,并在每次请求时附送上这个token值
  • 服务端验证token值,并返回数据

这个token必须要在每次请求时传递给服务端,它应该保存在请求头里, 另外,服务端要支持CORS(跨来源资源共享)策略,一般我们在服务端这么做就可以了Access-Control-Allow-Origin: *。

那么我们现在回到JWT的主题上。

JWT的构成

第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签证(signature).

C# MVC实现token

1.在NuGet中引用JWT

2.创建一个实体 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.创建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">不敏感的用户数据</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>
  /// 根据jwtToken 获取实体
  /// </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.创建一个编码类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个字符,64位
  /// </summary>
  private static string PrivateRsa = ConfigurationManager.AppSettings["PrivateRsa"];

  /// <summary>
  /// //注意了,是8个字符,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.创建一个返回消息类

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.创建一个控制器用于生产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>
  /// 创建jwtToken
  /// </summary>
  /// <param name="username"></param>
  /// <param name="pwd"></param>
  /// <returns></returns>
  public ActionResult CreateToken(string username, string pwd)
  {

   DataResult result = new DataResult();

   //假设用户名为"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请求需要修改成这样
   return Json(result,JsonRequestBehavior.AllowGet);
  }
 }
}

7.创建一个自定义过滤器

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>
  /// 验证入口
  /// </summary>
  /// <param name="filterContext"></param>
  public override void OnAuthorization(AuthorizationContext filterContext)
  {
   base.OnAuthorization(filterContext);
  }

  /// <summary>
  /// 验证核心代码
  /// </summary>
  /// <param name="httpContext">fbc8ZBLd5ZbtCogcY9NUVV4HZbPln1lb</param>
  /// <returns></returns>
  protected override bool AuthorizeCore(HttpContextBase httpContext)
  {

   //前端请求api时会将token存放在名为"auth"的请求头中
   var authHeader = httpContext.Request.Headers["auth"];
   if (authHeader == null)
    return false;

   //请求参数
   string requestTime = httpContext.Request["rtime"]; //请求时间经过DESC签名
   if (string.IsNullOrEmpty(requestTime))
    return false;

   //模拟生成rtime 时间戳,即登录的时间,加密.       //实际生产中这段代码应该在请求段。此处只为了程序验证通过
   string r= DESCryption.Encode(DateTime.Now.ToString());
   requestTime = r;

    //请求时间RSA解密后加上时间戳的时间即该请求的有效时间
    DateTime Requestdt = DateTime.Parse(DESCryption.Decode(requestTime)).AddMinutes(int.Parse(TimeStamp));
    DateTime Newdt = DateTime.Now; //服务器接收请求的当前时间

   if (Requestdt < Newdt)
   {
    return false;
   }
   else
   {
    if (authHeader != null)
    {
     //进行其他操作
     var userinfo = JwtHelp.GetJwtDecode(authHeader);
     //举个例子 生成jwtToken 存入redis中
     //这个地方用jwtToken当作key 获取实体val 然后看看jwtToken根据redis是否一样
     if (userinfo.UserName == "admin" && userinfo.Pwd == "123")
      return true;
    }

   }

   return false;
  }

  /// <summary>
  /// 验证失败处理
  /// </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.在要需要过滤的控制器方法上添加标签,标签就是自定义过滤器名称。

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.测试获取token

10.客户端将token放入header中达到携带token目的。

11.需要在web.config 中添加设置值

 <add key="Secret" value="GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrk"/>
  <add key="PrivateRsa" value="GQDstcKs"/>
  <add key="PublicRsa" value="DVvVBrkx0"/>
  <add key="TimeStamp" value="2"/>

以上就是C# 如何实现Token的详细内容,更多关于C# 实现Token的资料请关注我们其它相关文章!

(0)

相关推荐

  • C#微信公众平台开发之access_token的获取存储与更新

    一.什么是access_token? access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token.正常情况下access_token有效期为7200秒,重复获取将导致上次获取的access_token失效.由于获取access_token的api调用次数非常有限,建议开发者全局存储与更新access_token,频繁刷新access_token会导致api调用受限,影响自身业务. 二.要解决的问题 1.如何获取access_token. 2.由于acces

  • C# 关于爬取网站数据遇到csrf-token的分析与解决

    需求 某航空公司物流单信息查询,是一个post请求.通过后台模拟POST HTTP请求发现无法获取页面数据,通过查看航空公司网站后,发现网站使用避免CSRF攻击机制,直接发挥40X错误. 关于CSRF 读者自行百度 网站HTTP请求分析 Headers Form Data 在head里包含了cookie 与 x-csrf-token  formdata 里包含了_csrf (与head里的值是一样的). 这里通过查看该网站的JS源代码发现_csrf 来自于网页的head标签里 猜测cookie与

  • C# wx获取token的基本方法

    本文实例为大家分享了C# wx获取token的具体代码,供大家参考,具体内容如下 #region 请求Url,不发送数据 /// <summary> /// 请求Url,不发送数据 /// </summary> public static string RequestUrl(string url) { return RequestUrl(url, "POST"); } #endregion #region 请求Url,不发送数据 /// <summary&

  • Vue利用路由钩子token过期后跳转到登录页的实例

    在Vue2.0中的路由钩子主要是用来拦截导航,让它完成跳转或前取消,可以理解为路由守卫. 分为全局导航钩子,单个路由独享的钩子,组件内钩子. 三种 类型的钩子只是用的地方不一样,都接受一个函数作为参数,函数传入三个参数,分别为to,from,next. 其中next有三个方法 (1)next(); //默认路由 (2)next(false); //阻止路由跳转 (3)next({path:'/'}); //阻止默认路由,跳转到指定路径 这里我使用了组件内钩子进行判断token过期后跳转到登录页,

  • vue生成token保存在客户端localStorage中的方法

    前面我们已经了解了可以通过localStorage在客户端(浏览器)保存数据. 我们后端有这样一个接口: http://localhost/yiiserver/web/index.php/token?client_appid=aaa&client_appkey=bbb 其实就向clients(理解为用户表即可)里面去生成一个token 这里的client_appid 就相当于用户名,client_appkey 就相当于密码. 这样后端认证之后会生成一个access-token,我们需要把这个ac

  • 详解ASP.NET Core Token认证

    令牌认证(Token Authentication)已经成为单页应用(SPA)和移动应用事实上的标准.即使是传统的B/S应用也能利用其优点.优点很明白:极少的服务端数据管理.可扩展性.可以使用单独的认证服务器和应用服务器分离. 如果你对令牌(token)不是太了解,可以看这篇文章( overview of token authentication and JWTs) 令牌认证在asp.net core中集成.其中包括保护Bearer Jwt的路由功能,但是移除了生成token和验证token的部

  • php版微信开发Token验证失败或请求URL超时问题的解决方法

    本文实例分析了php版微信开发Token验证失败或请求URL超时问题的解决方法.分享给大家供大家参考,具体如下: 微信开发最近要用到的一个功能,其实就是一个非常的简单的用户输入然后自动搜索数据库并进行一个数据回复了,这个与官方没多大的问题,但小编就微信Token验证失败折腾了许多,下面解决了给各位分析一下. 1.Token验证失败 这个就是要检查配置文件了,最基本的就是 define("TOKEN", "weixin");  weixin 是你的微信开发后台的ID

  • jQury Ajax使用Token验证身份实例代码

    因为最近做了几个后台,所以经常会涉及到Token验证身份操作后台,所以这里记录一个如何向后台传请求头和Token. success:function(dat){ console.log(dat); if(dat.code==1){ sessionStorage.setItem('token',dat.data.access_token); //这里设置缓存存储Token sessionStorage.setItem('user',userName); location.href = "index

  • 微信小程序url与token设置详解

    微信小程序url与token设置详解 新浪云应用sae的代码里创建一个weixin.php文件,写入以下代码 define("TOKEN","myToken");// 后台填写的token,在微信公众平台启用 $wechatObj = new wechatAPI(); $wechatObj->isValid(); class wechatAPI { public function isValid()//验证微信接口,验证函数以外的代码和微信公众号开发token

  • 基于ASP.NET Core数据保护生成验证token示例

    ASP.NET Core Data Protection 不仅提供了非对称加密能力,而且提供了灵活的秘钥存储方式以及一致的加解密接口(Protect与Unprotect).Session中用到了它,Cookie验证中用到了它,OpenIdConnect中也用到了它...当然你也可以在应用开发中使用它,比如这篇博文中就是用它生成激活帐户的验证token. 首先在 Startup.ConfigureServices() 中注册 DataProtection 服务(注入 IDataProtection

  • 详解在ASP.NET Core中使用Angular2以及与Angular2的Token base身份认证

    Angular2是对Angular1的一次彻底的,破坏性的更新. 相对于Angular1.x,借用某果的广告语,唯一的不同,就是处处都不同. •首先,推荐的语言已经不再是Javascript,取而代之的TypeScript,(TypeScript = ES6 + 类型系统 + 类型注解), TypeScriipt的类型系统对于开发复杂的单页Web app大有帮助,同时编译成javascript后的执行效率也比大多数手写javascript要快.有兴趣的同学可以查阅官方文档:英文传送门 |中文传送

  • PHP Token(令牌)设计

    如何达到目的: 怎样避免重复提交? 在SESSION里要存一个数组,这个数组存放以经成功提交的token.在后台处理时,先判断这个token是否在这个数组里,如果存在,说明是重复提交.  如何检查来路? 可选项,这个token在生成的时候,加入了当前的session_id.如果别人copy你的html(token一迸copy),在提交时,理论上token里包含的session_id不等于当前session_id,就可以判断这次提交是外部提交.  如何匹配要执行的动作? 在token的时候,要把这

  • 基于thinkPHP3.2实现微信接入及查询token值的方法

    本文实例讲述了基于thinkPHP3.2实现微信接入及查询token值的方法.分享给大家供大家参考,具体如下: 1.在con.fig文件里面配置TOKEN,APPID,APPSECRET值 2.控制器WeixinController代码: <?php /** * 微信父类控制器 * @author Songle * */ namespace Weixin\Controller; use Think\Controller; class WeixinController extends Contro

随机推荐