.Net6 生成Token 和 刷新Token


前言

关于Token的基础概念请自行百度,这里只是记录一下如何生成Token的流程及使用到的技术。


一、引入Nuget包

生成Token和验证Token主要使用下面这个包。

Install-Package 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.测试

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

在这里插入图片描述

  1. 请求头增加Authorization参数,值为:Bearer +Token。(Bearer和Token 中间有空格)
    在这里插入图片描述

  2. 通过refresh_token刷新Token
    在这里插入图片描述

总结

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

### 回答1: .Net 实现 RefreshToken 可以使用 ASP.NET Identity 框架以及 JSON Web Token (JWT)来实现。下面是一个简单的实现步骤: 1. 引入 ASP.NET Identity:首先,在 .Net 项目中引入 ASP.NET Identity 框架。可以通过 NuGet 包管理器安装 Microsoft.AspNet.Identity.Core,Microsoft.AspNet.Identity.EntityFramework 和 Microsoft.AspNet.Identity.Owin 包。 2. 创建身份验证逻辑:创建一个名为 ApplicationUser 的自定义用户模型,并使用 ApplicationUser 类继承 IdentityUser 类。然后,创建一个名为 ApplicationSignInManager 的自定义检查登录逻辑的类,使用 SignInManager 类作为基类。 3. 实现 RefreshToken 功能:在应用中添加一个名为 RefreshToken 的实体类,包含必要属性,如 Token、UserId、ExpiryDate 等。然后,创建一个名为 RefreshTokenService 的服务类,用于处理和生成 RefreshToken 相关的逻辑。这个类可以包含一些方法,如 CreateRefreshToken、ValidateRefreshToken、DeleteRefreshToken 等。 4. 生成和验证 JWT:使用 System.IdentityModel.Tokens.Jwt 包生成和验证 JWT。在需要生成 JWT 的地方,可以使用 JwtSecurityTokenHandler 类来创建包含有效负载和签名的 JWT。可以将 RefreshToken 作为有效负载的一部分。 5. 客户端使用 RefreshToken:当用户的 AccessToken 过期时,客户端可以使用保存的 RefreshToken 向应用的 RefreshToken 端点发送请求获取新的 AccessToken。服务器会验证 RefreshToken 的有效性,如果有效则生成新的 AccessToken 并返回给客户端。 以上是一个基本的实现 RefreshToken 的步骤,具体的代码逻辑可以根据实际需求进行调整和优化。 ### 回答2: 在使用.NET实现Refresh Token的过程中,我们可以借助ASP.NET Core中的Identity框架来实现。首先,我们需要使用Entity Framework Core来创建数据库,并创建用于存储用户信息、Token和Refresh Token等相关表格。 在配置文件中设置Token的有效期限。然后,通过在Startup.cs文件中进行配置,将Identity添加到应用程序的服务中。配置身份验证选项,包括设置JWT Token验证参数。 接下来,我们需要创建一个Token生成器类,用于生成Token和Refresh Token。在这个类中,我们可以使用JWT库来生成Token,并使用Refresh Token作为一个单独的字段添加到Token的负载中。 在用户登录时,我们可以使用ASP.NET Core的身份验证机制生成一个标准的JWT Token,并将Refresh Token存储在数据库中并与用户进行关联。当Token失效时,用户使用Refresh Token来获取一个新的Token。 我们可以创建一个Token刷新端点,用于接收Refresh Token,并检查是否与数据库中存储的Refresh Token匹配。如果匹配成功,则使用之前生成的用户信息生成一个新的Token,并将其返回给用户。 在整个过程中,我们需要注意Token的有效期限以及Refresh Token的存储和更新。可以通过定期清理过期的Token和Refresh Token来确保系统的安全性。 总结来说,通过使用ASP.NET Core中的Identity框架和JWT库,我们可以相对轻松地实现Refresh Token的功能,为系统提供更好的安全性和用户体验。 ### 回答3: .Net实现Refresh Token可以通过以下步骤完成: 1. 首先,在身份验证过程中,用户登录并获得访问令牌(Access Token)。这个令牌是用于对受保护资源进行授权的。 2. 为了实现Refresh Token,我们需要在访问令牌的响应中返回一个刷新令牌(Refresh Token)。它通常是一个长期有效的令牌,并且具有更高的权限,可以用于重新请求新的访问令牌。 3. 将刷新令牌存储在可靠的持久性存储中,例如数据库或缓存。确保对其进行适当的保护和加密,以防止未经授权的访问。 4. 当访问令牌过期时,客户端可以使用刷新令牌请求新的访问令牌。在请求中包括刷新令牌,并向身份验证服务器发送请求。 5. 在服务器端,验证刷新令牌的有效性和正确性。如果刷新令牌是有效的,服务器将针对该用户生成一个新的访问令牌,并将其返回给客户端。 6. 客户端接收到新的访问令牌后,可以继续使用该令牌来访问受保护的资源。 7. 重复以上步骤,直到刷新令牌过期或被撤销。 总结来说,Refresh Token的实现过程中涉及到生成、存储和验证刷新令牌,并使用刷新令牌请求新的访问令牌。这样可以使用户在访问令牌过期时无需重新登录,提供更好的用户体验和安全性。在.Net中,可以使用相关的OAuth2.0和ASP.Net身份验证组件来实现Refresh Token功能。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值