mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2025-01-19 03:30:06 +08:00
【功能优化】SYSTEM:支持通过 refreshToken 认证,解决部分场景不方便刷新访问令牌场景
This commit is contained in:
parent
d50844246c
commit
c2937bd087
@ -1,7 +1,7 @@
|
|||||||
package cn.iocoder.yudao.module.system.dal.dataobject.oauth2;
|
package cn.iocoder.yudao.module.system.dal.dataobject.oauth2;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
@ -24,7 +24,7 @@ import java.util.List;
|
|||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
public class OAuth2RefreshTokenDO extends BaseDO {
|
public class OAuth2RefreshTokenDO extends TenantBaseDO {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编号,数据库字典
|
* 编号,数据库字典
|
||||||
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.dal.mysql.oauth2;
|
|||||||
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
|
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
|
||||||
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2RefreshTokenDO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2RefreshTokenDO;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
@ -13,6 +14,7 @@ public interface OAuth2RefreshTokenMapper extends BaseMapperX<OAuth2RefreshToken
|
|||||||
.eq(OAuth2RefreshTokenDO::getRefreshToken, refreshToken));
|
.eq(OAuth2RefreshTokenDO::getRefreshToken, refreshToken));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TenantIgnore // 获取 token 的时候,需要忽略租户编号。原因是:一些场景下,可能不会传递 tenant-id 请求头,例如说文件上传、积木报表等等
|
||||||
default OAuth2RefreshTokenDO selectByRefreshToken(String refreshToken) {
|
default OAuth2RefreshTokenDO selectByRefreshToken(String refreshToken) {
|
||||||
return selectOne(OAuth2RefreshTokenDO::getRefreshToken, refreshToken);
|
return selectOne(OAuth2RefreshTokenDO::getRefreshToken, refreshToken);
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,10 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
|||||||
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
|
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
||||||
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
|
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
|
||||||
|
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO;
|
||||||
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
|
||||||
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO;
|
||||||
@ -105,10 +107,21 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
|
|||||||
return accessTokenDO;
|
return accessTokenDO;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取不到,从 MySQL 中获取
|
// 获取不到,从 MySQL 中获取访问令牌
|
||||||
accessTokenDO = oauth2AccessTokenMapper.selectByAccessToken(accessToken);
|
accessTokenDO = oauth2AccessTokenMapper.selectByAccessToken(accessToken);
|
||||||
|
if (accessTokenDO != null && DateUtils.isExpired(accessTokenDO.getExpiresTime())) {
|
||||||
|
accessTokenDO = null;
|
||||||
|
}
|
||||||
|
// 特殊:从 MySQL 中获取刷新令牌。原因:解决部分场景不方便刷新访问令牌场景
|
||||||
|
// 例如说,积木报表只允许传递 token,不允许传递 refresh_token,导致无法刷新访问令牌
|
||||||
|
// 再例如说,前端 WebSocket 的 token 直接跟在 url 上,无法传递 refresh_token
|
||||||
|
OAuth2RefreshTokenDO refreshTokenDO = oauth2RefreshTokenMapper.selectByRefreshToken(accessToken);
|
||||||
|
if (refreshTokenDO != null && !DateUtils.isExpired(refreshTokenDO.getExpiresTime())) {
|
||||||
|
accessTokenDO = convertToAccessToken(refreshTokenDO);
|
||||||
|
}
|
||||||
|
|
||||||
// 如果在 MySQL 存在,则往 Redis 中写入
|
// 如果在 MySQL 存在,则往 Redis 中写入
|
||||||
if (accessTokenDO != null && !DateUtils.isExpired(accessTokenDO.getExpiresTime())) {
|
if (accessTokenDO != null) {
|
||||||
oauth2AccessTokenRedisDAO.set(accessTokenDO);
|
oauth2AccessTokenRedisDAO.set(accessTokenDO);
|
||||||
}
|
}
|
||||||
return accessTokenDO;
|
return accessTokenDO;
|
||||||
@ -169,6 +182,14 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
|
|||||||
return refreshToken;
|
return refreshToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private OAuth2AccessTokenDO convertToAccessToken(OAuth2RefreshTokenDO refreshTokenDO) {
|
||||||
|
OAuth2AccessTokenDO accessTokenDO = BeanUtils.toBean(refreshTokenDO, OAuth2AccessTokenDO.class)
|
||||||
|
.setAccessToken(refreshTokenDO.getRefreshToken());
|
||||||
|
TenantUtils.execute(refreshTokenDO.getTenantId(),
|
||||||
|
() -> accessTokenDO.setUserInfo(buildUserInfo(refreshTokenDO.getUserId(), refreshTokenDO.getUserType())));
|
||||||
|
return accessTokenDO;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 加载用户信息,方便 {@link cn.iocoder.yudao.framework.security.core.LoginUser} 获取到昵称、部门等信息
|
* 加载用户信息,方便 {@link cn.iocoder.yudao.framework.security.core.LoginUser} 获取到昵称、部门等信息
|
||||||
*
|
*
|
||||||
|
@ -231,6 +231,22 @@ public class OAuth2TokenServiceImplTest extends BaseDbAndRedisUnitTest {
|
|||||||
new ErrorCode(401, "访问令牌已过期"));
|
new ErrorCode(401, "访问令牌已过期"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckAccessToken_refreshToken() {
|
||||||
|
// mock 数据(访问令牌)
|
||||||
|
OAuth2RefreshTokenDO refreshTokenDO = randomPojo(OAuth2RefreshTokenDO.class)
|
||||||
|
.setExpiresTime(LocalDateTime.now().plusDays(1));
|
||||||
|
oauth2RefreshTokenMapper.insert(refreshTokenDO);
|
||||||
|
// 准备参数
|
||||||
|
String accessToken = refreshTokenDO.getRefreshToken();
|
||||||
|
|
||||||
|
// 调研,并断言
|
||||||
|
OAuth2AccessTokenDO result = oauth2TokenService.getAccessToken(accessToken);
|
||||||
|
// 断言
|
||||||
|
assertPojoEquals(refreshTokenDO, result, "expiresTime", "createTime", "updateTime", "deleted",
|
||||||
|
"creator", "updater");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCheckAccessToken_success() {
|
public void testCheckAccessToken_success() {
|
||||||
// mock 数据(访问令牌)
|
// mock 数据(访问令牌)
|
||||||
|
Loading…
Reference in New Issue
Block a user