返回顶部
首页 > 资讯 > 后端开发 > ASP.NET >通过.NET6实现RefreshToken
  • 792
分享到

通过.NET6实现RefreshToken

2024-04-02 19:04:59 792人浏览 安东尼
摘要

目录需求目标原理与思路实现使ApplicationUser支持RefreshToken修改CreateToken签名使其同时返回Refresh Token修改login方法实现ref

需求

在上一篇文章使用.NET 6实现基于Jwt的Identity功能中,我们演示了如何使用.net框架的Identity组件实现基于JWT Token的认证和授权功能。我们可以想象一下场景:当获取到的Token过期以后,我们必须要重新请求认证接口以获取新的Token,在实际的应用中,表现出来就是虽然当前用户一直在进行业务的操作,但是到了一个固定的时间点后,就会要求用户重新登陆一次来获取新Token,这对用户的体验是非常不友好的。所以我们引出了本文将要介绍的Refresh Token的概念。

那么我们为什么一定需要一个Refresh Token而不是将Token的过期时间设置的长一点呢?最主要的原因是如果这个长期的Token一旦被暴露,那么即使我们修改登录密码,也无法阻止已经被暴露的Token被用来访问我们受保护的api资源,只能等到这个Token自己过期。所以我们希望设置一个短时间有效的Token,当客户端Token失效后,服务端将会返回一个Token过期的响应,那么此时客户端就可以携带这个已过期的Token和服务器之前签发的一次性的Refresh Token去服务端换取一个新的Token和一个新的一次性Refresh Token。客户端就可以在不需要重新登陆的情况下携带这个新的Token去访问后端资源,同时也将Token暴露的影响降低了。

目标

TodoList实现Refresh Token功能。

原理与思路

为了实现Refresh Token功能,我们需要做这几件事:

  • 在用户请求Token时同时创建一个Refresh Token返回给客户端;
  • 修改认证服务,使其能够从已过期的Token中获取用户的Principal数据;
  • 创建一个refresh token的API接口用于响应客户端的获取新Token的逻辑。

实现

使ApplicationUser支持RefreshToken

ApplicationUser.cs

using Microsoft.Aspnetcore.Identity;

namespace TodoList.Infrastructure.Identity;

public class ApplicationUser : IdentityUser
{
    public string? RefreshToken { get; set; }
    public DateTime RefreshTokenExpiryTime { get; set; }
}

运行Migration使修改生效。

修改CreateToken签名使其同时返回Refresh Token

新建创建Token返回的响应体对象ApplicationToken

ApplicationToken.cs

namespace TodoList.Application.Common.Models;

public record ApplicationToken(string AccessToken, string RefreshToken);

修改接口定义

Task<ApplicationToken> CreateTokenAsync(bool populateExpiry);

并对应修改实现:

IdentityService.cs

public async Task<ApplicationToken> CreateTokenAsync(bool populateExpiry)
{
    var signinGCredentials = GetSigningCredentials();
    var claims = await GetClaims();
    var tokenOptions = GenerateTokenOptions(signingCredentials, claims);
    var refreshToken = GenerateRefreshToken();

    User!.RefreshToken = refreshToken;
    if(populateExpiry)
        User!.RefreshTokenExpiryTime = DateTime.Now.ADDDays(7);
    await _userManager.UpdateAsync(User);

    var accessToken = new JwtSecurityTokenHandler().WriteToken(tokenOptions);

    return new ApplicationToken(accessToken, refreshToken);
}
private string GenerateRefreshToken()
{
    // 创建一个随机的Token用做Refresh Token
    var randomNumber = new byte[32];

    using var rng = RandomNumberGenerator.Create();
    rng.GetBytes(randomNumber);

    return Convert.ToBase64String(randomNumber);
}

修改login方法

AuthenticationController.cs

[HttpPost("login")]
public async Task<IActionResult> Authenticate([FromBody] UserForAuthentication userForAuthentication)
{
    if (!await _identityService.ValidateUserAsync(userForAuthentication))
    {
        return Unauthorized();
    }

    var token = await _identityService.CreateTokenAsync(true);
    return Ok(token);
}

到目前为止,我们已经为应用程序添加了Refresh Token所需要的一些基础功能了,接下来就需要实现一个refresh token接口用于换取新的Token

实现refresh token接口

