JWT有什么用?
在一次性使用场景下,比如:无状态的API、邮箱验证码等需要一定用户标识,但无法篡改,且只在一定时间内有效的操作。
安装NuGet包
Install-Package Microsoft.IdentityModel.Tokens
Install-Package System.IdentityModel.Tokens.Jwt
Install-Package Microsoft.AspNetCore.Authentication.JwtBearer
对JWT进行配置
- 在Startup中的ConfigureServices方法中注册服务
public void ConfigureServices(IServiceCollection services) { services.Configure<Configs>(Configuration);//注册配置 #region 注册 JWT身份认证 services.AddScoped<ITokenService, TokenService>(); //JWT加密 解密 var conf = Configuration.Get<Configs>(); var jwtOptions = conf.JwtOptions; services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(x => { byte[] keyBytes = Encoding.UTF8.GetBytes(jwtOptions.SecurityKey); var secKey = new SymmetricSecurityKey(keyBytes); x.TokenValidationParameters = new() { ValidateIssuer = false, ValidateAudience = false, ValidateLifetime = true, ValidateIssuerSigningKey = true, IssuerSigningKey = secKey }; }); #endregion }
- 在Startup中的Configure方法中
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { //路由中间件 app.UseRouting(); //需要在UseAuthentication之后再次UseAuthorization 否则,当你使用授权功能比如使用[Authorize]属性的时候系统就会报错 app.UseAuthentication(); //认证 app.UseAuthorization(); //授权 }
-
登录接口(AuthController)
/// <summary> /// 登录服务 /// </summary> [Route("api/[controller]/[action]")] [ApiController] public class AuthController : ControllerBase { private ITokenService _ITokenService = null; public AuthController(ITokenService tokenService) { this._ITokenService = tokenService; } [HttpGet] public IActionResult Login(string loginName = "demo", string loginPassword = "123456") { if (loginName == "demo" && loginPassword == "123456") { var tokenStr = _ITokenService.GetToken(loginName, loginPassword); return new JsonResult(new { code = 200, msg = "登录成功", data = tokenStr }); } else { return new JsonResult(new { code = 0, msg = "登录失败" }); } } }
-
校验登录(AdminController)
[Route("api/[controller]/[action]")] [ApiController] public class AdminController : ControllerBase { private ITokenService _ITokenService = null; public AdminController(ITokenService tokenService) { this._ITokenService = tokenService; } [HttpGet] [Authorize]//表示只有登录过的用户,拥有token的客户端才可以访问。用这个特性需要引入对应的命名空间 public IActionResult GetUserInfo() { var claims = HttpContext.User.Claims; var loginName = claims.Where(x => x.Type == "loginName").Select(x => x.Value).FirstOrDefault(); var loginPassword = claims.Where(x => x.Type == "loginPassword").Select(x => x.Value).FirstOrDefault(); var _model = new { loginName = loginName, loginPassword = loginPassword }; return new JsonResult(new { code = 200, msg = "登录成功", data = _model }); } }
其他源码
-
appsettings.json
{ "JwtOptions": { "Issuer": "http://localhost", "Audience": "http://localhost", "Expires": 3600, "SecurityKey": "1234567890123456" //长度有要求 16+ } }
-
Configs.cs
public class Configs { public JwtOption JwtOptions { get; set; } } public class JwtOption { /// <summary> /// jwt签发者 /// </summary> public string Issuer { get; set; } = "http://localhost"; /// <summary> /// 接收jwt的一方 /// </summary> public string Audience { get; set; } = "http://localhost"; /// <summary> /// jwt的过期时间 /// </summary> public int Expires { get; set; } = 3600; /// <summary> /// 秘钥 /// </summary> public string SecurityKey { get; set; } = "123456789012345"; }
-
ITokenService.cs和TokenService.cs
public interface ITokenService { string GetToken(string loginName, string loginPassword); Dictionary<string, string> DecodeToken(string token); }
public class TokenService : ITokenService { private readonly JwtOption _jwtOptions; public TokenService(IOptionsMonitor<Configs> configs ) { _jwtOptions = configs.CurrentValue.JwtOptions; } /// <summary> /// 根据账号密码生成 Token /// </summary> public string GetToken(string loginName, string loginPassword) { #region 有效载荷, 可以自己写,爱写多少写多少;尽量避免敏感信息 var cls = new[] { new Claim("loginName",loginName), new Claim("loginPassword",loginPassword), }; #endregion //加密 //依赖Nuget:Microsoft.IdentityModel.Tokens SymmetricSecurityKey key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtOptions.SecurityKey)); //签名 SigningCredentials creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); //依赖Nuget:System.IdentityModel.Tokens.Jwt var jwtSecurityToken = new JwtSecurityToken( issuer: _jwtOptions.Issuer,//jwt签发者 audience: _jwtOptions.Audience,//接收jwt的一方 //notBefore: DateTime.Now,//定义在什么时间之前,该jwt都是不可用的 expires: DateTime.Now.AddSeconds(_jwtOptions.Expires),//jwt的过期时间,这个过期时间必须要大于签发时间 claims: cls, signingCredentials: creds ); var token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken); return token; } /// <summary> /// 调用ValidateToken方法对JWT进行解密 /// </summary> /// <param name="jwtToken">jwt令牌</param> /// <returns></returns> public Dictionary<string, string> DecodeToken(string jwtToken) { string secKey = _jwtOptions.SecurityKey;//秘钥 JwtSecurityTokenHandler tokenHandler = new(); TokenValidationParameters valParam = new(); var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secKey)); valParam.IssuerSigningKey = securityKey; valParam.ValidateIssuer = false; valParam.ValidateAudience = false; // 调用ValidateToken方法对JWT进行解密 ClaimsPrincipal claimsPrincipal = tokenHandler.ValidateToken(jwtToken, valParam, out SecurityToken secToken); Dictionary<string, string> dic = new Dictionary<string, string>(); foreach (var claim in claimsPrincipal.Claims) { dic.Add(claim.Type, claim.Value); } return dic; } }