实现单设备登录功能
This commit is contained in:
@@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
@@ -32,4 +33,12 @@ public interface OAuth2AccessTokenMapper extends BaseMapperX<OAuth2AccessTokenDO
|
||||
.orderByDesc(OAuth2AccessTokenDO::getId));
|
||||
}
|
||||
|
||||
default void deleteByUserId(Long userId) {
|
||||
delete(Wrappers.lambdaUpdate(OAuth2AccessTokenDO.class).eq(OAuth2AccessTokenDO::getUserId, userId));
|
||||
}
|
||||
|
||||
default List<OAuth2AccessTokenDO> selectListByUserId(Long userId) {
|
||||
return selectList(OAuth2AccessTokenDO::getUserId, userId);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
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 com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
@@ -18,5 +19,7 @@ public interface OAuth2RefreshTokenMapper extends BaseMapperX<OAuth2RefreshToken
|
||||
default OAuth2RefreshTokenDO selectByRefreshToken(String refreshToken) {
|
||||
return selectOne(OAuth2RefreshTokenDO::getRefreshToken, refreshToken);
|
||||
}
|
||||
|
||||
default void deleteByUserId(Long userId) {
|
||||
delete(Wrappers.lambdaUpdate(OAuth2RefreshTokenDO.class).eq(OAuth2RefreshTokenDO::getUserId, userId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,11 @@ public interface OAuth2TokenService {
|
||||
*/
|
||||
OAuth2AccessTokenDO refreshAccessToken(String refreshToken, String clientId);
|
||||
|
||||
/**
|
||||
* 删除用户所有返回令牌
|
||||
* @param userId 用户 Id
|
||||
*/
|
||||
void removeAccessTokenByUserId(Long userId);
|
||||
/**
|
||||
* 获得访问令牌
|
||||
*
|
||||
|
||||
@@ -8,6 +8,7 @@ import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
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;
|
||||
@@ -22,6 +23,7 @@ import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2AccessTokenMapper;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2RefreshTokenMapper;
|
||||
import cn.iocoder.yudao.module.system.dal.redis.oauth2.OAuth2AccessTokenRedisDAO;
|
||||
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -31,6 +33,7 @@ import java.time.LocalDateTime;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
@@ -57,11 +60,19 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
|
||||
@Lazy // 懒加载,避免循环依赖
|
||||
private AdminUserService adminUserService;
|
||||
|
||||
@Value("${multiple-device-login}")
|
||||
private Boolean multipleDeviceLoginConfig;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public OAuth2AccessTokenDO createAccessToken(Long userId, Integer userType, String clientId, List<String> scopes) {
|
||||
// 在 yaml multiple-device-login = True 时 删除用户上次登录令牌,实现单设备登录
|
||||
if (multipleDeviceLoginConfig){
|
||||
removeAccessTokenByUserId(userId);
|
||||
}
|
||||
OAuth2ClientDO clientDO = oauth2ClientService.validOAuthClientFromCache(clientId);
|
||||
// 创建刷新令牌
|
||||
|
||||
OAuth2RefreshTokenDO refreshTokenDO = createOAuth2RefreshToken(userId, userType, clientDO, scopes);
|
||||
// 创建访问令牌
|
||||
return createOAuth2AccessToken(refreshTokenDO, clientDO);
|
||||
@@ -99,6 +110,18 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
|
||||
return createOAuth2AccessToken(refreshTokenDO, clientDO);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void removeAccessTokenByUserId(Long userId) {
|
||||
List<OAuth2AccessTokenDO> oAuth2AccessTokenDOList = oauth2AccessTokenMapper.selectListByUserId(userId);
|
||||
if (!CollectionUtils.isAnyEmpty(oAuth2AccessTokenDOList)) {
|
||||
oauth2AccessTokenRedisDAO.deleteList(oAuth2AccessTokenDOList.stream().map(OAuth2AccessTokenDO::getAccessToken).collect(Collectors.toList()));
|
||||
|
||||
}
|
||||
oauth2AccessTokenMapper.deleteByUserId(userId);
|
||||
oauth2RefreshTokenMapper.deleteByUserId(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenDO getAccessToken(String accessToken) {
|
||||
// 优先从 Redis 中获取
|
||||
@@ -126,6 +149,7 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
|
||||
return accessTokenDO;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenDO checkAccessToken(String accessToken) {
|
||||
OAuth2AccessTokenDO accessTokenDO = getAccessToken(accessToken);
|
||||
|
||||
Reference in New Issue
Block a user