我们新建一个Action用于refresh token接口。

AuthenticationController.cs

[HttpPost("refresh")]
public async Task<IActionResult> Refresh([FromBody] ApplicationToken token)
{
    var tokenToReturn = await _identityService.RefreshTokenAsync(token);
    return Ok(tokenToReturn);
}

实现refresh token功能

我们在认证服务中添加Controller中调用的方法

IIdentityService.cs

Task<ApplicationToken> RefreshTokenAsync(ApplicationToken token);

并实现接口方法:

IdentityService.cs

// 省略其他...
public async Task<ApplicationToken> RefreshTokenAsync(ApplicationToken token)
{
    var principal = GetPrincipalFromExpiredToken(token.AccessToken);

    var user = await _userManager.FindByNameAsync(principal.Identity?.Name);
    if (user == null || user.RefreshToken != token.RefreshToken || user.RefreshTokenExpiryTime <= DateTime.Now)
    {
        throw new BadHttpRequestException("provided token has some invalid value");
    }

    User = user;
    return await CreateTokenAsync(true);
}

private ClaimsPrincipal GetPrincipalFromExpiredToken(string token)
{
    // 根据已过期的Token获取用户相关的Principal数据,用来生成新的Token
    var jwtSettings = _configuration.GetSection("JwtSettings");
    var tokenValidationParameters = new TokenValidationParameters {
        ValidateAudience = true,
        ValidateIssuer = true,
        ValidateIssuerSigningKey = true,
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Environment.GetEnvironmentVariable("SECRET") ?? "TodoListApiSecreTKEy")), ValidateLifetime = true,
        ValidIssuer = jwtSettings["validIssuer"],
        ValidAudience = jwtSettings["validAudience"]
    };

    var tokenHandler = new JwtSecurityTokenHandler();
    var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out var securityToken);
    if (securityToken is not JwtSecurityToken jwtSecurityToken || 
        !jwtSecurityToken.Header.Alg.Equals(SecurityAlGorithms.HMacSha256, StringComparison.InvariantCultureIgnoreCase))
    {
        throw new SecurityTokenException("Invalid token");
    }

    return principal;
}

接下来我们就可以验证refresh token的功能了。

验证

启动Api项目,首先我们获取Token:

可以看到同时返回了refresh token。

然后我们请求refresh token接口:

获取到了一个新的Access Token和一个新的refresh token。

接下来使用新获取到的access token去请求创建TodoList

可以看到新的access token是可以用来作为认证和授权的凭证请求接口的。

总结

在本文中我们实现了关于refresh token的功能,在实际应用中,客户端程序可能需要根据原始Token中payload里的exp字段去判断是否将要过期,提前请求refresh token,以实现用户无感知的持续携带有效的token去请求后端API资源。

到此这篇关于通过.NET 6实现RefreshToken的文章就介绍到这了,更多相关.NET 6 RefreshToken内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 通过.NET6实现RefreshToken

