用到的命名空间
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
生成TOKEN
方法
[HttpGet("auth")]
public IActionResult Get(Tmodel mod)
{
if (mod.user == "AngelaDaddy" && mod.pass == "123456")
{
// push the user’s name into a claim, so we can identify the user later on.
var claims = new[]
{
new Claim(ClaimTypes.Name, mod.user),
new Claim(ClaimTypes.Role, "useradmin"),
new Claim(ClaimTypes.SerialNumber, "123123123"),
new Claim(ClaimTypes.Role, "useradmin1"),
new Claim(ClaimTypes.Role, "useradmin2"),
new Claim(ClaimTypes.Role, "useradmin3"),
new Claim(ClaimTypes.Name, mod.user + "1"),
new Claim(ClaimTypes.Name, mod.user + "2"),
new Claim(ClaimTypes.Name, mod.user + "3")
};
//sign the token using a secret key.This secret will be shared between your API and anything that needs to check that the token is legit.
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["SecurityKey"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
//.NET Core’s JwtSecurityToken class takes on the heavy lifting and actually creates the token.
/**
* Claims (Payload)
Claims 部分包含了一些跟这个 token 有关的重要信息。 JWT 标准规定了一些字段,下面节选一些字段:
iss: The issuer of the token,token 是给谁的 发送者
audience: 接收的
sub: The subject of the token,token 主题
exp: Expiration Time。 token 过期时间,Unix 时间戳格式
iat: Issued At。 token 创建时间, Unix 时间戳格式
jti: JWT ID。针对当前 token 的唯一标识
除了规定的字段外,可以包含其他任何 JSON 兼容的字段。
* */
var token = new JwtSecurityToken(
issuer: "jwttest",
audience: "jwttest",
claims: claims,
notBefore: DateTime.UtcNow,
expires: DateTime.UtcNow.AddSeconds(10),
signingCredentials: creds);
return Ok(new
{
token = new JwtSecurityTokenHandler().WriteToken(token)
});
}
return BadRequest("用户名密码错误");
}
new Claim
时,可以设置失效时间 JwtRegisteredClaimNames.Exp
,值为Unix
时间戳
认证时需要添加生命周期校验
LifetimeValidator = (DateTime? notBefore, DateTime? expires, SecurityToken securityToken, TokenValidationParameters validationParameters) => expires > DateTime.UtcNow
var d = securityToken as JwtSecurityToken
var res1 = d.Claims.Where(s => s.Type == ClaimTypes.Role && s.Value == "useradmin2").Count()
生成Token
时
var token = new JwtSecurityToken(
issuer: "jwttest",
audience: "jwttest",
claims: claims,
notBefore: DateTime.Now,
expires: DateTime.Now.AddSeconds(30),
signingCredentials: creds);
失效时间可以为本地时间或UTC
时间
//添加jwt验证:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,//是否验证Issuer
ValidateAudience = true,//是否验证Audience
ValidateLifetime = false,//是否验证失效时间
ValidateIssuerSigningKey = true,//是否验证SecurityKey
ValidAudience = "jwttest",//Audience
ValidIssuer = "jwttest",//Issuer,这两项和前面签发jwt的设置一致
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["SecurityKey"])),//拿到SecurityKey
LifetimeValidator = (DateTime? notBefore, DateTime? expires, SecurityToken securityToken, TokenValidationParameters validationParameters) => expires > DateTime.UtcNow
//LifetimeValidator = (DateTime? notBefore, DateTime? expires, SecurityToken securityToken, TokenValidationParameters validationParameters) =>
//{
// var d = securityToken as JwtSecurityToken;
// var res1 = d.Claims.Where(s => s.Type == ClaimTypes.Role && s.Value == "useradmin2").Count();
// var res2 = d.Claims.Where(s => s.Type == ClaimTypes.Role && s.Value == "useradmin3").Count();
// var res3 = d.Claims.Where(s => s.Type == ClaimTypes.Name && s.Value == "useradmin2").Count();
// var res4 = d.Claims.Where(s => s.Type == ClaimTypes.Role && s.Value == "useradmin8").Count();
// return expires > DateTime.UtcNow;
//}
};
});
生成TOKEN
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using IdentityModel;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
[HttpGet("token")]
public ActionResult<string> Token(InputData inputData)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.UTF8.GetBytes("1111111111");
var authTime = DateTime.UtcNow;
var expiresAt = authTime.AddSeconds(3000);
第一种
//var token = new JwtSecurityToken(
// issuer: "发送者(TokenCreate)",
// audience: "接收者(TokenServer)",
// claims: new Claim[]
// {
// new Claim("uname", inputData.Username)
// },
// notBefore: authTime,
// expires: expiresAt,
// signingCredentials: new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha512Signature)
// );
// 第二种
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(JwtClaimTypes.Audience,"Client2"),
//new Claim(JwtClaimTypes.Issuer,"发送者(TokenCreate)"),
//new Claim("uname", inputData.Username)
}),
Expires = expiresAt,
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenString = tokenHandler.WriteToken(token);
return Ok(new
{
access_token = tokenString,
token_type = "Bearer",
profile = new
{
uname = inputData.Username,
upass = inputData.Password,
auth_time = new DateTimeOffset(authTime).ToUnixTimeSeconds(),
expires_at = new DateTimeOffset(expiresAt).ToUnixTimeSeconds()
}
});
}
注册TOKEN
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using IdentityModel;
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.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
namespace WebApiJwtDemo
{
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.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(o =>
{
o.TokenValidationParameters = new TokenValidationParameters
{
//NameClaimType = JwtClaimTypes.Name,
//RoleClaimType = JwtClaimTypes.Role,
ValidIssuer = "发送者(TokenCreate)",
ValidAudience = "接收者(TokenServer)",
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("abc123!@#abc123!@#abc123!@#")),
RequireExpirationTime = true,
ClockSkew = TimeSpan.Zero,
ValidateLifetime = true
/***********************************TokenValidationParameters的参数默认值***********************************/
// RequireSignedTokens = true,
// SaveSigninToken = false,
// ValidateActor = false,
// 将下面两个参数设置为false,可以不验证Issuer和Audience,但是不建议这样做。
// ValidateAudience = true,
// ValidateIssuer = true,
// ValidateIssuerSigningKey = false,
// 是否要求Token的Claims中必须包含Expires
// RequireExpirationTime = true,
// 允许的服务器时间偏移量
// ClockSkew = TimeSpan.FromSeconds(300),
// 是否验证Token有效期,使用当前时间与Token的Claims中的NotBefore和Expires对比
// ValidateLifetime = true
};
});
services.AddAuthorization(options =>
{
options.AddPolicy("Author", policy =>
{
policy.RequireClaim("uname");
});
});
services.AddControllers();
}
// 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();
}
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.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
WebApi使用JWT认证(二)
这是第二部:实现NetCore上的WebApi
使用JWT
认证
1、NetCore新建一个WebApi
的项目
2、打开AppSettings.json
,添加Jwt
的信息,这里为了演示而已
{
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Warning"
}
},
"Console": {
"LogLevel": {
"Default": "Warning"
}
}
},
"JwtSettings": {
"Issuer": "XXX",
"Audience": "XXXX",
"SecretKey": "To live is to change the world!"
}
}
3、Models
下新建两个类,一个用于登录,一个用于获取配置文件中的值
namespace NerCoreJwt.Models
{
public class LoginViewModel
{
public string UserName { get; set; } = "wangshibang";
public string Password { get; set; } = "123456";
}
}
namespace NerCoreJwt.Models
{
public class JwtSettings
{
/// <summary>
/// 证书颁发者
/// </summary>
public string Issuer { get; set; }
/// <summary>
/// 允许使用的角色
/// </summary>
public string Audience { get; set; }
/// <summary>
/// 加密字符串
/// </summary>
public string SecretKey { get; set; }
}
}
4、新建一个Controller
,用来写登录后生成Token
逻辑
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using NerCoreJwt.Models;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
namespace NerCoreJwt.Controllers
{
[Route("api/[controller]/[action]")]
public class AuthorizeController : Controller
{
private JwtSettings setting;
public AuthorizeController(IOptions<JwtSettings> options)
{
setting = options.Value;
}
[HttpPost]
public IActionResult Login(LoginViewModel login)
{
if (ModelState.IsValid)
{
if (login.UserName == "wangshibang" && login.Password == "123456")
{
var claims = new Claim[] {
new Claim(ClaimTypes.Name, login.UserName),
new Claim(ClaimTypes.Role, "admin, Manage")
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(setting.SecretKey));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
setting.Issuer,
setting.Audience,
claims,
DateTime.Now,
DateTime.Now.AddMinutes(30),
creds);
return Ok(new { Token = new JwtSecurityTokenHandler().WriteToken(token) });
}
}
return BadRequest();
}
[HttpGet]
public IActionResult NoValidate()
{
return Ok();
}
}
}
5、StartUp
类里面添加从Configure<JwtSettings>
中获取Section
才可以使用IOptions
获取里面的内容,为了省事就全部贴出来了
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using NerCoreJwt.Models;
using System.Linq;
using System.Threading.Tasks;
namespace NerCoreJwt
{
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<JwtSettings>(Configuration.GetSection("JwtSettings"));
JwtSettings setting = new JwtSettings();
Configuration.Bind("JwtSettings", setting);
services.AddAuthentication(option =>
{
option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(config =>
{
/*
config.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
ValidAudience = setting.Audience,
ValidIssuer = setting.Issuer,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(setting.SecretKey))
};
*/
config.SecurityTokenValidators.Clear();
config.SecurityTokenValidators.Add(new MyTokenValidate());
config.Events = new JwtBearerEvents()
{
OnMessageReceived = context =>
{
var token = context.Request.Headers["myToken"];
context.Token = token.FirstOrDefault();
return Task.CompletedTask;
}
};
});
services.AddMvc();
}
// 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();
}
app.UseAuthentication();
app.UseMvc();
}
}
}
6、Token
生成了,可以用PostMan
调用接口试试,把生成的Token
粘到jwt.io
官网看看里面的信息
下面我们来进行授权
7、为了自定义授权方法,我们需要新建一个类,继承自ISecurityTokenValidator
接口
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
namespace NerCoreJwt
{
public class MyTokenValidate : ISecurityTokenValidator
{
public bool CanValidateToken => true;
public int MaximumTokenSizeInBytes { get ; set ; }
public bool CanReadToken(string securityToken)
{
return true;
}
public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
{
ClaimsPrincipal principal;
try
{
validatedToken = null;
//这里需要验证生成的Token
/*
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoid2FuZ3NoaWJhbmciLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3JvbGUiOiJhZG1pbiwgTWFuYWdlIiwibmJmIjoxNTIyOTI0MDgxLCJleHAiOjE1MjI5MjU4ODEsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6NTAwMCIsImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6NTAwMCJ9.fa0jDYt_MqHFcwQfsMS30eCsjEwQt_uiv96bGtMQJBE
*/
var token = new JwtSecurityToken(securityToken);
//获取到Token的一切信息
var payload = token.Payload;
var role = (from t in payload where t.Key == ClaimTypes.Role select t.Value).FirstOrDefault();
var name = (from t in payload where t.Key == ClaimTypes.Name select t.Value).FirstOrDefault();
var issuer = token.Issuer;
var key = token.SecurityKey;
var audience = token.Audiences;
var identity = new ClaimsIdentity(JwtBearerDefaults.AuthenticationScheme);
identity.AddClaim(new Claim(ClaimTypes.Name, name.ToString()));
identity.AddClaim(new Claim(ClaimsIdentity.DefaultRoleClaimType, "admin"));
principal = new ClaimsPrincipal(identity);
}
catch
{
validatedToken = null;48 principal = null;
}
return principal;
}
}
}
8、然后注释掉上面代码我注册的部分,因为这是原生的Authorize
验证特性,添加后面的自定义验证逻辑
9、在接口上面添加Authorize
特性,用PostMan
调用接口传入生成的Token
,设置断点看看效果吧
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
namespace NerCoreJwt.Controllers
{
[Route("api/[controller]")]
public class ValuesController : Controller
{
// GET api/values
[Authorize(Roles = "admin")]
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
[HttpGet("{id}")]
public string Get(int id)
{
return "value";
}
// POST api/values
[HttpPost]
public void Post([FromBody]string value)
{
}
// PUT api/values/5
[HttpPut("{id}")]
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/values/5
[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
}
JWT-生成、校验、解析Token
(C#)
重要对象
JwtSecurityToken
代表一个jwt token
,可以直接用此对象生成token
字符串,也可以使用token
字符串创建此对象
SecurityToken
JwtSecurityToken
的基类,包含基础数据
JwtSecurityTokenHandler
创建、校验token
,返回ClaimsPrincipal
CanReadToken()
:确定字符串是否是格式良好的Json Web令牌(JWT)
ReadJwtToken(string token)
:token
字符串转为JwtSecurityToken
对象
ValidateToken(string token、TokenValidationParameters parameter,out SecurityToken validatedToken)
:校验token
,返回ClaimsIdentity
,
方式1(推荐)
引用NuGet包:System.IdentityModel.Tokens.Jwt
static void Main(string[] args)
{
//引用System.IdentityModel.Tokens.Jwt
DateTime utcNow = DateTime.UtcNow;
string key = "f47b558d-7654-458c-99f2-13b190ef0199";
SecurityKey securityKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(key));
var claims = new List<Claim>() {
new Claim("ID","1"),
new Claim("Name","fan")
};
JwtSecurityToken jwtToken = new JwtSecurityToken(
issuer: "fan",
audience: "audi~~!",
claims: claims,
notBefore: utcNow,
expires: utcNow.AddYears(1),
signingCredentials: new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256)
);
//生成token方式1
string token1 = new JwtSecurityTokenHandler().WriteToken(jwtToken);
//A Microsoft.IdentityModel.Tokens.SecurityTokenDescriptor that contains details of contents of the token.
var tokenDescriptor = new SecurityTokenDescriptor // 创建一个 Token 的原始对象
{
Issuer = "fan",
Audience = "audi",
Subject = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, "")
}),
Expires = DateTime.Now.AddMinutes(60),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.ASCII.GetBytes(key)), SecurityAlgorithms.HmacSha256)
};
//生成token方式2
SecurityToken securityToken = new JwtSecurityTokenHandler().CreateToken(tokenDescriptor);
var token2 = new JwtSecurityTokenHandler().WriteToken(securityToken);
//校验token
var validateParameter = new TokenValidationParameters()
{
ValidateLifetime = true,
ValidateAudience = true,
ValidateIssuer = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "fan",
ValidAudience = "audi~~!",
IssuerSigningKey = securityKey,
};
//不校验,直接解析token
//jwtToken = new JwtSecurityTokenHandler().ReadJwtToken(token1);
try
{
//校验并解析token
var claimsPrincipal = new JwtSecurityTokenHandler().ValidateToken(token1, validateParameter, out SecurityToken validatedToken);//validatedToken:解密后的对象
var jwtPayload = ((JwtSecurityToken)validatedToken).Payload.SerializeToJson(); //获取payload中的数据
}
catch (SecurityTokenExpiredException)
{
//表示过期
}
catch (SecurityTokenException)
{
//表示token错误
}
}
方式2
引用Nuget包:JWT
/// <summary>
/// 创建token
/// </summary>
/// <returns></returns>
public static string CreateJwtToken(IDictionary<string, object> payload, string secret, IDictionary<string, object> extraHeaders = null)
{
IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
IJsonSerializer serializer = new JsonNetSerializer();
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
var token = encoder.Encode(payload, secret);
return token;
}
/// <summary>
/// 校验解析token
/// </summary>
/// <returns></returns>
public static string ValidateJwtToken(string token, string secret)
{
try
{
IJsonSerializer serializer = new JsonNetSerializer();
IDateTimeProvider provider = new UtcDateTimeProvider();
IJwtValidator validator = new JwtValidator(serializer, provider);
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IJwtAlgorithm alg = new HMACSHA256Algorithm();
IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder, alg);
var json = decoder.Decode(token, secret, true);
//校验通过,返回解密后的字符串
return json;
}
catch (TokenExpiredException)
{
//表示过期
return "expired";
}
catch (SignatureVerificationException)
{
//表示验证不通过
return "invalid";
}
catch (Exception)
{
return "error";
}
}
//-------------客户端调用---------------
public static void Main(string[] args)
{
var sign = "123";
var extraHeaders = new Dictionary<string, object>
{
{ "myName", "limaru" },
};
//过期时间(可以不设置,下面表示签名后 10秒过期)
double exp = (DateTime.UtcNow.AddSeconds(10) - new DateTime(1970, 1, 1)).TotalSeconds;
var payload = new Dictionary<string, object>
{
{ "userId", "001" },
{ "userAccount", "fan" },
{ "exp",exp }
};
var token = CreateJwtToken(payload, sign, extraHeaders);
var text = ValidateJwtToken(token, sign);
Console.ReadKey();
}
方式3
手写jwt算法
JWT组成
样式:"xxxxxxxxxxxx.xxxxxxxxxxxxx.xxxxxxxxxxxxxxxx"由三部分组成.
(1).Header
头部:{"alg":"HS256","typ":"JWT"}
基本组成,也可以自己添加别的内容,然后对最后的内容进行Base64
编码.
(2).Payload
负载:iss、sub、aud、exp、nbf、iat、jti
基本参数,也可以自己添加别的内容,然后对最后的内容进行Base64
编码.
(3).Signature
签名:将Base64
后的Header
和Payload
通过.组合起来,然后利用Hmacsha256
+密钥进行加密。
#region Base64编码
/// <summary>
/// Base64编码
/// </summary>
/// <param name="text">待编码的文本字符串</param>
/// <returns>编码的文本字符串</returns>
public string Base64UrlEncode(string text)
{
var plainTextBytes = Encoding.UTF8.GetBytes(text);
var base64 = Convert.ToBase64String(plainTextBytes).Replace('+', '-').Replace('/', '_').TrimEnd('=');
return base64;
}
#endregion
#region Base64解码
/// <summary>
/// Base64解码
/// </summary>
/// <param name="base64UrlStr"></param>
/// <returns></returns>
public string Base64UrlDecode(string base64UrlStr)
{
base64UrlStr = base64UrlStr.Replace('-', '+').Replace('_', '/');
switch (base64UrlStr.Length % 4)
{
case 2:
base64UrlStr += "==";
break;
case 3:
base64UrlStr += "=";
break;
}
var bytes = Convert.FromBase64String(base64UrlStr);
return Encoding.UTF8.GetString(bytes);
}
#endregion Base64编码和解码
/// <summary>
/// 手写JWT算法
/// </summary>
public bool TestJwt1()
{
string secretKey = Configuration["SecretKey"];
//1.加密
//1.1 表头的处理
string headerBase64Url = this.Base64UrlEncode("{\"alg\":\"HS256\",\"typ\":\"JWT\"}");
//1.2 PayLoad的处理
var jwtPayLoad = new
{
expire = DateTime.Now.AddMinutes(15),
userId = "00000000001",
userAccount = "admin"
};
string payloadBase64Url = this.Base64UrlEncode(JsonConvert.SerializeObject(jwtPayLoad));
//1.3 Sign的处理
string sign = $"{headerBase64Url}.{payloadBase64Url}".HMACSHA256(secretKey);
//1.4 最终的jwt字符串
string jwtStr = $"{headerBase64Url}.{payloadBase64Url}.{sign}";
//2.校验token是否正确
bool result; //True表示通过,False表示未通过
//2.1. 获取token中的PayLoad中的值,并做过期校验
JwtData myData = JsonConvert.DeserializeObject<JwtData>(this.Base64UrlDecode(jwtStr.Split('.')[1])); //这一步已经获取到了payload中的值,并进行转换了
var nowTime = DateTime.Now;
if (nowTime > myData.expire)
{
//表示token过期,校验未通过
result = false;
return result;
}
else
{
//2.2 做准确性校验
var items = jwtStr.Split('.');
var oldSign = items[2];
string newSign = $"{items[0]}.{items[1]}".HMACSHA256(secretKey);
result = oldSign == newSign; //true表示检验通过,false表示检验未通过
return result;
}
}