更新网关对外API

This commit is contained in:
磷叶 2025-05-16 11:16:05 +08:00
parent 78e294b7b9
commit de891cbd6c
11 changed files with 138 additions and 25 deletions

View File

@ -117,4 +117,9 @@ public class CacheConstants
* 所有硬件版本名称
*/
public static final String ALL_HARDWARE_VERSION_NAME = "all_hardware_version_name";
/**
* API用户ID前缀
*/
public static final String API_USER_ID_PREFIX = "api_user_id:";
}

View File

@ -184,4 +184,14 @@ public class Constants
* 账号密码登录
*/
public static final String LOGIN_TYPE_PASSWORD = "LOGIN_TYPE_PASSWORD";
/**
* 用户ID
*/
public static final String HEADER_USER_ID = "CT-USER-ID";
/**
* API秘钥
*/
public static final String HEADER_API_SECRET = "CT-API-SECRET";
}

View File

@ -130,6 +130,10 @@ public class User extends BaseEntity
@ApiModelProperty("分成延迟到账时间(小时)")
private Integer bonusDelay;
@ApiModelProperty("api访问秘钥")
@Sensitive(desensitizedType = DesensitizedType.PASSWORD)
private String apiSecret;
public User(Long userId) {
this.userId = userId;
}

View File

@ -27,4 +27,8 @@ public enum UserStatus
{
return info;
}
public static boolean isEnabled(String status) {
return OK.getCode().equals(status);
}
}

View File