本文链接: https://lsjlt.com/news/162130.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 通过.NET6实现RefreshToken
    目录需求目标原理与思路实现使ApplicationUser支持RefreshToken修改CreateToken签名使其同时返回Refresh Token修改login方法实现ref...
    99+
    2024-04-02
  • .NET6开发之实现缓存过程详解
    目录需求目标原理与思路实现使用原生ResponseCaching实现缓存使用Marvin.Cache.Headers实现更多缓存功能一点扩展总结参考资料需求 有的时候为了减少客户端请...
    99+
    2024-04-02
  • .NET6环境下实现MQTT通信及详细代码演示
    前言: MQTT广泛应用于工业物联网、智能家居、各类智能制造或各类自动化场景等。MQTT是一个基于客户端-服务器的消息发布/订阅传输协议,在很多受限的环境下,比如说机器与机器通信、机...
    99+
    2024-04-02
  • php实现通过api实现chatgpt
    ...
    99+
    2023-09-03
    php 开发语言
  • 使用.NET6实现动态API
    目录开发环境项目地址项目目标编码约定核心代码使用示例ApiLite是基于.NET6直接将Service层生成动态api路由,可以不用添加Controller,支持模块插件化,在项目开...
    99+
    2024-04-02
  • 【2023】java通过modbus4j实现modus TCP通讯
    Modbus通信协议: 主要分为三个子协议 RTUASCIITCP Modbus RTU:——传输的是字节数组(bit[]) 通信:读写 输出:可以读写 输入:只能读 存储区:输出线圈、输入线...
    99+
    2023-09-06
    java tcp/ip 开发语言
  • Windows 中通过Python实现p
    由于ping命令在ping的时候无法加入时间,不能够直观分析结果。便想在ping的时候加入时间戳。 1.首先需要系统配置了Python的环境,我的环境如下,这里就不介绍环境搭建步骤。 2.以下是代码展示,新建一个pi...
    99+
    2023-01-31
    Windows Python
  • 通过ASM 反射实现IOC
    大家知道ASM可以来分析 修改类 从前学习spring的时候里面有个叫IOC的技术,不知道他的底层实现感觉很神秘,但是最近在看ASM的东西,感觉结合反射用它就可以实现自动注入的功能。例子如下那spring里面是如何实现的...
    99+
    2023-06-02
  • 如何使用.NET6实现动态API
    本篇文章为大家展示了如何使用.NET6实现动态API,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。ApiLite是基于.NET6直接将Service层生成动态api路由,可以不用添加Controll...
    99+
    2023-06-22
  • .NET6 ConfigurationManager的实现及使用方式
    前言 友情提示:建议阅读本文之前先了解下.Net Core配置体系相关,也可以参考本人之前的文章《.Net Core Configuration源码探究 》然后对.Net Core的...
    99+
    2024-04-02
  • .NET6开发TodoList应用之实现ActionFilter
    目录需求目标原理与思路实现验证总结需求 Filter在.NET Web API项目开发中也是很重要的一个概念,它运行在执行MVC响应的Pipeline中执行,允许我们将一些可以在多个...
    99+
    2024-04-02
  • python如何通过protobuf实现rpc
    由于项目组现在用的rpc是基于google protobuf rpc协议实现的,所以花了点时间了解下protobuf rpc。rpc对于做分布式系统的人来说肯定不陌生,对于rpc不了解的童鞋可以自行goog...
    99+
    2022-06-04
    python protobuf rpc
  • js通过audioContext实现3D音效
    本文实例为大家分享了js通过audioContext实现3D音效的具体代码,供大家参考,具体内容如下 前言 AudioContext的setPosition实现3D音效 效果展示 ...
    99+
    2024-04-02
  • jquery怎么通过animate实现height
    本文小编为大家详细介绍“jquery怎么通过animate实现height”,内容详细,步骤清晰,细节处理妥当,希望这篇“jquery怎么通过animate实现height”文章能帮助大家解决疑惑,下面跟着...
    99+
    2024-04-02
  • 通过数据结构实现简易通讯录
    AddressBookTest是测试类package MyADB;import java.util.InputMismatchException;import java.util.Scanner;class InstructionsMist...
    99+
    2023-06-02
  • nodejs通过phantomjs实现下载网页
    功能其实很见简单,通过 phantomjs.exe 采集 url 加载的资源,通过子进程的方式,启动nodejs 加载所有的资源,对于css的资源,匹配css内容,下载里面的url资源 当然功能还是很简单的...
    99+
    2022-06-04
    下载网页 nodejs phantomjs
  • Android通过JNI实现守护进程
    开发一个需要常住后台的App其实是一件非常头疼的事情,不仅要应对国内各大厂商的ROM,还需要应对各类的安全管家...虽然不断的研究各式各样的方法,但是效果并不好,比如任务管理器...
    99+
    2022-06-06
    进程 jni Android
  • 通过sql实现动态行转列
    上一章我们讲了固定行转列,本章我们就将一下怎么动态实现行转列的。因为有时候需要行专列的值有成千上万条,不可能再用固定行转列的方法,否则你一定会崩溃掉的。好了,废话不多说,开始吧!常见一张表tmp_test,...
    99+
    2024-04-02
  • Java 通过AQS实现数据组织
    引言 从本篇文章开始,我们将介绍 Java AQS 的实现方式,本文先介绍 AQS 的内部数据是如何组织的,后面的文章中再分别介绍 AQS 的各个部门实现。 AQS 通过前面的介绍,...
    99+
    2024-04-02
  • android实现通过NFC读取卡号
    本文实例为大家分享了android通过NFC读取卡号的具体代码,供大家参考,具体内容如下 1.获取权限 <uses-permission android:name="and...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作