• .NetCore采取JWT方式进行身份认证


    验证与授权

    Authentication(身份认证)

    认证是系统对请求的用户进行身份识别的过程。

    Authorization (授权)

    授权是对认证通过后的用户进行权限分配的过程。授权简单理解就是:识别认证后用户所拥有哪些权限,从而开放服务器相对应的资源;

    我们通俗点来解释身份验证与授权:验证确认用户是否允许访问,授权给予登录后的用户指定权限标识(通过这个标识,服务端可允许用户进行访问和操作);

    在进行讲解Jwt身份认证前我们来回一下过去我们在MVC、WebForm这些站点都是怎样进行身份认证的。

    我想应该大多数都是基于Cookie、Form表单的身份验证方式吧。

    Cookie验证方式的流程图如下:


    上面流程就是服务端在接收用户登录请求后创建Cookie并保存在服务器上,然后通过Response.Cookies.Add将Cookie返回客户端。

    客户端浏览器可以记住服务器返回的Cookie,记住后Cookie值会存储在客户端硬盘上,下次访问站点时候Http请求头会携带Cookie。

    携带Cookie的请求到服务端后,服务端进行验证,验证通过后即可正返回请求的资源,否则会跳转到登录页面。

    Cookie方式的缺点

    了解到Cookie方式的验证流程后可以发现它是对Http请求强加了一层“会话”,让我们的Http请求携带与身份认证相关的标识(Cookie)。

    那这种方式有什么不好的呢?我总结了下面几点:

    1、对有多种客户端(APP、浏览器、Winform应用)请求的场景不好扩展;
    2、对分布式架构的服务端不好扩展,客户端的请求不一定指向同一台服务器,每一台服务器都需存储针对已登录的用户Cookie;
    3、跨域访问问题;

    Jwt身份验证方式

    在多终端,分布式架构的服务无所不在的今天,Cookie身份认证的方式显然是难以满足我们的,这个时候Jwt(Json Web Token)横空出世啦~ 

    使用Jwt我们可以完美的解决上面的遗留问题(当然后面也会说到jwt本身存在的问题....)

    我们先看下Jwt的身份验证流程:

     

    根据流程图得知jwt是在返回Token给客户端后要求客户端在Http请求头里携带载有Jwt信息的Authorization对象。

    服务端会通过密钥对Jwt信息进行解密和验证,验证通过后会返回客户端所请求的资源。

    根据流程我们得知jwt至少依赖这几项:

    1、服务端的密钥;

    2、客户端请求需指定格式(请求头携带Token);

    其中密钥是客户端接触不到的,客户端所拥有的其实就是服务端生成的Token,这个Token是由三部分组成:

    1、Header(包含算法和Token的类型:jwt)

    2、PayLoad(负载,可配置的一些标识数据,不要将敏感信息写入到PayLoad内)

    3、验签

    其中Header和PayLoad只是在服务端进行了base64转码,所以如果有人抓取了Http请求是可以轻易截取里面的数据,我们

    使用过程中千万不要将一些敏感信息放置里面。想详细了解Jwt信息可以到官网看看,官网地址:https://jwt.io/

    .Net Core进行Jwt身份认证

    .NetCore上使用Jwt身份认证非常简单,我们在Startup.cs文件的ConfigureServices里加入以下代码:

     1   services.AddAuthentication(x =>
     2             {
     3                 x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
     4                 x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
     5             }).AddJwtBearer(x =>
     6             {
     7                 //获取权限是否需要HTTPS
     8                 x.RequireHttpsMetadata = false;
     9                 //在成功的授权之后令牌是否应该存储在Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties中
    10                 x.SaveToken = true;
    11                 
    12                 x.TokenValidationParameters = new TokenValidationParameters
    13                 {
    14                     //是否验证秘钥
    15                     ValidateIssuerSigningKey = true,
    16                     IssuerSigningKey = new SymmetricSecurityKey(key),
    17                     ValidateIssuer = false,
    18                     ValidateAudience = false
    19                 };
    20             });

    在Startup里的Configure方法必须添加下面这行代码,且要求写在 app.UseMvc();前面。

     app.UseAuthentication(); //引用身份认证服务

    上面的关键代码是Startup里的代码。 它明确告知系统采取Jwt验证方式为默认的身份认证方式、秘钥的

    生成方式,以及一些验证相关的参数配置。

    OK,现在我们已经明确了验证方式了,那我们创建Token是在哪里创建的呢?

    我们来看看下面代码:

     1         private TokenDto CreateToken(User user)
     2         {
     3             // JwtSecurityTokenHandler可以创建Token
     4             var tokenHandler = new JwtSecurityTokenHandler();
     5             var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
     6             DateTime tokenExpires = DateTime.Now.AddMinutes(3); //过期时间这里写死
     7             DateTime refRefreshTokenExpires = tokenExpires.AddMinutes(-1);
     8             var tokenDescriptor = new SecurityTokenDescriptor
     9             {
    10                 Subject = new ClaimsIdentity(new Claim[]
    11                 {
    12                     //添加申明,申明可以自定义,可以无限扩展,对于后续的身份验证通过后的授权特别有用...
    13                     new Claim(ClaimTypes.Name, user.Id.ToString()),
    14                     new Claim("refRefreshTokenExpires",refRefreshTokenExpires.ToString()),
    15                     new Claim("tokenExpires",tokenExpires.ToString())
    16                 }),
    17                 Expires = tokenExpires,
    18                 IssuedAt = DateTime.Now, //Token发布时间
    19                 Audience = "AuthTest", //接收令牌的受众
    20                 //根据配置文件的私钥值设置Token
    21                 SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
    22             };
    23             var token = tokenHandler.CreateToken(tokenDescriptor);
    24             user.Token = tokenHandler.WriteToken(token);
    25             TokenDto output = Mapper.Map<TokenDto>(user);
    26             output.RefRefreshToken = Guid.NewGuid().ToString();
    27             output.RefRefreshTokenExpires = refRefreshTokenExpires.ToString("yyyy-MM-dd HH:mm:ss");
    28             output.Token = user.Token;
    29             UserRefreshTokenData(user, output);
    30             return output;
    31         }

    上面代码是包含了 刷新Token和刷新Token时间的创建Token方法。 

    我在验证用户账号密码正确后即调用上面方法将Token返回给客户端,要求客户端在后续的API里必须携带Token来进行访问。

    Token的有效时间我在上面写死了为三分钟,即三分钟后访问需授权的接口都会报http响应码为401的错误,如果需要解决则

    要求客户端在刷新时间内,携带刷新Token值、刷新时间来调用 刷新Token接口获取 刷新后的Token值。

    刷新Token方法;

     1    public TokenDto RefreshToken(TokenDto oldTokenDto)
     2         {
     3             TokenDto output = new TokenDto();
     4             //如果有刷新Token值对应的用户则刷新Token以及RefRefreshToken
     5             var user = _users.FirstOrDefault(p => p.RefRefreshToken == oldTokenDto.RefRefreshToken
     6                                             && Convert.ToDateTime(oldTokenDto.RefRefreshTokenExpires) > DateTime.Now);
     7             if (user != null)
     8             {
     9                 output = CreateToken(user);
    10             }
    11             return output;
    12         }

    至此,.NetCore采取JWT验证身份方式就写好了,包含了刷新Token。

    对了,还没有总结JWT的劣势,劣势我捋了下面几点:

    1、没有一个很方便的撤销已颁发的JWT令牌方法;

    2、续签(刷新Token)增加了客户端的工作量(需要客户端在请求前验证刷新Token时间);

    3、Token的加密与解密是与开发者自定义的payload的大小有关,如果存储的东西越多自然执行的效率也会越低(建议存储少量信息);

    不过上面问题也不大,撤销令牌可以采取黑名单方式,至于第2点其实问题可以与前端约定好流程即可;

  • 相关阅读:
    微擎使用函数获取用户微信信息
    xshell连接不上linux情况一
    destoon手机端分页
    kvm安装win2012
    kvm安装ubuntu
    KVM的磁盘管理相关
    ubuntu的iptables
    kvm安装win2003
    Centos-6.4 安装mysql-5.5.14
    CentOS 6.4安装bind-9.8.2最新版(DNS服务器)
  • 原文地址:https://www.cnblogs.com/hunanzp/p/10177145.html
Copyright © 2020-2023  润新知