新增组织失效/过期校验:1、登录校验;2、已登录用户checkToken和机构校验过滤器校验;

This commit is contained in:
gaoqr
2024-08-02 11:24:03 +08:00
parent 355332b23d
commit a6ce630a8c
4 changed files with 39 additions and 49 deletions
@@ -1,6 +1,7 @@
package com.cf.imes.framework.organ.core.security; package com.cf.imes.framework.organ.core.security;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.exception.enums.GlobalErrorCodeConstants; import com.cf.imes.framework.common.exception.enums.GlobalErrorCodeConstants;
import com.cf.imes.framework.common.pojo.CommonResult; import com.cf.imes.framework.common.pojo.CommonResult;
import com.cf.imes.framework.common.util.servlet.ServletUtils; import com.cf.imes.framework.common.util.servlet.ServletUtils;
@@ -13,6 +14,7 @@ import com.cf.imes.framework.web.config.WebProperties;
import com.cf.imes.framework.web.core.filter.ApiRequestFilter; import com.cf.imes.framework.web.core.filter.ApiRequestFilter;
import com.cf.imes.framework.web.core.handler.GlobalExceptionHandler; import com.cf.imes.framework.web.core.handler.GlobalExceptionHandler;
import com.cf.imes.framework.web.core.util.WebFrameworkUtils; import com.cf.imes.framework.web.core.util.WebFrameworkUtils;
import com.cf.imes.module.system.enums.ErrorCodeConstants;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher; import org.springframework.util.AntPathMatcher;
@@ -90,6 +92,10 @@ public class OrganSecurityWebFilter extends ApiRequestFilter {
organFrameworkService.validOrgan(organId); organFrameworkService.validOrgan(organId);
} catch (Throwable ex) { } catch (Throwable ex) {
CommonResult<?> result = globalExceptionHandler.allExceptionHandler(request, ex); CommonResult<?> result = globalExceptionHandler.allExceptionHandler(request, ex);
// 组织失效返回401踢出系统
if (needUnauthorizedWhenOrgExpired(ex)) {
result.setCode(GlobalErrorCodeConstants.UNAUTHORIZED.getCode());
}
ServletUtils.writeJSON(response, result); ServletUtils.writeJSON(response, result);
return; return;
} }
@@ -117,4 +123,21 @@ public class OrganSecurityWebFilter extends ApiRequestFilter {
return false; return false;
} }
/**
* 是否组织失效设置未登录回调
*
* @param ex
* @return
*/
private boolean needUnauthorizedWhenOrgExpired(Throwable ex) {
if (ex instanceof ServiceException) {
ServiceException serviceException = (ServiceException) ex;
if (Objects.equals(serviceException.getCode(), ErrorCodeConstants.ORGAN_EXPIRE.getCode())
|| Objects.equals(serviceException.getCode(), ErrorCodeConstants.ORGAN_DISABLE.getCode())
|| Objects.equals(serviceException.getCode(), ErrorCodeConstants.ORGAN_NOT_EXISTS.getCode())) {
return true;
}
}
return false;
}
} }
@@ -1,6 +1,5 @@
package com.cf.imes.framework.organ.core.service; package com.cf.imes.framework.organ.core.service;
import com.cf.imes.framework.common.pojo.CommonResult;
import com.cf.imes.framework.common.util.cache.CacheUtils; import com.cf.imes.framework.common.util.cache.CacheUtils;
import com.cf.imes.module.system.api.organ.OrganApi; import com.cf.imes.module.system.api.organ.OrganApi;
import com.google.common.cache.CacheLoader; import com.google.common.cache.CacheLoader;
@@ -26,7 +25,7 @@ public class OrganFrameworkServiceImpl implements OrganFrameworkService {
*/ */
private final LoadingCache<Object, List<Long>> getOrganIdsCache = CacheUtils.buildAsyncReloadingCache( private final LoadingCache<Object, List<Long>> getOrganIdsCache = CacheUtils.buildAsyncReloadingCache(
Duration.ofMinutes(1L), // 过期时间 1 分钟 Duration.ofMinutes(1L), // 过期时间 1 分钟
new CacheLoader<Object, List<Long>>() { new CacheLoader<>() {
@Override @Override
public List<Long> load(Object key) { public List<Long> load(Object key) {
@@ -35,20 +34,6 @@ public class OrganFrameworkServiceImpl implements OrganFrameworkService {
}); });
/**
* 针对 {@link #validOrgan(Long)} 的缓存
*/
private final LoadingCache<Long, CommonResult<Boolean>> validOrganCache = CacheUtils.buildAsyncReloadingCache(
Duration.ofMinutes(1L), // 过期时间 1 分钟
new CacheLoader<Long, CommonResult<Boolean>>() {
@Override
public CommonResult<Boolean> load(Long id) {
return organApi.validOrgan(id);
}
});
@Override @Override
@SneakyThrows @SneakyThrows
public List<Long> getOrganIds() { public List<Long> getOrganIds() {
@@ -58,7 +43,7 @@ public class OrganFrameworkServiceImpl implements OrganFrameworkService {
@Override @Override
@SneakyThrows @SneakyThrows
public void validOrgan(Long id) { public void validOrgan(Long id) {
validOrganCache.get(id).checkError(); organApi.validOrgan(id).checkError();
} }
} }
@@ -1,15 +1,12 @@
package com.cf.imes.module.system.service.auth; package com.cf.imes.module.system.service.auth;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.cf.imes.framework.common.enums.CommonStatusEnum; import com.cf.imes.framework.common.enums.CommonStatusEnum;
import com.cf.imes.framework.common.enums.UserTypeEnum; import com.cf.imes.framework.common.enums.UserTypeEnum;
import com.cf.imes.framework.common.exception.ServerException;
import com.cf.imes.framework.common.exception.util.ServiceExceptionUtil; import com.cf.imes.framework.common.exception.util.ServiceExceptionUtil;
import com.cf.imes.framework.common.util.monitor.TracerUtils; import com.cf.imes.framework.common.util.monitor.TracerUtils;
import com.cf.imes.framework.common.util.servlet.ServletUtils; import com.cf.imes.framework.common.util.servlet.ServletUtils;
import com.cf.imes.framework.common.util.validation.ValidationUtils; import com.cf.imes.framework.common.util.validation.ValidationUtils;
import com.cf.imes.framework.organ.core.context.OrganContextHolder;
import com.cf.imes.module.system.api.logger.dto.LoginLogCreateReqDTO; import com.cf.imes.module.system.api.logger.dto.LoginLogCreateReqDTO;
import com.cf.imes.module.system.api.sms.SmsCodeApi; import com.cf.imes.module.system.api.sms.SmsCodeApi;
import com.cf.imes.module.system.api.social.dto.SocialUserBindReqDTO; import com.cf.imes.module.system.api.social.dto.SocialUserBindReqDTO;
@@ -39,6 +36,7 @@ import com.xingyuv.captcha.model.common.ResponseModel;
import com.xingyuv.captcha.model.vo.CaptchaVO; import com.xingyuv.captcha.model.vo.CaptchaVO;
import com.xingyuv.captcha.service.CaptchaService; import com.xingyuv.captcha.service.CaptchaService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -124,9 +122,12 @@ public class AdminAuthServiceImpl implements AdminAuthService {
reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState())); reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState()));
} }
Long organId = user.getOrganId(); Long organId = user.getOrganId();
// 校验机构有效性
organService.validOrgan(organId);
OrganizationDO organ = organService.getOrgan(organId); OrganizationDO organ = organService.getOrgan(organId);
String dataSourceCode = organ.getDataSourceCode(); String dataSourceCode = organ.getDataSourceCode();
if(StrUtil.isBlank(dataSourceCode)) { // 校验机构数据源
if (StringUtils.isBlank(dataSourceCode)) {
throw exception(ORGAN_DATA_CODE_NOT_EXISTS); throw exception(ORGAN_DATA_CODE_NOT_EXISTS);
} }
// 创建 Token 令牌,记录登录日志 // 创建 Token 令牌,记录登录日志
@@ -156,7 +157,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
Long organId = user.getOrganId(); Long organId = user.getOrganId();
OrganizationDO organ = organService.getOrgan(organId); OrganizationDO organ = organService.getOrgan(organId);
String dataSourceCode = organ.getDataSourceCode(); String dataSourceCode = organ.getDataSourceCode();
if(StrUtil.isBlank(dataSourceCode)) { if(StringUtils.isBlank(dataSourceCode)) {
throw exception(ORGAN_DATA_CODE_NOT_EXISTS); throw exception(ORGAN_DATA_CODE_NOT_EXISTS);
} }
@@ -201,7 +202,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
Long organId = user.getOrganId(); Long organId = user.getOrganId();
OrganizationDO organ = organService.getOrgan(organId); OrganizationDO organ = organService.getOrgan(organId);
String dataSourceCode = organ.getDataSourceCode(); String dataSourceCode = organ.getDataSourceCode();
if(StrUtil.isBlank(dataSourceCode)) { if(StringUtils.isBlank(dataSourceCode)) {
throw exception(ORGAN_DATA_CODE_NOT_EXISTS); throw exception(ORGAN_DATA_CODE_NOT_EXISTS);
} }
@@ -231,11 +232,6 @@ public class AdminAuthServiceImpl implements AdminAuthService {
private AuthLoginRespVO createTokenAfterLoginSuccess(Long userId, String username, LoginLogTypeEnum logType, Boolean large, String dataCode, Long organId, String nickname) { private AuthLoginRespVO createTokenAfterLoginSuccess(Long userId, String username, LoginLogTypeEnum logType, Boolean large, String dataCode, Long organId, String nickname) {
// 插入登陆日志 // 插入登陆日志
createLoginLog(userId, username, logType, LoginResultEnum.SUCCESS); createLoginLog(userId, username, logType, LoginResultEnum.SUCCESS);
/*Long organId = OrganContextHolder.getOrganId();
OrganizationDO organ = organService.getOrgan(organId);
if(Objects.isNull(organ)) {
throw new ServerException(10023,"组织不存在");
}*/
// 创建访问令牌 // 创建访问令牌
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken(userId, getUserType().getValue(), OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken(userId, getUserType().getValue(),
OAuth2ClientConstants.CLIENT_ID_DEFAULT, null, large, null, null, dataCode, organId, nickname); OAuth2ClientConstants.CLIENT_ID_DEFAULT, null, large, null, null, dataCode, organId, nickname);
@@ -15,6 +15,7 @@ import com.cf.imes.module.system.dal.dataobject.oauth2.OAuth2RefreshTokenDO;
import com.cf.imes.module.system.dal.mysql.oauth2.OAuth2AccessTokenMapper; import com.cf.imes.module.system.dal.mysql.oauth2.OAuth2AccessTokenMapper;
import com.cf.imes.module.system.dal.mysql.oauth2.OAuth2RefreshTokenMapper; import com.cf.imes.module.system.dal.mysql.oauth2.OAuth2RefreshTokenMapper;
import com.cf.imes.module.system.dal.redis.oauth2.OAuth2AccessTokenRedisDAO; import com.cf.imes.module.system.dal.redis.oauth2.OAuth2AccessTokenRedisDAO;
import com.cf.imes.module.system.service.organ.OrganService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -36,6 +37,7 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
@Resource @Resource
private OAuth2AccessTokenMapper oauth2AccessTokenMapper; private OAuth2AccessTokenMapper oauth2AccessTokenMapper;
@Resource @Resource
private OAuth2RefreshTokenMapper oauth2RefreshTokenMapper; private OAuth2RefreshTokenMapper oauth2RefreshTokenMapper;
@@ -48,6 +50,9 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
@Resource @Resource
private SecurityFrameworkService securityFrameworkService; private SecurityFrameworkService securityFrameworkService;
@Resource
private OrganService organService;
@Override @Override
@Transactional @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) { public OAuth2AccessTokenDO createAccessToken(Long userId, Integer userType, String clientId, List<String> scopes,Boolean large, Integer dbNo, Integer tableNo, String dataCode, Long organId, String nickname) {
@@ -68,7 +73,6 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
} }
// 校验 Client 匹配 // 校验 Client 匹配
OAuth2ClientDO clientDO = oauth2ClientService.validOAuthClientFromCache(clientId);
if (ObjectUtil.notEqual(clientId, refreshTokenDO.getClientId())) { if (ObjectUtil.notEqual(clientId, refreshTokenDO.getClientId())) {
throw exception0(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), "刷新令牌的客户端编号不正确"); throw exception0(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), "刷新令牌的客户端编号不正确");
} }
@@ -86,31 +90,19 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
throw exception0(GlobalErrorCodeConstants.UNAUTHORIZED.getCode(), "刷新令牌已过期"); throw exception0(GlobalErrorCodeConstants.UNAUTHORIZED.getCode(), "刷新令牌已过期");
} }
// // 创建访问令牌
// return createOAuth2AccessToken(refreshTokenDO, clientDO);
return null; return null;
} }
@Override @Override
public OAuth2AccessTokenDO getAccessToken(String accessToken) { public OAuth2AccessTokenDO getAccessToken(String accessToken) {
// // 优先从 Redis 中获取
// OAuth2AccessTokenDO accessTokenDO = oauth2AccessTokenRedisDAO.get(accessToken);
// if (accessTokenDO != null) {
// return accessTokenDO;
// }
//
// // 获取不到,从 MySQL 中获取
// accessTokenDO = oauth2AccessTokenMapper.selectByAccessToken(accessToken);
// // 如果在 MySQL 存在,则往 Redis 中写入
// if (accessTokenDO != null && !DateUtils.isExpired(accessTokenDO.getExpiresTime())) {
// oauth2AccessTokenRedisDAO.set(accessTokenDO);
// }
// 因数据库不在存入缓存数据,所以直接从缓存中获取 // 因数据库不在存入缓存数据,所以直接从缓存中获取
// 数据库移除令牌存入,所以直接从缓存中获取 // 数据库移除令牌存入,所以直接从缓存中获取
OAuth2AccessTokenDO accessTokenDO = oauth2AccessTokenRedisDAO.get(accessToken); OAuth2AccessTokenDO accessTokenDO = oauth2AccessTokenRedisDAO.get(accessToken);
if(accessTokenDO != null){ if(accessTokenDO != null){
// 校验组织的有效性
organService.validOrgan(accessTokenDO.getOrganId());
// 有令牌的校验,代表有接口访问,延长令牌的过期时间(30分钟) // 有令牌的校验,代表有接口访问,延长令牌的过期时间(30分钟)
oauth2AccessTokenRedisDAO.expire(accessToken, 1800, TimeUnit.SECONDS); oauth2AccessTokenRedisDAO.expire(accessToken, 1800, TimeUnit.SECONDS);
} }
@@ -123,9 +115,6 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
if (accessTokenDO == null) { if (accessTokenDO == null) {
throw exception0(GlobalErrorCodeConstants.UNAUTHORIZED.getCode(), "访问令牌不存在"); throw exception0(GlobalErrorCodeConstants.UNAUTHORIZED.getCode(), "访问令牌不存在");
} }
// if (DateUtils.isExpired(accessTokenDO.getExpiresTime())) {
// throw exception0(GlobalErrorCodeConstants.UNAUTHORIZED.getCode(), "访问令牌已过期");
return accessTokenDO; return accessTokenDO;
} }
@@ -162,7 +151,6 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
} }
boolean b = securityFrameworkService.hasAnyRoles(userId,"super_admin"); boolean b = securityFrameworkService.hasAnyRoles(userId,"super_admin");
refreshToken.setIsSupAdmin(b); refreshToken.setIsSupAdmin(b);
// oauth2RefreshTokenMapper.insert(refreshToken);
return refreshToken; return refreshToken;
} }
@@ -177,8 +165,6 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
.setDataCode(refreshTokenDO.getDataCode()).setOrganId(refreshTokenDO.getOrganId()) .setDataCode(refreshTokenDO.getDataCode()).setOrganId(refreshTokenDO.getOrganId())
.setNickname(refreshTokenDO.getNickname()).setIsSupAdmin(refreshTokenDO.getIsSupAdmin()) .setNickname(refreshTokenDO.getNickname()).setIsSupAdmin(refreshTokenDO.getIsSupAdmin())
; ;
//accessTokenDO.setOrganId(OrganContextHolder.getOrganId()); // 手动设置组织编号,避免缓存到 Redis 的时候,无对应的组织编号
// oauth2AccessTokenMapper.insert(accessTokenDO);
// 记录到 Redis 中 // 记录到 Redis 中
oauth2AccessTokenRedisDAO.set(accessTokenDO); oauth2AccessTokenRedisDAO.set(accessTokenDO);
return accessTokenDO; return accessTokenDO;