net core 3.1 jwt认证
- 首先在Visual Studio中创建一个WebApi项目;
- 引入nuget包:Microsoft.AspNetCore.Authentication.JwtBearer
- 在appsetting.json中配置jwt参数
"tokenConfig": {
"secret": "D96BFA5B-F2AF-45BC-9342-5A55C3F9BBB0",
"issuer": "test.cn",
"audience": "test",
"accessExpiration": 30,
"refreshExpiration": 60
}
- 编写对应的token对象:
using Newtonsoft.Json;
namespace JwtDemo
{
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; }
}
}
- 在Startup中配置启用token认证
using System.Text;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens;
using static JwtDemo.LoginRequestDTO;
namespace JwtDemo
{
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)
{
services.AddControllers();
services.Configure<TokenManagement>(Configuration.GetSection("tokenConfig"));
var token = Configuration.GetSection("tokenConfig").Get<TokenManagement>();
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(x =>
{
x.RequireHttpsMetadata = false;
x.SaveToken = true;
//Token Validation Parameters
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
//获取或设置要使用的Microsoft.IdentityModel.Tokens.SecurityKey用于签名验证。
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.
GetBytes(token.Secret)),
//获取或设置一个System.String,它表示将使用的有效发行者检查代币的发行者。
ValidIssuer = token.Issuer,
//获取或设置一个字符串,该字符串表示将用于检查的有效受众反对令牌的观众。
ValidAudience = token.Audience,
ValidateIssuer = false,
ValidateAudience = false,
};
});
services.AddScoped<IAuthenticateService, TokenAuthenticationService>();
services.AddScoped<IUserService, UserService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
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();
});
}
}
}
- 编写认证服务接口及服务类
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using System;
using System.ComponentModel.DataAnnotations;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
namespace JwtDemo
{
public interface IAuthenticateService
{
bool IsAuthenticated(LoginRequestDTO request, out string token);
}
public class LoginRequestDTO
{
[Required]
[JsonProperty("username")]
public string Username { get; set; }
[Required]
[JsonProperty("password")]
public string Password { get; set; }
/// <summary>
/// token认证服务
/// </summary>
public class TokenAuthenticationService : IAuthenticateService
{
private readonly IUserService _userService;
private readonly TokenManagement _tokenManagement;
public TokenAuthenticationService(IUserService userService, IOptions<TokenManagement> 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;
}
}
}
}
- 自定义认证接口及类IUserService和UserService,模拟验证密码的过程,这个需要在Startup中配置注入服务
namespace JwtDemo
{
public interface IUserService
{
bool IsValid(LoginRequestDTO req);
}
public class UserService : IUserService
{
//模拟测试,默认都是人为验证有效
public bool IsValid(LoginRequestDTO req)
{
return true;
}
}
}
- 添加AuthenticationController,用于根据用户名和密码获取token
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace JwtDemo.Controllers
{
[Route("api/[controller]")]
[ApiController]
public 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");
}
}
}
- 测试:测试之前先给WeatherForecastController加上[Authorize],身份验证之后才能访问
- 先访问https://localhost:44324/weatherforecast,结果为401,未授权,
- 下面请求token:
获取到token:
带token访问被保护的webapi:
通过学习了解了基本的jwt认证的使用方法
学会了在Fiddler中测试webapi
源码:https://gitee.com/Alexander360/LearnIdentity/tree/master/LearnIdentity