C# 如何实现Token
什么是JWT
JWT:Jsonwebtoken(JWT),是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC7519).该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类
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Web;
namespaceWebApplication1.model
{
publicclassUserInfo
{
publicstringUserName{get;set;}
publicstringPwd{get;set;}
}
}
3.创建JWT帮助类
usingJWT;
usingJWT.Algorithms;
usingJWT.Serializers;
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Web;
namespaceWebApplication1.model
{
publicclassJwtHelp
{
//私钥web.config中配置
//"GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrk";
privatestaticstringsecret="GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrk";
//ConfigurationManager.AppSettings["Secret"].ToString();
///
///生成JwtToken
///
///不敏感的用户数据
///
publicstaticstringSetJwtEncode(Dictionarypayload)
{
//格式如下
//varpayload=newDictionary
//{
//{"username","admin"},
//{"pwd","claim2-value"}
//};
IJwtAlgorithmalgorithm=newHMACSHA256Algorithm();
IJsonSerializerserializer=newJsonNetSerializer();
IBase64UrlEncoderurlEncoder=newJwtBase64UrlEncoder();
IJwtEncoderencoder=newJwtEncoder(algorithm,serializer,urlEncoder);
vartoken=encoder.Encode(payload,secret);
returntoken;
}
///
///根据jwtToken获取实体
///
///jwtToken
///
publicstaticUserInfoGetJwtDecode(stringtoken)
{
IJsonSerializerserializer=newJsonNetSerializer();
IDateTimeProviderprovider=newUtcDateTimeProvider();
IJwtValidatorvalidator=newJwtValidator(serializer,provider);
IBase64UrlEncoderurlEncoder=newJwtBase64UrlEncoder();
varalgorithm=newHMACSHA256Algorithm();
IJwtDecoderdecoder=newJwtDecoder(serializer,validator,urlEncoder,algorithm);
varuserInfo=decoder.DecodeToObject(token,secret,verify:true);//token为之前生成的字符串
returnuserInfo;
}
}
}
4.创建一个编码类DESCryption
usingSystem;
usingSystem.Text;
usingSystem.Security.Cryptography;
usingSystem.IO;
usingSystem.Configuration;
namespaceJWT.MvcDemo.Help
{
publicclassDESCryption
{
///
/////注意了,是8个字符,64位
///
privatestaticstringPrivateRsa=ConfigurationManager.AppSettings["PrivateRsa"];
///
/////注意了,是8个字符,64位
///
privatestaticstringPublicRsa=ConfigurationManager.AppSettings["PublicRsa"];
///
///加密
///
///
///
publicstaticstringEncode(stringdata)
{
byte[]byKey=Encoding.ASCII.GetBytes(PrivateRsa);
byte[]byIV=Encoding.ASCII.GetBytes(PublicRsa);
DESCryptoServiceProvidercryptoProvider=newDESCryptoServiceProvider();
inti=cryptoProvider.KeySize;
MemoryStreamms=newMemoryStream();
CryptoStreamcst=newCryptoStream(ms,cryptoProvider.CreateEncryptor(byKey,byIV),CryptoStreamMode.Write);
StreamWritersw=newStreamWriter(cst);
sw.Write(data);
sw.Flush();
cst.FlushFinalBlock();
sw.Flush();
returnConvert.ToBase64String(ms.GetBuffer(),0,(int)ms.Length);
}
///
///解密
///
///
///
publicstaticstringDecode(stringdata)
{
byte[]byKey=Encoding.ASCII.GetBytes(PrivateRsa);
byte[]byIV=Encoding.ASCII.GetBytes(PublicRsa);
byte[]byEnc;
try
{
byEnc=Convert.FromBase64String(data);
}
catch
{
returnnull;
}
DESCryptoServiceProvidercryptoProvider=newDESCryptoServiceProvider();
MemoryStreamms=newMemoryStream(byEnc);
CryptoStreamcst=newCryptoStream(ms,cryptoProvider.CreateDecryptor(byKey,byIV),CryptoStreamMode.Read);
StreamReadersr=newStreamReader(cst);
returnsr.ReadToEnd();
}
}
}
5.创建一个返回消息类
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Web;
namespaceJWT.MvcDemo.Models
{
publicclassDataResult
{
///
///
///
publicstringToken{get;set;}
publicboolSuccess{get;set;}
publicstringMessage{get;set;}
}
}
6.创建一个控制器用于生产token
usingJWT.MvcDemo.Models;
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Web;
usingSystem.Web.Mvc;
usingWebApplication1.model;
namespaceWebApplication1.Controllers
{
publicclassJwtController:Controller
{
//GET:Jwt
publicActionResultIndex()
{
returnView();
}
///
///创建jwtToken
///
///
///
///
publicActionResultCreateToken(stringusername,stringpwd)
{
DataResultresult=newDataResult();
//假设用户名为"admin",密码为"123"
if(username=="admin"&&pwd=="123")
{
varpayload=newDictionary
{
{"username",username},
{"pwd",pwd}
};
result.Token=JwtHelp.SetJwtEncode(payload);
result.Success=true;
result.Message="成功";
}
else
{
result.Token="";
result.Success=false;
result.Message="生成token失败";
}
//returnJson(result);
//get请求需要修改成这样
returnJson(result,JsonRequestBehavior.AllowGet);
}
}
}
7.创建一个自定义过滤器
usingJWT.MvcDemo.Help;
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Configuration;
usingSystem.Linq;
usingSystem.Web;
usingSystem.Web.Mvc;
usingSystem.Web.Security;
usingWebApplication1.model;
namespaceJWT.MvcDemo.App_Start
{
publicclassMyAuthorizeAttribute:AuthorizeAttribute
{
privatereadonlystringTimeStamp=ConfigurationManager.AppSettings["TimeStamp"];
///
///验证入口
///
///
publicoverridevoidOnAuthorization(AuthorizationContextfilterContext)
{
base.OnAuthorization(filterContext);
}
///
///验证核心代码
///
///fbc8ZBLd5ZbtCogcY9NUVV4HZbPln1lb
///
protectedoverrideboolAuthorizeCore(HttpContextBasehttpContext)
{
//前端请求api时会将token存放在名为"auth"的请求头中
varauthHeader=httpContext.Request.Headers["auth"];
if(authHeader==null)
returnfalse;
//请求参数
stringrequestTime=httpContext.Request["rtime"];//请求时间经过DESC签名
if(string.IsNullOrEmpty(requestTime))
returnfalse;
//模拟生成rtime时间戳,即登录的时间,加密.//实际生产中这段代码应该在请求段。此处只为了程序验证通过
stringr=DESCryption.Encode(DateTime.Now.ToString());
requestTime=r;
//请求时间RSA解密后加上时间戳的时间即该请求的有效时间
DateTimeRequestdt=DateTime.Parse(DESCryption.Decode(requestTime)).AddMinutes(int.Parse(TimeStamp));
DateTimeNewdt=DateTime.Now;//服务器接收请求的当前时间
if(Requestdt
///验证失败处理
///
///
protectedoverridevoidHandleUnauthorizedRequest(AuthorizationContextfilterContext)
{
base.HandleUnauthorizedRequest(filterContext);
filterContext.Result=newRedirectResult("/Error");
filterContext.HttpContext.Response.Redirect("/Home/Error");
}
}
}
8.在要需要过滤的控制器方法上添加标签,标签就是自定义过滤器名称。
usingJWT.MvcDemo.App_Start;
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Web;
usingSystem.Web.Mvc;
namespaceWebApplication1.Controllers
{
publicclassHomeController:Controller
{
publicActionResultIndex()
{
returnView();
}
[HttpPost]
[MyAuthorize]
publicstringAbout()
{
stringrtJson="{\"code\":0}";
try
{
rtJson="{\"code\":0,\"data\":[],\"msg\":\"Yourapplicationdescriptionpage.\",\"count\":1}";
}
catch
{
rtJson="{\"code\":0}";
}
returnrtJson;
}
publicActionResultContact()
{
ViewBag.Message="Yourcontactpage.";
returnView();
}
}
}
9.测试获取token
10.客户端将token放入header中达到携带token目的。
11.需要在web.config中添加设置值
以上就是C#如何实现Token的详细内容,更多关于C#实现Token的资料请关注毛票票其它相关文章!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。