属于网络营销站点推广的是,自媒体平台怎么注册,WordPress 发布内容,wordpress 3.9 友情链接JWT认证简单介绍关于Jwt的介绍网上很多#xff0c;此处不在赘述#xff0c;我们主要看看jwt的结构。JWT主要由三部分组成#xff0c;如下#xff1a;HEADER.PAYLOAD.SIGNATUREHEADER包含token的元数据#xff0c;主要是加密算法#xff0c;和签名的类型#xff0c;如下面… JWT认证简单介绍 关于Jwt的介绍网上很多此处不在赘述我们主要看看jwt的结构。 JWT主要由三部分组成如下HEADER.PAYLOAD.SIGNATURE HEADER包含token的元数据主要是加密算法和签名的类型如下面的信息说明了加密的对象类型是JWT加密算法是HMAC SHA-256{alg:HS256,typ:JWT} 然后需要通过BASE64编码后存入token中eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 Payload主要包含一些声明信息claim这些声明是key-value对的数据结构。通常如用户名角色等信息过期日期等因为是未加密的所以不建议存放敏感信息。{http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name:admin,exp:1578645536,iss:webapi.cn,aud:WebApi}也需要通过BASE64编码后存入token中eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiYWRtaW4iLCJleHAiOjE1Nzg2NDU1MzYsImlzcyI6IndlYmFwaS5jbiIsImF1ZCI6IldlYkFwaSJ9 Signaturejwt要符合jws(Json Web Signature)的标准生成一个最终的签名。把编码后的Header和Payload信息加在一起然后使用一个强加密算法如 HmacSHA256进行加密。HS256(BASE64(Header).Base64(Payload)secret)2_akEH40LR2QWekgjm8Tt3lesSbKtDethmJMo_3jpF4 最后生成的token如下eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiYWRtaW4iLCJleHAiOjE1Nzg2NDU1MzYsImlzcyI6IndlYmFwaS5jbiIsImF1ZCI6IldlYkFwaSJ9.2_akEH40LR2QWekgjm8Tt3lesSbKtDethmJMo_3jpF4 开发环境框架asp.net 3.1IDEVS2019ASP.NET 3.1 Webapi中使用JWT认证 命令行中执行执行以下命令创建webapix项目dotnet new webapi -n Webapi -o WebApi 特别注意的时3.x默认是没有jwt的Microsoft.AspNetCore.Authentication.JwtBearer库的所以需要手动添加NuGet Package切换到项目所在目录执行 .net cli命令dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer --version 3.1.0 创建一个简单的POCO类用来存储签发或者验证jwt时用到的信息using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;namespace Webapi.Models{public class TokenManagement{[JsonProperty(secret)]public string Secret { get; set; }[JsonProperty(issuer)]public string Issuer { get; set; }[JsonProperty(audience)]public string Audience { get; set; }[JsonProperty(accessExpiration)]public int AccessExpiration { get; set; }[JsonProperty(refreshExpiration)]public int RefreshExpiration { get; set; }}
} 然后在 appsettings.Development.json 增加jwt使用到的配置信息如果是生成环境在appsettings.json添加即可tokenManagement: {secret: 123456,issuer: webapi.cn,audience: WebApi,accessExpiration: 30,refreshExpiration: 60} 然后再startup类的ConfigureServices方法中增加读取配置信息public void ConfigureServices(IServiceCollection services){services.AddControllers();services.ConfigureTokenManagement(Configuration.GetSection(tokenManagement));var token Configuration.GetSection(tokenManagement).GetTokenManagement();} 到目前为止我们完成了一些基础工作下面再webapi中注入jwt的验证服务并在中间件管道中启用authentication中间件。 startup类中要引用jwt验证服务的命名空间using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens; 然后在ConfigureServices方法中添加如下逻辑services.AddAuthentication(x {x.DefaultAuthenticateScheme JwtBearerDefaults.AuthenticationScheme;x.DefaultChallengeScheme JwtBearerDefaults.AuthenticationScheme;}).AddJwtBearer(x {x.RequireHttpsMetadata false;x.SaveToken true;x.TokenValidationParameters new TokenValidationParameters{ValidateIssuerSigningKey true,IssuerSigningKey new SymmetricSecurityKey(Encoding.ASCII.GetBytes(token.Secret)),ValidIssuer token.Issuer,ValidAudience token.Audience,ValidateIssuer false,ValidateAudience false};}); 再Configure方法中启用验证public void Configure(IApplicationBuilder app, IWebHostEnvironment env){if (env.IsDevelopment()){app.UseDeveloperExceptionPage();}app.UseHttpsRedirection();app.UseAuthentication();app.UseRouting();app.UseAuthorization();app.UseEndpoints(endpoints {endpoints.MapControllers();});} 上面完成了JWT验证的功能下面就需要增加签发token的逻辑。我们需要增加一个专门用来用户认证和签发token的控制器命名成AuthenticationController同时增加一个请求的DTO类public class LoginRequestDTO{[Required][JsonProperty(username)]public string Username { get; set; }[Required][JsonProperty(password)]public string Password { get; set; }}[Route(api/[controller])][ApiController]public class AuthenticationController : ControllerBase{[AllowAnonymous][HttpPost, Route(requestToken)]public ActionResult RequestToken([FromBody] LoginRequestDTO request){if (!ModelState.IsValid){return BadRequest(Invalid Request);}return Ok();}} 目前上面的控制器只实现了基本的逻辑下面我们要创建签发token的服务去完成具体的业务。第一步我们先创建对应的服务接口命名为IAuthenticateServicepublic interface IAuthenticateService{bool IsAuthenticated(LoginRequestDTO request, out string token);} 接下来实现接口public class TokenAuthenticationService : IAuthenticateService{public bool IsAuthenticated(LoginRequestDTO request, out string token){throw new NotImplementedException();}} 在Startup的ConfigureServices方法中注册服务services.AddScopedIAuthenticateService, TokenAuthenticationService(); 在Controller中注入IAuthenticateService服务并完善actionpublic class AuthenticationController : ControllerBase{private readonly IAuthenticateService _authService;public AuthenticationController(IAuthenticateService authService){this._authService authService;}[AllowAnonymous][HttpPost, Route(requestToken)]public ActionResult RequestToken([FromBody] LoginRequestDTO request){if (!ModelState.IsValid){return BadRequest(Invalid Request);}string token;if (_authService.IsAuthenticated(request, out token)){return Ok(token);}return BadRequest(Invalid Request);}} 正常情况我们都会根据请求的用户和密码去验证用户是否合法需要连接到数据库获取数据进行校验我们这里为了方便假设任何请求的用户都是合法的。 这里单独加个用户管理的服务不在IAuthenticateService这个服务里面添加相应逻辑主要遵循了职责单一原则。首先和上面一样创建一个服务接口IUserServicepublic interface IUserService{bool IsValid(LoginRequestDTO req);} 实现IUserService接口public class UserService : IUserService{//模拟测试默认都是人为验证有效public bool IsValid(LoginRequestDTO req){return true;}} 同样注册到容器中services.AddScopedIUserService, UserService(); 接下来就要完善TokenAuthenticationService签发token的逻辑首先要注入IUserService 和 TokenManagement然后实现具体的业务逻辑这个token的生成还是使用的Jwt的类库提供的api具体不详细描述。特别注意下TokenManagement的注入是已IOptions的接口类型注入的还记得在Startpup中吗我们是通过配置项的方式注册TokenManagement类型的。 public class TokenAuthenticationService : IAuthenticateService{private readonly IUserService _userService;private readonly TokenManagement _tokenManagement;public TokenAuthenticationService(IUserService userService, IOptionsTokenManagement tokenManagement){_userService userService;_tokenManagement tokenManagement.Value;}public bool IsAuthenticated(LoginRequestDTO request, out string token){token string.Empty;if (!_userService.IsValid(request))return false;var claims new[]{new Claim(ClaimTypes.Name,request.Username)};var key new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_tokenManagement.Secret));var credentials new SigningCredentials(key, SecurityAlgorithms.HmacSha256);var jwtToken new JwtSecurityToken(_tokenManagement.Issuer, _tokenManagement.Audience, claims, expires: DateTime.Now.AddMinutes(_tokenManagement.AccessExpiration), signingCredentials: credentials);token new JwtSecurityTokenHandler().WriteToken(jwtToken);return true;}} 准备好测试试用的APi打上Authorize特性表明需要授权[ApiController][Route([controller])][Authorize]public class WeatherForecastController : ControllerBase{private static readonly string[] Summaries new[]{Freezing, Bracing, Chilly, Cool, Mild, Warm, Balmy, Hot, Sweltering, Scorching};private readonly ILoggerWeatherForecastController _logger;public WeatherForecastController(ILoggerWeatherForecastController logger){_logger logger;}[HttpGet]public IEnumerableWeatherForecast Get(){var rng new Random();return Enumerable.Range(1, 5).Select(index new WeatherForecast{Date DateTime.Now.AddDays(index),TemperatureC rng.Next(-20, 55),Summary Summaries[rng.Next(Summaries.Length)]}).ToArray();}} 支持我们可以测试验证了我们可以使用postman来进行http请求先启动http服务获取url先测试一个访问需要授权的接口但没有携带token信息返回是401表示未授权 下面我们先通过认证接口获取token居然报错查询了下发现HS256算法的秘钥长度最新为128位转换成字符至少16字符之前设置的秘钥是123456所以导致异常。System.ArgumentOutOfRangeException: IDX10603: Decryption failed. Keys tried: HS256. Exceptions caught: 128. token: 48 (Parameter KeySize) at 更新秘钥 tokenManagement: {secret: 123456123456123456,issuer: webapi.cn,audience: WebApi,accessExpiration: 30,refreshExpiration: 60} 重新发起请求成功获取tokeneyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiYWRtaW4iLCJleHAiOjE1Nzg2NDUyMDMsImlzcyI6IndlYmFwaS5jbiIsImF1ZCI6IldlYkFwaSJ9.AehD8WTAnEtklof2OJsvg0U4_o8_SjdxmwUjzAiuI-o 把token带到之前请求的api中重新测试成功获取数据总结 基于token的认证方式让我们构建分布式/松耦合的系统更加容易。任何地方生成的token只有拥有相同秘钥就可以再任何地方进行签名校验。 当然要用好jwt认证方式还有其他安全细节需要处理比如palyload中不能存放敏感信息使用https的加密传输方式等等可以根据业务实际需要再进一步安全加固 同时我们也发现使用token就可以摆脱cookie的限制所以JWT是移动app开发的首选