C#分布式登陆——jwt

1、传统的session登陆

在服务器存储一份用户登陆的信息,这份登陆信息会在响应时传递给浏览器,告诉其保存为cookie,以便下次请求时发送给咱们的应用,这样咱们的应用就能识别请求来自哪一个用户了,这就是传统的基于session认证。html

 

在asp.net core中能够简单实现:git

 1   // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
 2         public void Configure(IApplicationBuilder app, IHostingEnvironment env)
 3         {
 4             if (env.IsDevelopment())
 5             {
 6                 app.UseDeveloperExceptionPage();
 7             }
 8             else
 9             {
10                 app.UseExceptionHandler("/Home/Error");
11                 app.UseHsts();
12             }
13  
14             app.UseHttpsRedirection();
15             //使用静态文件
16             app.UseStaticFiles();
17             //Cookie策略
18             //app.UseCookiePolicy();
19             //Session
20             app.UseSession();
21  
22             app.UseMvc(routes =>
23             {
24                 routes.MapRoute(
25                     name: "default",
26                    // template: "{controller=Home}/{action=Index}/{id?}");
27                    //template: "{controller=Home}/{action=Server}/{id?}");
28                    template: "{controller=Login}/{action=SignIn}/{id?}");
29             });
30         }
 1         public IActionResult SignIn(UserModel userModel)
 2         {
 3             if (ModelState.IsValid)
 4             {
 5                 //检查用户信息
 6                 if (userModel.Username.Equals("yswenli") && userModel.Password.Equals("yswenli"))
 7                 {
 8                     //记录Session
 9                     HttpContext.Session.Set("User", ByteConvertHelper.Object2Bytes(userModel));
10                     //跳转到系统首页
11                     return RedirectToAction("Server", "Home");
12                 }
13                 ViewBag.ErrorInfo = "用户名或密码错误";
14                 return View(userModel);
15             }
16             ViewBag.ErrorInfo = ModelState.Values.First().Errors[0].ErrorMessage;
17             return View(userModel);

 

可是这种基于session的认证使应用自己很可贵到扩展,随着不一样客户端用户的增长,独立的服务器已没法承载更多的用户,而这时候基于session认证应用的问题就会暴露出来。github

传统session的主要问题以下:web

1.服务器压力: 每一个用户通过咱们的应用认证以后,咱们的应用都要在服务端作一次记录,以方便用户下次请求的鉴别,一般而言session都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大。后端

2.扩展性: 用户认证以后,服务端作认证记录,若是认证的记录被保存在内存中的话,这意味着用户下次请求还必需要请求在这台服务器上,这样才能拿到受权的资源,这样在分布式的应用上,相应的限制了负载均衡器的能力。这也意味着限制了应用的扩展能力。跨域

3.CSRF: 由于是基于cookie来进行用户识别的, cookie若是被截获,用户就会很容易受到跨站请求伪造的攻击。浏览器

2、基于token的鉴权机制

基于token的鉴权机制是无状态的,它不须要在服务端去保留用户的认证信息或者会话信息,而是基于token去运算而实现鉴权。这就意味着基于token认证机制的应用不须要去考虑用户在哪一台服务器登陆了,这就为服务实现大规模分布式提供了基础。安全

 

上图是一种用token登陆的实现方式,相似的还有不少,虽然实现了分布式的登陆处理,可是因为不一样的系统之间的不一样实现,致使开发量剧增。服务器

3、Json web token

这里推荐使用JWT——Json web token(官网连接)。一个典型的JWT看起来以下图:cookie

 

 

 

jwt为一个字符串,字符之间经过"."分隔符分为三个子串。注意JWT对象为一个长字串,各字串之间也没有换行符,此处为了演示须要,特地分行并用不一样颜色表示了。每个子串表示了一个功能块,总共有如下三个部分:JWT头、有效载荷和签名,将它们写成一行以下:

 1 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3QiLCJpYXQiOjE1OTM5NTU5NDMsInVpZCI6MTAsImV4cCI6MTU5Mzk1NTk3Mywic2NvcGVzIjpbImFkbWluIiwidXNlciJdfQ.VHpxmxKVKpsn2Iytqc_6Z1U1NtiX3EgVki4PmA-J3Pg 

通常是将它放入HTTP请求的Header Authorization字段中

 1 Authorization: Bearer 

这里能够打开nuget:https://www.nuget.org/packages/JWT.Standard/,或者在vs中使用

 

 

输入jwt.standard找到nuget包下载

1.生成jwt数据

在须要使用的地方输入以下C#代码:

var jwtp = new JWTPackage<UserModel>(new UserModel()
{
    Id = "1",
    Name = "yswenli",
    Role = "Admin"
}, 180, _pwd);
var keyValuePair = jwtp.GetAuthorizationBearer();
context.HttpContext.Response.Headers[keyValuePair.Key] = keyValuePair.Value;

这样就将须要的jwt内容信息加入到Http头部中,固然可使用以下方式,以参数数据的方式传递,从而避免跨域问题

 1     var password = Guid.NewGuid().ToString("N");
 2 
 3     var jwtp1 = new JWTPackage<User>(new User()
 4     {
 5         Id = "1",
 6         Name = "yswenli",
 7         Role = "Admin"
 8     }, 180, password);
 9 
10     var sign = jwtp1.Signature;    

2.jwt解析验证

JWTPackage<T>中使用JWTPackage<T>.Parse方法解析jwt的内容,若是内容是header中的参数,则快捷解析验证代码以下:

 1 var result = string.Empty;
 2 try
 3 {
 4     if (context.HttpContext.Request.Headers.ContainsKey(keyValuePair.Key))
 5     {
 6         var val = context.HttpContext.Request.Headers[keyValuePair.Key].ToString();
 7 
 8         val = val.Replace(JWTPackage.Prex, "");
 9 
10         var jwt = JWTPackage<UserModel>.Parse(val, pwd);
11 
12         result = "OK";
13     }
14 }
15 catch (IllegalTokenException iex)
16 {
17     result = $"解析失败:{iex.Message}";
18 }
19 catch (TokenExpiredException tex)
20 {
21     result = $"解析失败:{tex.Message}";
22 }
23 catch (SignatureVerificationException sex)
24 {
25     result = $"解析失败:{sex.Message}";
26 }
27 catch (Exception ex)
28 {
29     result = $"解析失败:{ex.Message}";
30 }
31 return result;

4、JWT的问题

通过上述的简单介绍,JWT不只可用于认证,还可用于信息交换,善用JWT有助于减小服务器请求数据的次数。可是若是不正确的使用JWT也会形成安全问题,主要几点以下:

1.保护好secret私钥,加密的密码不能泄漏,不然就失去了签名的意义了

2.Replay Attacks,JWT的消息体中最好加入生成时间,在后端中进行时间断定,小于规定时间的直接拦截

3.不该该在JWT的payload部分存放敏感信息,由于该部分是客户端可解密的部分

4.建议的方式是经过SSL加密的传输(https协议),从而避免敏感信息被嗅探

 


转载请标明本文来源:http://www.javashuo.com/article/p-uxubclas-nc.html
更多内容欢迎star个人的github:https://github.com/cnwenli/JWT.Net若是发现本文有什么问题和任何建议,也随时欢迎交流~

相关文章
相关标签/搜索