JWT签名与验签
簽名Token生產
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.Mvc; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens;namespace CoreTest.Controllers {public class TokenController : Controller{private ITokenHelper _tokenHelper = null;public TokenController(ITokenHelper tokenHelper){_tokenHelper = tokenHelper;}public IActionResult Index(string code, string pwd){User user = TemporaryData.GetUser(code);if (null != user && user.Password.Equals(pwd)){return Ok(_tokenHelper.CreateToken(user));}return BadRequest();}[HttpPost][Authorize]public IActionResult Index(){return Ok(_tokenHelper.RefreshToken(Request.HttpContext.User));}}public interface ITokenHelper{Token CreateAccessToken(User user);ComplexToken CreateToken(User user);ComplexToken CreateToken(Claim[] claims);Token RefreshToken(ClaimsPrincipal claimsPrincipal);}public class TokenHelper : ITokenHelper{private IOptions<JWTConfig> _options;public TokenHelper(IOptions<JWTConfig> options){_options = options;}public Token CreateAccessToken(User user){Claim[] claims = new Claim[] { new Claim(ClaimTypes.NameIdentifier, user.Code), new Claim(ClaimTypes.Name, user.Name) };return CreateToken(claims, TokenType.AccessToken);}public ComplexToken CreateToken(User user){Claim[] claims = new Claim[] { new Claim(ClaimTypes.NameIdentifier, user.Code), new Claim(ClaimTypes.Name, user.Name)//下面兩個Claim用于測試在Token中存儲用戶的角色信息,對應測試在FlyLolo.JWT.API的兩個測試Controller的Put方法,若用不到可刪除, new Claim(ClaimTypes.Role, "TestPutBookRole"), new Claim(ClaimTypes.Role, "TestPutStudentRole")};return CreateToken(claims);}public ComplexToken CreateToken(Claim[] claims){return new ComplexToken { AccessToken = CreateToken(claims, TokenType.AccessToken), RefreshToken = CreateToken(claims, TokenType.RefreshToken) };}/// <summary>/// 用于創建AccessToken和RefreshToken。/// 這里AccessToken和RefreshToken只是過期時間不同,【實際項目】中二者的claims內容可能會不同。/// 因為RefreshToken只是用于刷新AccessToken,其內容可以簡單一些。/// 而AccessToken可能會附加一些其他的Claim。/// </summary>/// <param name="claims"></param>/// <param name="tokenType"></param>/// <returns></returns>private Token CreateToken(Claim[] claims, TokenType tokenType){var now = DateTime.Now;var expires = now.Add(TimeSpan.FromMinutes(tokenType.Equals(TokenType.AccessToken) ? _options.Value.AccessTokenExpiresMinutes : _options.Value.RefreshTokenExpiresMinutes));//設置不同的過期時間var token = new JwtSecurityToken(issuer: _options.Value.Issuer,audience: tokenType.Equals(TokenType.AccessToken) ? _options.Value.Audience : _options.Value.RefreshTokenAudience,//設置不同的接受者 claims: claims,notBefore: now,expires: expires,signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_options.Value.IssuerSigningKey)), SecurityAlgorithms.HmacSha256));return new Token { TokenContent = new JwtSecurityTokenHandler().WriteToken(token), Expires = expires };}public Token RefreshToken(ClaimsPrincipal claimsPrincipal){var code = claimsPrincipal.Claims.FirstOrDefault(m => m.Type.Equals(ClaimTypes.NameIdentifier));if (null != code){return CreateAccessToken(TemporaryData.GetUser(code.Value.ToString()));}else{return null;}}}public class User{public string Code { get; set; }public string Name { get; set; }public string Password { get; set; }}public class Token{public string TokenContent { get; set; }public DateTime Expires { get; set; }}public enum TokenType{AccessToken = 1,RefreshToken = 2}public class ComplexToken{public Token AccessToken { get; set; }public Token RefreshToken { get; set; }}public class JWTConfig{public string Issuer { get; set; }public string Audience { get; set; }public string IssuerSigningKey { get; set; }public int AccessTokenExpiresMinutes { get; set; }public string RefreshTokenAudience { get; set; }public int RefreshTokenExpiresMinutes { get; set; }}public static class TemporaryData{private static List<User> Users = new List<User>(){new User { Code = "001", Name = "張三", Password = "111111" },new User { Code = "002", Name = "李四", Password = "222222" }};public static User GetUser(string code){return Users.FirstOrDefault(m => m.Code.Equals(code));}} }appsettings.json
{"Logging": {"LogLevel": {"Default": "Warning"}},"AllowedHosts": "*","JWT": {"Issuer": "FlyLolo","Audience": "TestAudience","IssuerSigningKey": "FlyLolo1234567890","AccessTokenExpiresMinutes": "30","RefreshTokenAudience": "RefreshTokenAudience","RefreshTokenExpiresMinutes": "10080"} }Startup.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using CoreTest.Controllers; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.HttpsPolicy; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens;namespace CoreTest {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.Configure<Controllers.UserInfo>(Configuration.GetSection("User"));services.AddSingleton<ITokenHelper, TokenHelper>();services.Configure<JWTConfig>(Configuration.GetSection("JWT"));JWTConfig config = new JWTConfig();Configuration.GetSection("JWT").Bind(config);services.AddAuthentication(options => {options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;}).AddJwtBearer(options => {options.TokenValidationParameters = new TokenValidationParameters{ValidIssuer = config.Issuer,ValidAudience = config.RefreshTokenAudience,IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config.IssuerSigningKey))};});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){if (env.IsDevelopment()){app.UseDeveloperExceptionPage();}else{// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts();}app.UseHttpsRedirection();app.UseAuthentication();app.UseMvc(route =>{route.MapRoute(name: "default",template: "{controller=Home}/{action=Index}/{id?}");});}} }Token驗證
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc;namespace ClientTest.Controllers {[Route("api/[controller]")][ApiController][Authorize]public class BookController : ControllerBase{// GET: api/<controller> [HttpGet][AllowAnonymous]public IEnumerable<string> Get(){return new string[] { "ASP", "C#" };}// POST api/<controller> [HttpPost]public JsonResult Post(){return new JsonResult("Create Book ...");}}public class JWTConfig{public string Issuer { get; set; }public string Audience { get; set; }public string IssuerSigningKey { get; set; }public int AccessTokenExpiresMinutes { get; set; } } }appsettings.json
{"Logging": {"LogLevel": {"Default": "Warning"}},"AllowedHosts": "*","JWT": {"Issuer": "FlyLolo","Audience": "TestAudience","IssuerSigningKey": "FlyLolo1234567890","AccessTokenExpiresMinutes": "30"} }Startup.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using ClientTest.Controllers; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.HttpsPolicy; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens;namespace ClientTest {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){#region 讀取配置JWTConfig config = new JWTConfig();Configuration.GetSection("JWT").Bind(config);#endregion#region 啟用JWT認證services.AddAuthentication(options =>{options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;}).AddJwtBearer(options =>{options.TokenValidationParameters = new TokenValidationParameters{ValidIssuer = config.Issuer,ValidAudience = config.Audience,IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config.IssuerSigningKey)),ClockSkew = TimeSpan.FromMinutes(1)};});#endregionservices.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){if (env.IsDevelopment()){app.UseDeveloperExceptionPage();}else{// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts();}app.UseHttpsRedirection();app.UseAuthentication();app.UseMvc();}} }?
轉載于:https://www.cnblogs.com/huangzelin/p/11475191.html
總結
- 上一篇: P1541 乌龟棋
- 下一篇: P1016 旅行家的预算