首页 .NET/Web .Net6 生成Token 和 刷新Token

.Net6 生成Token 和 刷新Token

作者:胡同里的砖头 围观群众:253 更新于:2024-01-18

一、引入Nuget包

生成Token和验证Token主要使用下面这个包。
Microsoft.AspNetCore.Authentication.JwtBearer


二、生成步骤
1.添加配置文件

在API项目的配置文件中增加关于Token的配置信息。
代码如下:

{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"JwtSettings": {
"Issuer": "https://localhost:7141", //颁发者
"Audience": "https://localhost:7141", //使用者
"SecrentKey": "fdsfdsfdfdsfdsfsdfdfsdf", //秘钥
"Expirces": 3600, //Token过期时间,
"RefreshTokenExpirces": 3600 //refresh_Token过期时间
}
}


需要注意的是SecrentKey 的值必须大于16位,不然在生成Token时会报错。
2.创建对应的实体

我们先创建一个和配置文件中相对应的实体,命名为JwtSettings。
代码如下:

namespace JwtDemo
{
/// <summary>
/// JWT 配置信息
/// </summary>
public class JwtSettings
{
/// <summary>
/// 颁发者
/// </summary>
public string Issuer { get; set; }

/// <summary>
/// 使用者
/// </summary>
public string Audience { get; set; }

/// <summary>
/// 私钥
/// </summary>
public string SecrentKey { get; set; }

/// <summary>
/// Token过期时间 单位秒
/// </summary>
public int Expirces { get; set; }

/// <summary>
/// Refresh_Token过期时间 单位秒
/// </summary>
public int RefreshTokenExpirces { get; set; }
}
}


创建一个用于返回Token的实体,命名为 ResponseToken

namespace JwtDemo
{
/// <summary>
/// Token的返回实体
/// </summary>
public class ResponseToken
{

/// <summary>
/// JWT Token
/// </summary>
public string Token { get; set; }

/// <summary>
/// 用于刷新token的刷新令牌
/// </summary>
public string Refresh_Token { get; set; }
}
}


3.Program.cs中注入服务
using JwtDemo;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using System.Text;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.Services.AddTransient<TokenHelper>();

builder.Services.Configure<JwtSettings>(builder.Configuration.GetSection("JwtSettings"));

builder.Services.AddSwaggerGen(options =>
{
var scheme = new OpenApiSecurityScheme()
{
Description = "Authorization header.\r\n Example:'Bearer 123'",
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Authorization" },
Scheme = "oauth2",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey
};
options.AddSecurityDefinition("Authorization", scheme);
var requirement = new OpenApiSecurityRequirement();
requirement[scheme] = new List<string>();
options.AddSecurityRequirement(requirement);
});

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(opt =>
{
var jwtSettings = builder.Configuration.GetSection("JwtSettings").Get<JwtSettings>();
byte[] keyBytes = Encoding.UTF8.GetBytes(jwtSettings.SecrentKey);
var secKey = new SymmetricSecurityKey(keyBytes);
opt.TokenValidationParameters = new()
{
ValidateIssuer = true, //验证颁发者
ValidIssuer = jwtSettings.Issuer,
ValidateAudience = true, // 验证使用者
ValidAudience = jwtSettings.Audience,
ValidateLifetime = true, //是否验证Token有效期,使用当前时间与Token的Claims中的NotBefore和Expires对比
ValidateIssuerSigningKey = true, //验证秘钥
IssuerSigningKey = secKey,
RequireExpirationTime = true,//要求Token的Claims中必须包含Expires
ClockSkew = TimeSpan.Zero, //允许服务器时间偏移量300秒,即我们配置的过期时间加上这个允许偏移的时间值,才是真正过期的时间(过期时间 + 偏移值)你也可以设置为0,ClockSkew = TimeSpan.Zero
};

});

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthentication();

app.UseAuthorization();

app.MapControllers();

app.Run();
builder.Services.AddSwaggerGen(); 是用来在Swagger中添加一个填写Token的按钮

builder.Services.AddAuthentication();是用来配置关于验证Token的一些配置。

app.UseAuthentication(); 添加身份认证,一定要在app.UseAuthorization()的上面。



4.Token的生成和刷新

在帮助类中并没有将Token和refreshToken 存在缓存中,大家可根据自己的业务自行添加对应的逻辑。
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;

