最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 科技 - 知识百科 - 正文

asp.net core集成JWT的步骤记录

来源:动视网 责编:小采 时间:2020-11-27 14:43:04
文档

asp.net core集成JWT的步骤记录

asp.net core集成JWT的步骤记录:【什么是JWT】 JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案。 JWT的官网地址:https://jwt.io/ 通俗地来讲,JWT是能代表用户身份的令牌,可以使用JWT令牌在api接口中校验用户的身份以确认用户是否有访问api的权限。 JWT中包含了身份认证
推荐度:
导读asp.net core集成JWT的步骤记录:【什么是JWT】 JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案。 JWT的官网地址:https://jwt.io/ 通俗地来讲,JWT是能代表用户身份的令牌,可以使用JWT令牌在api接口中校验用户的身份以确认用户是否有访问api的权限。 JWT中包含了身份认证


【什么是JWT】

JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案。

JWT的官网地址:https://jwt.io/

通俗地来讲,JWT是能代表用户身份的令牌,可以使用JWT令牌在api接口中校验用户的身份以确认用户是否有访问api的权限。

JWT中包含了身份认证必须的参数以及用户自定义的参数,JWT可以使用秘密(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对进行签名。

【什么时候应该使用JSON Web令牌?】

授权:这是使用JWT的最常见方案。一旦用户登录,每个后续请求将包括JWT,允许用户访问该令牌允许的路由,服务和资源。Single Sign On是一种现在广泛使用JWT的功能,因为它的开销很小,并且能够在不同的域中轻松使用。

信息交换:JSON Web令牌是在各方之间安全传输信息的好方法。因为JWT可以签名 - 例如,使用公钥/私钥对 - 您可以确定发件人是他们所说的人。此外,由于使用标头和有效负载计算签名,您还可以验证内容是否未被篡改。

【JWT有什么优势?】  

  1. 用户向服务器发送用户名和密码。
  2. 服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色、登录时间等等。
  3. 服务器向用户返回一个 session_id,写入用户的 Cookie。
  4. 用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。
  5. 服务器收到 session_id,找到前期保存的数据,由此得知用户的身份。

  这种模式的问题在于,扩展性(scaling)不好。单机当然没有问题,如果是服务器集群,或者是跨域的服务导向架构,就要求 session 数据共享,每台服务器都能够读取 session。如果session存储的节点挂了,那么整个服务都会瘫痪,体验相当不好,风险也很高。

  相比之下,JWT的实现方式是将用户信息存储在客户端,服务端不进行保存。每次请求都把令牌带上以校验用户登录状态,这样服务就变成了无状态的,服务器集群也很好扩展。

【JWT令牌结构】

在紧凑的形式中,JSON Web Tokens由dot(.)分隔的三个部分组成,它们是:

  • Header 头
  • Payload 有效载荷
  • Signature 签名
  • 因此,JWT通常如下所示:

      xxxxx.yyyyy.zzzzz

    1.Header 头

    标头通常由两部分组成:令牌的类型,即JWT,以及正在使用的签名算法,例如HMAC SHA256或RSA。

    例如:

    {
     "alg": "HS256",
     "typ": "JWT"
    }

    然后,这个JSON被编码为BaseUrl,形成JWT的第一部分。

    2.Payload有效载荷

    Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。JWT 规定了7个官方字段,供选用。

  • iss (issuer):签发人
  • exp (expiration time):过期时间
  • sub (subject):主题
  • aud (audience):受众
  • nbf (Not Before):生效时间
  • iat (Issued At):签发时间
  • jti (JWT ID):编号
  • 除了官方字段,你还可以在这个部分定义私有字段,下面就是一个例子。例如:

    {
     "sub": "12345670",
     "name": "John Doe",
     "admin": true
    }

    注意,JWT 默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分。这个 JSON 对象也要使用 BaseURL 算法转成字符串。

    3.Signature 签名

    Signature 部分是对前两部分的签名,防止数据篡改。

    首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。

    HMACSHA256(
     baseUrlEncode(header) + "." +
     baseUrlEncode(payload),
     secret)

    签名用于验证消息在此过程中未被更改,并且,在使用私钥签名的令牌的情况下,它还可以验证JWT的发件人是否是它所声称的人。  

    把他们三个全部放在一起

    输出是三个由点分隔的Base-URL字符串,可以在HTML和HTTP环境中轻松传递,而与基于XML的标准(如SAML)相比更加紧凑。

    下面显示了一个JWT,它具有先前的头和​​有效负载编码,并使用机密签名。

    如果您想使用JWT并将这些概念付诸实践,您可以使用jwt.io Debugger来解码,验证和生成JWT。

    【JSON Web令牌如何工作?】

    在身份验证中,当用户使用其凭据成功登录时,将返回JSON Web令牌。由于令牌是凭证,因此必须非常小心以防止出现安全问题。一般情况下,您不应该将令牌保留的时间超过要求。

    每当用户想要访问受保护的路由或资源时,用户代理应该使用承载模式发送JWT,通常在Authorization标头中。标题的内容应如下所示:

    Authorization: Bearer <token>

    在某些情况下,这可以是无状态授权机制。服务器的受保护路由将检查Authorization标头中的有效JWT,如果存在,则允许用户访问受保护资源。如果JWT包含必要的数据,则可以减少查询数据库以进行某些操作的需要,尽管可能并非总是如此。

    如果在标Authorization头中发送令牌,则跨域资源共享(CORS)将不会成为问题,因为它不使用cookie。

    下图显示了如何获取JWT并用于访问API或资源:

    应用程序向授权服务器请求授权校验用户身份,校验成功,返回token应用程序使用访问令牌访问受保护的资源【ASP.Net Core 集成JWT】

    前面我们介绍了JWT的原理,下面我们在asp.net core实际项目中集成JWT。

    首先我们新建一个Demo asp.net core 空web项目

    添加数据访问模拟api,ValuesController

    其中api/value1是可以直接访问的,api/value2添加了权限校验特性标签 [Authorize]

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    
    namespace Demo.Jwt.Controllers
    {
     [ApiController]
     public class ValuesController : ControllerBase
     {
     [HttpGet]
     [Route("api/value1")]
     public ActionResult<IEnumerable<string>> Get()
     {
     return new string[] { "value1", "value1" };
     }
    
     [HttpGet]
     [Route("api/value2")]
     [Authorize]
     public ActionResult<IEnumerable<string>> Get2()
     {
     return new string[] { "value2", "value2" };
     }
     }
    }

    添加模拟登陆,生成Token的api,AuthController

    这里模拟一下登陆校验,只验证了用户密码不为空即通过校验,真实环境完善校验用户和密码的逻辑。

    using System;
    using System.Collections.Generic;
    using System.IdentityModel.Tokens.Jwt;
    using System.Linq;
    using System.Security.Claims;
    using System.Text;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.IdentityModel.Tokens;
    
    namespace Demo.Jwt.Controllers
    {
     [Route("api/[controller]")]
     [ApiController]
     public class AuthController : ControllerBase
     {
     [AllowAnonymous]
     [HttpGet]
     public IActionResult Get(string userName, string pwd)
     {
     if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(pwd))
     {
     var claims = new[]
     {
     new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}") ,
     new Claim (JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddMinutes(30)).ToUnixTimeSeconds()}"),
     new Claim(ClaimTypes.Name, userName)
     };
     var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Const.SecurityKey));
     var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
     var token = new JwtSecurityToken(
     issuer: Const.Domain,
     audience: Const.Domain,
     claims: claims,
     expires: DateTime.Now.AddMinutes(30),
     signingCredentials: creds);
    
     return Ok(new
     {
     token = new JwtSecurityTokenHandler().WriteToken(token)
     });
     }
     else
     {
     return BadRequest(new { message = "username or password is incorrect." });
     }
     }
     }
    }

    Startup添加JWT验证的相关配置

    using Microsoft.AspNetCore.Authentication.JwtBearer;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.IdentityModel.Tokens;
    using System;
    using System.Text;
    
    
    namespace Demo.Jwt
    {
     public class Startup
     {
     public Startup(IConfiguration configuration)
     {
     Configuration = configuration;
     }
    
     public IConfiguration Configuration { get; }
    
     // This method gets called by the runtime. Use this method to add services to the container.
     public void ConfigureServices(IServiceCollection services)
     {
     //添加jwt验证:
     services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
     .AddJwtBearer(options => {
     options.TokenValidationParameters = new TokenValidationParameters
     {
     ValidateIssuer = true,//是否验证Issuer
     ValidateAudience = true,//是否验证Audience
     ValidateLifetime = true,//是否验证失效时间
     ClockSkew = TimeSpan.FromSeconds(30),
     ValidateIssuerSigningKey = true,//是否验证SecurityKey
     ValidAudience = Const.Domain,//Audience
     ValidIssuer = Const.Domain,//Issuer,这两项和前面签发jwt的设置一致
     IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Const.SecurityKey))//拿到SecurityKey
     };
     });
    
     services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
     }
    
     // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
     public void Configure(IApplicationBuilder app, IHostingEnvironment env)
     {
     ///添加jwt验证
     app.UseAuthentication();
    
     if (env.IsDevelopment())
     {
     app.UseDeveloperExceptionPage();
     }
    
     app.UseMvc(routes =>
     {
     routes.MapRoute(
     name: "default",
     template: "{controller=Home}/{action=Index}/{id?}");
     });
     }
     }
    }

    最后把代码里面用到的一些相关常量也粘贴过来,Const.cs

    namespace Demo.Jwt
    {
     public class Const
     {
     /// <summary>
     /// 这里为了演示,写死一个密钥。实际生产环境可以从配置文件读取,这个是用网上工具随便生成的一个密钥
     /// </summary>
     public const string SecurityKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDI2a2EJ7m872v0afyoSDJT2o1+SitIeJSWtLJU8/Wz2m7gStexajkeD+Lka6DSTy8gt9UwfgVQo6uKjVLG5Ex7PiGOODVqAEghBuS7JzIYU5RvI543nNDAPfnJsas96mSA7L/mD7RTE2drj6hf3oZjJpMPZUQI/B1Qjb5H3K3PNwIDAQAB";
     public const string Domain = "http://localhost:5000";
     }
    }

    到这里,已经是我们项目的所有代码了。

    如果需要完整的项目代码,Github地址:https://github.com/sevenTiny/Demo.Jwt

    【JWT测试】

    我们找一个趁手的工具,比如fiddler,然后把我们的web站点运行起来

    首先调用无权限的接口:http://localhost:5000/api/value1

    正确地返回了数据,那么接下来我们测试JWT的流程

    1. 无权限

    首先我们什么都不加调用接口:http://localhost:5000/api/value2

    返回了状态码401,也就是未经授权:访问由于凭据无效被拒绝。 说明JWT校验生效了,我们的接口收到了保护。

    2.获取Token

    调用模拟登陆授权接口:http://localhost:5000/api/Auth?userName=zhangsan&pwd=123

    这里的用户密码是随便写的,因为我们模拟登陆只是校验了下非空,因此写什么都能通过

    成功得到了响应

    然后我们得到了一个xxx.yyy.zzz 格式的 token 值。我们把token复制出来

    3.在刚才401的接口请求HEADER中添加JWT的参数,把我们的token加上去

    再次调用我们的模拟数据接口,但是这次我们加了一个HEADER:http://localhost:5000/api/value2

    把内容粘出来

    User-Agent: Fiddler
    Host: localhost:5000
    Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOiIxNTYwMzQ1MDIxIiwiZXhwIjoxNTYwMzQ2ODIxLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiemhhbmdzYW4iLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjUwMDAiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjUwMDAifQ.x7Slk4ho1hZc8sR8_McVTB6VEYLz_v-5eaHvXtIDS-o

    这里需要注意Bearer 后面是有一个空格的,然后就是我们上一步获取到的token

    嗯,没有401了,成功返回了数据

    4.JWT的Token过期

    我们且倒一杯开水,坐等30分钟(我们代码中设置的过期时间),然后再次调用数据接口:http://localhost:5000/api/value2

    又变成了401,我们看下详细的返回数据

    这里有标注,错误描述 token过期,说明我们设置的token过期时间生效了

    【结束】

    到这里,我们JWT的简介以及asp.net core 集成JWT已经完美完成,当然了这只是一个demo,在实际的应用中需要补充和完善的地方还有很多。

    如果想要完整项目源码的,可以参考地址:https://github.com/sevenTiny/Demo.Jwt

    如果有幸能帮助到你,高抬贵手点个star吧~

    总结

    文档

    asp.net core集成JWT的步骤记录

    asp.net core集成JWT的步骤记录:【什么是JWT】 JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案。 JWT的官网地址:https://jwt.io/ 通俗地来讲,JWT是能代表用户身份的令牌,可以使用JWT令牌在api接口中校验用户的身份以确认用户是否有访问api的权限。 JWT中包含了身份认证
    推荐度:
    标签: 使用 过程 net
    • 热门焦点

    最新推荐

    猜你喜欢

    热门推荐

    专题
    Top