mirror of
http://192.168.1.205:9980/cf_devdept2/cf_imes_server.git
synced 2026-08-12 21:02:08 +08:00
禅道bug#1588修复
This commit is contained in:
+4
@@ -4,6 +4,7 @@ import com.cf.imes.framework.common.pojo.CommonResult;
|
||||
import com.cf.imes.module.system.api.oauth2.dto.OAuth2AccessTokenCheckRespDTO;
|
||||
import com.cf.imes.module.system.api.oauth2.dto.OAuth2AccessTokenCreateReqDTO;
|
||||
import com.cf.imes.module.system.api.oauth2.dto.OAuth2AccessTokenRespDTO;
|
||||
import com.cf.imes.module.system.api.oauth2.dto.OAuth2KickOutAccessTokenRespDTO;
|
||||
import com.cf.imes.module.system.enums.ApiConstants;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
@@ -64,4 +65,7 @@ public interface OAuth2TokenApi {
|
||||
@Operation(summary = "请求忽略令牌数据源")
|
||||
CommonResult<String> getIgnoreTokenSource();
|
||||
|
||||
@GetMapping(PREFIX + "/kickout/{token}")
|
||||
@Operation(summary = "获取当前token对应的被踢除token")
|
||||
CommonResult<OAuth2KickOutAccessTokenRespDTO> getKickoutToken(@PathVariable("token") String token);
|
||||
}
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.cf.imes.module.system.api.oauth2.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Schema(description = "RPC 服务 - OAuth2 被踢除令牌的信息 Response DTO")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class OAuth2KickOutAccessTokenRespDTO implements Serializable {
|
||||
|
||||
@Schema(description = "登录ip")
|
||||
private String ip;
|
||||
|
||||
@Schema(description = "踢除时间")
|
||||
private String kickTime;
|
||||
|
||||
}
|
||||
+7
@@ -5,6 +5,7 @@ import com.cf.imes.framework.common.util.object.BeanUtils;
|
||||
import com.cf.imes.module.system.api.oauth2.dto.OAuth2AccessTokenCheckRespDTO;
|
||||
import com.cf.imes.module.system.api.oauth2.dto.OAuth2AccessTokenCreateReqDTO;
|
||||
import com.cf.imes.module.system.api.oauth2.dto.OAuth2AccessTokenRespDTO;
|
||||
import com.cf.imes.module.system.api.oauth2.dto.OAuth2KickOutAccessTokenRespDTO;
|
||||
import com.cf.imes.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
|
||||
import com.cf.imes.module.system.service.oauth2.OAuth2TokenService;
|
||||
import com.cf.imes.module.system.service.organ.OrganService;
|
||||
@@ -68,4 +69,10 @@ public class OAuth2TokenApiImpl implements OAuth2TokenApi {
|
||||
public CommonResult<String> getIgnoreTokenSource() {
|
||||
return success(oauth2TokenService.getIgnoreTokenSource());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<OAuth2KickOutAccessTokenRespDTO> getKickoutToken(String token) {
|
||||
OAuth2AccessTokenDO kickOutAccessToken = oauth2TokenService.getKickOutAccessToken(token);
|
||||
return success(BeanUtils.toBean(kickOutAccessToken, OAuth2KickOutAccessTokenRespDTO.class));
|
||||
}
|
||||
}
|
||||
|
||||
+12
@@ -117,4 +117,16 @@ public class OAuth2AccessTokenDO extends BaseDO {
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private Long productId;
|
||||
|
||||
/**
|
||||
* ip地址
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String ip;
|
||||
|
||||
/**
|
||||
* 踢出时间
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String kickTime;
|
||||
}
|
||||
|
||||
+5
@@ -69,6 +69,11 @@ public class RedisKeyConstants {
|
||||
*/
|
||||
public static final String OAUTH2_ACCESS_TOKEN = "oauth2_access_token:%s";
|
||||
|
||||
/**
|
||||
* 踢出令牌的缓存,记录当前登录ip
|
||||
*/
|
||||
public static final String OAUTH2_KICKOUT_TOKEN = "oauth2_kickout_token:%s";
|
||||
|
||||
/**
|
||||
* 站内信模版的缓存
|
||||
* <p>
|
||||
|
||||
+34
@@ -1,5 +1,7 @@
|
||||
package com.cf.imes.module.system.dal.redis.oauth2;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cf.imes.framework.common.util.collection.CollectionUtils;
|
||||
import com.cf.imes.framework.common.util.json.JsonUtils;
|
||||
@@ -11,10 +13,14 @@ import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.cf.imes.framework.common.util.servlet.ServletUtils.getClientIP;
|
||||
import static com.cf.imes.module.system.dal.redis.RedisKeyConstants.OAUTH2_ACCESS_TOKEN;
|
||||
|
||||
/**
|
||||
@@ -39,6 +45,17 @@ public class OAuth2AccessTokenRedisDAO {
|
||||
return JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(redisKey), OAuth2AccessTokenDO.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* key获取被踢除token
|
||||
*
|
||||
* @param accessToken
|
||||
* @return
|
||||
*/
|
||||
public OAuth2AccessTokenDO getKickOut(String accessToken) {
|
||||
String redisKey = formatKickOutKey(accessToken);
|
||||
return JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(redisKey), OAuth2AccessTokenDO.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 带key获取,oauth2_access_token:xxxx
|
||||
*
|
||||
@@ -98,6 +115,10 @@ public class OAuth2AccessTokenRedisDAO {
|
||||
return String.format(RedisKeyConstants.OAUTH2_ACCESS_TOKEN, accessToken);
|
||||
}
|
||||
|
||||
private static String formatKickOutKey(String accessToken) {
|
||||
return String.format(RedisKeyConstants.OAUTH2_KICKOUT_TOKEN, accessToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建token游标,使用时轮训一次获取两百个token
|
||||
*
|
||||
@@ -106,4 +127,17 @@ public class OAuth2AccessTokenRedisDAO {
|
||||
public Cursor<String> scan(){
|
||||
return stringRedisTemplate.scan(ScanOptions.scanOptions().match(String.format(OAUTH2_ACCESS_TOKEN, "*")).count(200).build());
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建被踢除的token
|
||||
*
|
||||
* @param accessToken
|
||||
*/
|
||||
public void createKickOutToken(String accessToken) {
|
||||
String redisKey = formatKickOutKey(accessToken);
|
||||
OAuth2AccessTokenDO kickOutToken = new OAuth2AccessTokenDO();
|
||||
kickOutToken.setIp(getClientIP()).setKickTime(DateUtil.format(LocalDateTime.now(), DatePattern.NORM_DATETIME_PATTERN));
|
||||
// 创建被踢除的token,设置有效期为5分钟
|
||||
stringRedisTemplate.opsForValue().set(redisKey, JSON.toJSONString(kickOutToken), Duration.ofMinutes(5));
|
||||
}
|
||||
}
|
||||
|
||||
+8
@@ -104,4 +104,12 @@ public interface OAuth2TokenService {
|
||||
* @param userId
|
||||
*/
|
||||
void kickOut(Long userId);
|
||||
|
||||
/**
|
||||
* 获取被剔除的token信息
|
||||
*
|
||||
* @param token
|
||||
* @return
|
||||
*/
|
||||
OAuth2AccessTokenDO getKickOutAccessToken(String token);
|
||||
}
|
||||
|
||||
+9
-8
@@ -25,12 +25,10 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.redis.core.Cursor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception0;
|
||||
@@ -78,7 +76,6 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public OAuth2AccessTokenDO createAccessToken(Long userId, Integer userType, String clientId, List<String> scopes,Boolean large, Integer dbNo, Integer tableNo, String dataCode, Long organId, String nickname) {
|
||||
OAuth2ClientDO clientDO = oauth2ClientService.validOAuthClientFromCache(clientId);
|
||||
// 填入访问令牌包含的字段
|
||||
@@ -243,11 +240,8 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
|
||||
accessTokenDO.setAccessToken(currentToken);
|
||||
// 记录到 Redis 中
|
||||
oauth2AccessTokenRedisDAO.set(accessTokenDO);
|
||||
// 异步踢出其他token
|
||||
CompletableFuture.runAsync(() -> kickOut(userId, currentToken)).exceptionally(e -> {
|
||||
log.error("[OAuth2TokenServiceImpl] redis 清空token失败, 用户id:{}, 异常:{}", userId, e);
|
||||
return null;
|
||||
});
|
||||
// 踢出其他token
|
||||
kickOut(userId, currentToken);
|
||||
return accessTokenDO;
|
||||
}
|
||||
|
||||
@@ -266,6 +260,8 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
|
||||
if (ObjectUtil.equal(userId, oAuth2AccessTokenDO.getUserId()) && !StringUtils.equals(currentToken, oAuth2AccessTokenDO.getAccessToken()) && Boolean.FALSE.equals(oAuth2AccessTokenDO.getIsSupAdmin())) {
|
||||
// 用户id匹配、非当次登录token、非超管 -> 删除redis中的token缓存
|
||||
oauth2AccessTokenRedisDAO.deleteWithKey(key);
|
||||
// 创建踢除的token
|
||||
oauth2AccessTokenRedisDAO.createKickOutToken(oAuth2AccessTokenDO.getAccessToken());
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
@@ -295,4 +291,9 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenDO getKickOutAccessToken(String token) {
|
||||
return oauth2AccessTokenRedisDAO.getKickOut(token);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user