namespace JwtDemo
{
/// <summary>
/// Token的帮助类
/// </summary>
public class TokenHelper
{
private readonly IOptionsSnapshot<JwtSettings> _jwtSettings;

public TokenHelper(IOptionsSnapshot<JwtSettings> jwtSettings)
{
_jwtSettings = jwtSettings;
}

/// <summary>
/// 颁发Token
/// </summary>
/// <returns></returns>
public ResponseToken CreateToken()
{
List<Claim> claims = new List<Claim>()
{
new Claim(ClaimTypes.NameIdentifier, "1"),
new Claim(ClaimTypes.Name, "jjm")
};

string key = _jwtSettings.Value.SecrentKey;

DateTime now = DateTime.Now;

var expores = now.AddSeconds(_jwtSettings.Value.Expirces);

byte[] secBytes = Encoding.UTF8.GetBytes(key);
var secKey = new SymmetricSecurityKey(secBytes);
var credentials = new SigningCredentials(secKey, SecurityAlgorithms.HmacSha256Signature);

var tokenDescriptor = new JwtSecurityToken(
issuer: _jwtSettings.Value.Issuer,
audience: _jwtSettings.Value.Audience,
claims: claims,
notBefore: now,
expires: expores,
signingCredentials: credentials);


string token = new JwtSecurityTokenHandler().WriteToken(tokenDescriptor);
string refreshToken = CreateRefreshToken();

//需要将两个Token 都放在缓存中

return new ResponseToken() { Token = token, Refresh_Token = refreshToken };
}

/// <summary>
/// 生成refresh_Token
/// </summary>
/// <returns></returns>
public string CreateRefreshToken()
{
var refresh = new byte[32];
using (var number = RandomNumberGenerator.Create())
{
number.GetBytes(refresh);
return Convert.ToBase64String(refresh);
}

//将refresh_Token存在缓存中
}

public ResponseToken Refresh(string Token, string refresh_Token)
{
string key = _jwtSettings.Value.SecrentKey;

byte[] secBytes = Encoding.UTF8.GetBytes(key);
var secKey = new SymmetricSecurityKey(secBytes);

var tokenHandler = new JwtSecurityTokenHandler();
SecurityToken validatedToken;

// 根据过期Token获取一个SecurityToken
var principal = tokenHandler.ValidateToken(Token, new TokenValidationParameters()
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = secKey,
ValidateIssuer = true,
ValidIssuer = _jwtSettings.Value.Issuer,
ValidateAudience = true,
ValidAudience = _jwtSettings.Value.Audience,
ValidateLifetime = false
}, out validatedToken);

var jwtToken = validatedToken as JwtSecurityToken;

if (jwtToken == null || !jwtToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256Signature, StringComparison.InvariantCultureIgnoreCase))
{
throw new SecurityTokenException("Token不合法");
}

//判断refresh_Token是否此用户生成的

//生成新Token
List<Claim> claims = new List<Claim>()
{
new Claim(ClaimTypes.NameIdentifier, "1"),
new Claim(ClaimTypes.Name, "jjm")
};

var jwtSecurityToken = new JwtSecurityToken(
claims: claims,
notBefore: DateTime.Now,
expires: DateTime.Now.AddSeconds(_jwtSettings.Value.Expirces),
issuer: _jwtSettings.Value.Issuer,
audience: _jwtSettings.Value.Audience,
signingCredentials: new SigningCredentials(secKey, SecurityAlgorithms.HmacSha256Signature)
);

var token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
var refreshToken = CreateRefreshToken();

//将缓存中原来的Token和refresh_Token 删除掉,并且保存新生成的Token

return new ResponseToken() { Token = token, Refresh_Token = refreshToken };
}
}
}


5.创建Controller

[Authorize]: 将则会个特性放在控制器头部的话,整个控制器的所有方法都会需要验证。
[AllowAnonymous]:如果某个方法不需要进行Token的验证,则可以添加这个特性

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace JwtDemo.Controllers
{
[ApiController]
[Route("[controller]/[action]")]
public class WeatherForecastController : ControllerBase
{
private TokenHelper _tokenHelper;
private readonly ILogger<WeatherForecastController> _logger;

public WeatherForecastController(ILogger<WeatherForecastController> logger, TokenHelper tokenHelper)
{
_logger = logger;
_tokenHelper = tokenHelper;
}

/// <summary>
/// 登录
/// </summary>
/// <param name="user">用户名</param>
/// <param name="pwd">密码</param>
/// <returns></returns>
[HttpPost]
public IActionResult Login(string user, string pwd)
{
if (user == "jjm" && pwd == "123")
{
return Ok(_tokenHelper.CreateToken());
}
else
{
return BadRequest();
}
}

[HttpGet]
[Authorize]
public IActionResult Demo1()
{
return Ok("1232131");
}

[HttpGet]
[AllowAnonymous]
public IActionResult Result(string token, string refresh_token)
{
return Ok(_tokenHelper.Refresh(token, refresh_token));
}
}
}
6.测试

输入后台写死的用户名和密码获取Token



请求头增加Authorization参数,值为:Bearer +Token。(Bearer和Token 中间有空格)


通过refresh_token刷新Token


总结

以上就是生成、验证、刷新Token 的全部代码,当然这个比较简单,并没有加入相关的验证逻辑,大家可自行添加。

  • 本文标题: .Net6 生成Token 和 刷新Token
  • 文章分类:【.NET/Web】
  • 非特殊说明,本文版权归【胡同里的砖头】个人博客 所有,转载请注明出处.
留言评论
站点声明:
1、本站【胡同里的砖头】个人博客,借鉴网上一些博客模板,取其各优点模块自行拼装开发,本博客开发纯属个人爱好。
2、所有笔记提供给广大用户交流使用,可转载,可复制,纯个人开发所遇问题锦集记录使用
Copyright © huzlblog.com All Rights Reserved. 备案号:苏ICP备2021056683号-8