本文共 6659 字,大约阅读时间需要 22 分钟。
JWT介绍就太多了,这里主要关注下Jwt的结构。
Jwt中包含三个部分:Header(头部).Payload(负载).Signature(签名)
Header:描述 JWT 的元数据的JSON对象,如:
{"alg":"HS256","typ":"JWT"}
Payload:一个用来存放实际需要传递的数据的JSON 对象。如:
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name": "admin", "exp": 1610877510, "iss": "cba", "aud": "cba"}
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
JWT示例:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiYWRtaW4iLCJleHAiOjE2MTA4Nzc1MTAsImlzcyI6ImNiYSIsImF1ZCI6ImNiYSJ9.O9lbZwfqRuA6vKcRCfYieA1zLkTPppdSvTc8UzwCkNw
1、添加Nuget包引用:
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
2、定义一个JwtSettingDto结构,用于读取JWT配置信息
public class JwtSetting{ /// <summary> /// 发行者 /// </summary> public string Issuer { get; set; } /// <summary> /// 受众 /// </summary> public string Audience { get; set; } /// <summary> /// 秘钥 /// </summary> public string SecretKey { get; set; } /// <summary> /// 过期时间 /// </summary> public int AccessExpiration { get; set; } /// <summary> /// 刷新时间 /// </summary> public int RefreshExpiration { get; set; }}
3、在appsetting.json配置文件中,添加jwt相关配置信息
"JWTSetting": { "Issuer": "cba", "Audience": "cba", "SecretKey": "123456789abcdefghi", "AccessExpiration": 60, "RefreshExpiration": 80 }
4、在Startup.cs 中启用Jwt认证
public void ConfigureServices(IServiceCollection services){ services.Configure<JwtSetting>(Configuration.GetSection("JWTSetting")); var token = Configuration.GetSection("JWTSetting").Get<JwtSetting>(); //JWT认证 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.SecretKey)), ValidIssuer = token.Issuer, ValidAudience = token.Audience, ValidateIssuer = false, ValidateAudience = false }; });}// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.public void Configure(IApplicationBuilder app, IWebHostEnvironment env){ app.UseAuthentication(); app.UseAuthorization();}
5、实现认证控制器:
a) 添加认证Dto
public class LoginDto{ [Required] public string Username { get; set; } [Required] public string Password { get; set; }}
b) 实现用户校验服务:默认实现:当用户密码都等于admin通过校验
public interface IUserService{ bool IsValid(LoginDto request);}public class UserService : IUserService{ //本次,固定校验admin public bool IsValid(LoginDto request) { return request.Password == request.Username && request.Username == "admin"; }}
c) 实现签发token的认证服务:
//认证服务接口
public interface IAuthenticateService{ bool IsAuthenticated(LoginDto request, out string token);}//认证服务public class TokenAuthenticationService : IAuthenticateService{ private readonly IUserService _userService; private readonly JwtSetting _jwtSetting; public TokenAuthenticationService(IUserService userService, IOptions<JwtSetting> jwtSetting) { _userService = userService; _jwtSetting = jwtSetting.Value; } public bool IsAuthenticated(LoginDto 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(_jwtSetting.SecretKey)); var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var jwtToken = new JwtSecurityToken(_jwtSetting.Issuer, _jwtSetting.Audience, claims, expires: DateTime.Now.AddMinutes(_jwtSetting.AccessExpiration), signingCredentials: credentials); token = new JwtSecurityTokenHandler().WriteToken(jwtToken); return true; }}
d) 添加认证控制器
[Route("api/[controller]")][ApiController]public class AuthenticationController : ControllerBase{ private IAuthenticateService _authService; public AuthenticationController(IAuthenticateService authService) { _authService = authService; } [AllowAnonymous] [HttpPost, Route("RequestToken")] public ActionResult RequestToken([FromBody] LoginDto request) { if (!ModelState.IsValid) { return BadRequest("Invalid Request"); } string token; if (_authService.IsAuthenticated(request, out token)) { return Ok(token); } return BadRequest("Invalid Request"); }}
6、注入服务:TokenAuthenticationService 、UserService
services.AddScoped<IUserService, UserService>();services.AddScoped<IAuthenticateService, TokenAuthenticationService>();
7、添加测试控制器:
[Authorize][Route("api/[controller]")][ApiController]public class AuditLogController : ControllerBase{ // GET: api/<AuditLogController> [HttpGet] public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; }}
到此Jwt认证在.net core中已经实现,接下来验证下运行效果
1、请求AuditLog接口:api/AuditLog未传入认证信息时:
2、获取Token:
3、添加token调用接口:
在项目中通常都添加了Swagger UI来展示接口及基础测试,那么如果添加了认证后,如何在调用接口前添加认证信息呢?
在Startup中:ConfigureServices中添加Swagger设置时,添加认证设置
//注册Swagger生成器,定义一个和多个Swagger 文档services.AddSwaggerGen(c =>{ c.SwaggerDoc("v1", new OpenApiInfo { Title = "AuditLogDemo API", Version = "v1" }); #region 启用swagger验证功能 //添加一个必须的全局安全信息,和AddSecurityDefinition方法指定的方案名称一致即可。 c.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }, new string[] { } } }); c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { Description = "JWT授权(数据将在请求头中进行传输) 在下方输入Bearer {token} 即可,注意两者之间有空格", Name = "Authorization",//jwt默认的参数名称 In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中) Type = SecuritySchemeType.ApiKey, BearerFormat = "JWT", Scheme = "Bearer", }); #endregion});
运行效果: 添加token->调用需认证接口
源码地址:https://github.com/cwsheng/AuditLogDemo.git
转载地址:http://ddwuz.baihongyu.com/