@ -1,9 +1,13 @@
package com.ruoyi.framework.security.filter;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.web.service.TokenService;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
@ -11,11 +15,17 @@ import org.springframework.security.web.authentication.WebAuthenticationDetailsS
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.domain.vo.UserVO;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.UserStatus;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.web.service.SysPermissionService;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.user.service.UserService;
/**
* token过滤器 验证token有效性
@ -28,18 +38,71 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter
@Autowired
private TokenService tokenService;
@Autowired
private RedisCache redisCache;
@Autowired
private UserService userService;
@Autowired
private SysPermissionService permissionService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException
{
LoginUser loginUser = tokenService.getLoginUser(request);
if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityUtils.getAuthentication()))
{
tokenService.verifyToken(loginUser);
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
if (StringUtils.isNull(SecurityUtils.getAuthentication())) {
// 优先尝试使用token来获取用户信息
LoginUser loginUser = tokenService.getLoginUser(request);
if (loginUser != null) {
tokenService.verifyToken(loginUser);
}
// 若token未获取到信息则使用accessKey来获取用户信息
else {
loginUser = this.getLoginUserByAccessKey(request);
}
if (StringUtils.isNotNull(loginUser)) {
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}
chain.doFilter(request, response);
}
private LoginUser getLoginUserByAccessKey(HttpServletRequest request) {
String userId = request.getHeader(Constants.HEADER_USER_ID);
String apiSecret = request.getHeader(Constants.HEADER_API_SECRET);
if (StringUtils.isBlank(userId) || StringUtils.isBlank(apiSecret)) {
return null;
}
// 从缓存中获取数据
String redisKey = CacheConstants.API_USER_ID_PREFIX + userId;
LoginUser loginUser = redisCache.getCacheObject(redisKey);
// 缓存未命中查询获取数据
if (loginUser == null) {
// 获取用户信息
UserVO user = userService.selectUserById(Long.parseLong(userId));
if (user == null || !UserStatus.isEnabled(user.getStatus())) {
return null;
}
loginUser = new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));
// 放入缓存中
redisCache.setCacheObject(redisKey, loginUser, 30, TimeUnit.MINUTES);
}
// 校验秘钥
if (!SecurityUtils.matchesPassword(apiSecret, loginUser.getUser().getApiSecret())) {
redisCache.deleteObject(redisKey);
return null;
}
return loginUser;
}
}

View File

@ -67,6 +67,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
u.withdraw_service_value,
u.area_id,
u.bonus_delay,
u.api_secret,
d.dept_id,
d.parent_id,
d.ancestors,
@ -190,6 +191,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
AND date(u.create_time) >= #{createDateRange[0]}
AND date(u.create_time) <= #{createDateRange[1]}
</if>
<if test="apiSecret != null and apiSecret != ''">
AND u.api_secret like concat('%', #{apiSecret}, '%')
</if>
${params.dataScope}
</sql>
@ -290,6 +294,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="withdrawServiceValue != null">withdraw_service_value,</if>
<if test="areaId != null">area_id,</if>
<if test="bonusDelay != null">bonus_delay,</if>
<if test="apiSecret != null and apiSecret != ''">api_secret,</if>
create_time
)values(
<if test="userId != null and userId != ''">#{userId},</if>
@ -315,6 +320,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="withdrawServiceValue != null">#{withdrawServiceValue},</if>
<if test="areaId != null">#{areaId},</if>
<if test="bonusDelay != null">#{bonusDelay},</if>
<if test="apiSecret != null and apiSecret != ''">#{apiSecret},</if>
sysdate()
)
</insert>
@ -346,6 +352,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="withdrawServiceValue != null">withdraw_service_value = #{withdrawServiceValue},</if>
<if test="areaId != null">area_id = #{areaId},</if>
<if test="bonusDelay != null">bonus_delay = #{bonusDelay},</if>
<if test="apiSecret != null and apiSecret != ''">api_secret = #{apiSecret},</if>
update_time = sysdate()
</set>
where user_id = #{userId}

View File

@ -27,6 +27,7 @@ public class UserConverterImpl implements UserConverter {
vo.setSex(data.getSex());
vo.setAvatar(data.getAvatar());
vo.setStatus(data.getStatus());
vo.setApiSecret(data.getApiSecret());
return vo;
}
@ -49,6 +50,7 @@ public class UserConverterImpl implements UserConverter {
vo.setSex(data.getSex());
vo.setAvatar(data.getAvatar());
vo.setStatus(data.getStatus());
vo.setApiSecret(data.getApiSecret());
return vo;
}

View File

@ -278,6 +278,9 @@ public class UserServiceImpl implements UserService
if (user.getPassword() != null) {
user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
}
if (user.getApiSecret() != null) {
user.setApiSecret(SecurityUtils.encryptPassword(user.getApiSecret()));
}
// 设置默认信息
this.setDefaultInfo(user);
@ -294,7 +297,7 @@ public class UserServiceImpl implements UserService
// 后校验
this.afterCheck(user.getUserId());
this.clearCache();
this.clearCache(user.getUserId());
}
return rows;
@ -317,8 +320,15 @@ public class UserServiceImpl implements UserService
}
}
void clearCache() {
private void clearCache() {
clearCache(null);
}
private void clearCache(Long userId) {
redisCache.deleteObject(CacheConstants.USER_NAME_LIST);
if (userId != null) {
redisCache.deleteObject(CacheConstants.API_USER_ID_PREFIX + userId);
}
}
@ -358,6 +368,10 @@ public class UserServiceImpl implements UserService
ServiceUtil.assertion(StringUtils.isNotEmpty(user.getEmail()) && !this.checkEmailUnique(user),
"修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
if (user.getApiSecret() != null) {
user.setApiSecret(SecurityUtils.encryptPassword(user.getApiSecret()));
}
Integer result = transactionTemplate.execute(status -> {
// 删除用户与角色关联
userRoleMapper.deleteUserRoleByUserId(userId);
@ -373,7 +387,7 @@ public class UserServiceImpl implements UserService
// 后校验
this.afterCheck(user.getUserId());
this.clearCache();
this.clearCache(user.getUserId());
}
return rows;
@ -413,7 +427,7 @@ public class UserServiceImpl implements UserService
int rows = userMapper.updateUser(user);
if (rows > 0) {
clearCache();
clearCache(user.getUserId());
}
return rows;
@ -562,7 +576,7 @@ public class UserServiceImpl implements UserService
int rows = userMapper.deleteUserById(userId);
if (rows > 0) {
clearCache();
clearCache(userId);
}
return rows;
@ -590,7 +604,9 @@ public class UserServiceImpl implements UserService
int rows = userMapper.deleteUserByIds(userIds);
if (rows > 0) {
clearCache();
for (Long userId : userIds) {
clearCache(userId);
}
}
return rows;

View File

@ -134,6 +134,7 @@ public class SysUserController extends BaseController
if (StringUtils.isNotNull(userId))
{
UserVO user = userService.selectUserById(userId);
user.setApiSecret(null);
ajax.put(AjaxResult.DATA_TAG, user);
ajax.put("postIds", postService.selectPostListByUserId(userId));
ajax.put("roleIds", user.getRoles().stream().map(Role::getRoleId).collect(Collectors.toList()));

View File

@ -6,7 +6,7 @@ spring:
# 端口默认为6379
port: 6379
# 数据库索引
database: 8
database: 9
# 密码
password:
# 连接超时时间
@ -45,3 +45,4 @@ pay:
# 活体检测
liveness:
returnUrl: http://192.168.2.99:4100/liveness

View File

@ -51,7 +51,7 @@ spring:
devtools:
restart:
# 热部署开关
enabled: true
enabled: false
# token配置
token: