feat: 后端完成双token刷新功能

This commit is contained in:
陈淳
2024-01-24 11:26:44 +08:00
parent c18334002c
commit c9e01e0782
7 changed files with 51 additions and 12 deletions

View File

@@ -1,7 +1,6 @@
using System.Text.RegularExpressions;
using Lazy.Captcha.Core;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Options;
@@ -10,7 +9,6 @@ using Volo.Abp;
using Volo.Abp.Application.Services;
using Volo.Abp.Authorization;
using Volo.Abp.Caching;
using Volo.Abp.EventBus.Local;
using Volo.Abp.Guids;
using Volo.Abp.Uow;
using Volo.Abp.Users;
@@ -43,7 +41,7 @@ namespace Yi.Framework.Rbac.Application.Services
ICaptcha captcha,
IGuidGenerator guidGenerator,
IOptions<RbacOptions> options,
IAliyunManger aliyunManger)
IAliyunManger aliyunManger )
{
_userRepository = userRepository;
_currentUser = currentUser;
@@ -64,6 +62,7 @@ namespace Yi.Framework.Rbac.Application.Services
/// <summary>
/// 效验图片登录验证码,无需和账号绑定
/// </summary>
[AllowAnonymous]
private void ValidationImageCaptcha(LoginInputVo input)
{
if (_rbacOptions.EnableCaptcha)
@@ -83,6 +82,7 @@ namespace Yi.Framework.Rbac.Application.Services
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[AllowAnonymous]
public async Task<object> PostLoginAsync(LoginInputVo input)
{
if (string.IsNullOrEmpty(input.Password) || string.IsNullOrEmpty(input.UserName))
@@ -99,11 +99,24 @@ namespace Yi.Framework.Rbac.Application.Services
//获取token
var accessToken = await _accountManager.GetTokenByUserIdAsync(user.Id);
var refreshToken = _accountManager.CreateRefreshToken(user.Id);
return new { Token = accessToken };
return new { Token = accessToken, RefreshToken = refreshToken };
}
/// <summary>
/// 刷新token
/// </summary>
/// <param name="refresh_token"></param>
/// <returns></returns>
[Authorize(AuthenticationSchemes = TokenTypeConst.Refresh)]
public async Task<object> PostRefreshAsync([FromQuery] string refresh_token)
{
var userId = CurrentUser.Id.Value;
var accessToken = await _accountManager.GetTokenByUserIdAsync(userId);
var refreshToken = _accountManager.CreateRefreshToken(userId);
return new { Token = accessToken, RefreshToken = refreshToken };
}
/// <summary>
/// 生成验证码

View File

@@ -25,5 +25,7 @@ namespace Yi.Framework.Rbac.Domain.Shared.Consts
public const string Permission = nameof(Permission);
public const string RoleInfo=nameof(RoleInfo);
public const string Refresh=nameof(Refresh);
}
}

View File

@@ -35,5 +35,11 @@ namespace Yi.Framework.Rbac.Domain.Extensions
return roleOrNull is null ? null : JsonConvert.DeserializeObject<List<RoleTokenInfoModel>>(roleOrNull);
}
public static bool IsRefreshToken(this ICurrentUser currentUser)
{
var refreshOrNull = currentUser.FindClaims(TokenTypeConst.Refresh).Select(x => x.Value).FirstOrDefault();
return refreshOrNull is null ? false : bool.Parse(refreshOrNull);
}
}
}

View File

@@ -41,7 +41,7 @@ namespace Yi.Framework.Rbac.Domain.Managers
, IOptions<JwtOptions> jwtOptions
, ILocalEventBus localEventBus
, UserManager userManager
,IOptions<RefreshJwtOptions> refreshJwtOptions
, IOptions<RefreshJwtOptions> refreshJwtOptions
, ISqlSugarRepository<RoleEntity> roleRepository)
{
_repository = repository;
@@ -50,7 +50,7 @@ namespace Yi.Framework.Rbac.Domain.Managers
_localEventBus = localEventBus;
_userManager = userManager;
_roleRepository = roleRepository;
_refreshJwtOptions= refreshJwtOptions.Value;
_refreshJwtOptions = refreshJwtOptions.Value;
}
/// <summary>
@@ -112,11 +112,15 @@ namespace Yi.Framework.Rbac.Domain.Managers
return returnToken;
}
private string CreateRefreshToken()
public string CreateRefreshToken(Guid userId)
{
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_refreshJwtOptions.SecurityKey));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var claims =new List<Claim> { new Claim("Refresh", "true") } ;
//添加用户id及刷新token的标识
var claims = new List<Claim> {
new Claim(AbpClaimTypes.UserId,userId.ToString()),
new Claim(TokenTypeConst.Refresh, "true")
};
var token = new JwtSecurityToken(
issuer: _refreshJwtOptions.Issuer,
audience: _refreshJwtOptions.Audience,

View File

@@ -10,6 +10,7 @@ namespace Yi.Framework.Rbac.Domain.Managers
{
public interface IAccountManager : IDomainService
{
string CreateRefreshToken(Guid userId);
Task<string> GetTokenByUserIdAsync(Guid userId);
Task LoginValidationAsync(string userName, string password, Action<UserEntity> userAction = null);
Task RegisterAsync(string userName, string password, long phone);

View File

@@ -21,7 +21,7 @@ namespace Yi.Framework.Rbac.SqlSugarCore
{
DataPermissionFilter(sqlSugarClient);
}
base.CustomDataFilter(sqlSugarClient);
}
@@ -33,7 +33,7 @@ namespace Yi.Framework.Rbac.SqlSugarCore
protected void DataPermissionFilter(ISqlSugarClient sqlSugarClient)
{
//获取当前用户的信息
if (CurrentUser.Id == null) return;
if (CurrentUser.Id == null || CurrentUser.IsRefreshToken()) return;
//管理员不过滤
if (CurrentUser.UserName.Equals(UserConst.Admin) || CurrentUser.Roles.Any(f => f.Equals(UserConst.AdminRolesCode))) return;
var expUser = Expressionable.Create<UserEntity>();

View File

@@ -25,6 +25,7 @@ using Yi.Framework.AspNetCore.Microsoft.AspNetCore.Builder;
using Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection;
using Yi.Framework.Bbs.Application;
using Yi.Framework.Rbac.Application;
using Yi.Framework.Rbac.Domain.Shared.Consts;
using Yi.Framework.Rbac.Domain.Shared.Options;
namespace Yi.Abp.Web
@@ -144,7 +145,7 @@ namespace Yi.Abp.Web
}
};
})
.AddJwtBearer("Refresh", options => {
.AddJwtBearer(TokenTypeConst.Refresh, options => {
options.TokenValidationParameters = new TokenValidationParameters
{
ClockSkew = TimeSpan.Zero,
@@ -153,6 +154,18 @@ namespace Yi.Abp.Web
ValidAudience = refreshJwtOptions.Audience,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(refreshJwtOptions.SecurityKey))
};
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
var accessToken = context.Request.Query["refresh_token"];
if (!string.IsNullOrEmpty(accessToken))
{
context.Token = accessToken;
}
return Task.CompletedTask;
}
};
})
.AddQQ(options =>