From de891cbd6c689a492c06b3aefecbbcb1e931ac8c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=A3=B7=E5=8F=B6?=
<14103883+leaf-phos@user.noreply.gitee.com>
Date: Fri, 16 May 2025 11:16:05 +0800
Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=BD=91=E5=85=B3=E5=AF=B9?=
=?UTF-8?q?=E5=A4=96API?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../ruoyi/common/constant/CacheConstants.java | 5 +
.../com/ruoyi/common/constant/Constants.java | 10 ++
.../ruoyi/common/core/domain/entity/User.java | 4 +
.../com/ruoyi/common/enums/UserStatus.java | 4 +
.../filter/JwtAuthenticationTokenFilter.java | 95 +++++++++++++++----
.../ruoyi/system/user/mapper/UserMapper.xml | 7 ++
.../user/service/impl/UserConverterImpl.java | 2 +
.../user/service/impl/UserServiceImpl.java | 28 ++++--
.../ruoyi/web/system/SysUserController.java | 1 +
.../src/main/resources/application-env.yml | 3 +-
ruoyi-web/src/main/resources/application.yml | 4 +-
11 files changed, 138 insertions(+), 25 deletions(-)
diff --git a/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java
index ebccc06..f9d669c 100644
--- a/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java
+++ b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java
@@ -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:";
}
diff --git a/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
index 4892307..3e41389 100644
--- a/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
+++ b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
@@ -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";
}
diff --git a/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/User.java b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/User.java
index 2a3a3d8..00810dc 100644
--- a/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/User.java
+++ b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/User.java
@@ -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;
}
diff --git a/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/enums/UserStatus.java b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/enums/UserStatus.java
index d7ff44a..7d36f29 100644
--- a/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/enums/UserStatus.java
+++ b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/enums/UserStatus.java
@@ -27,4 +27,8 @@ public enum UserStatus
{
return info;
}
+
+ public static boolean isEnabled(String status) {
+ return OK.getCode().equals(status);
+ }
}
diff --git a/common-ruoyi/ruoyi-framework/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java b/common-ruoyi/ruoyi-framework/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java
index 188e24f..0ccc6b6 100644
--- a/common-ruoyi/ruoyi-framework/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java
+++ b/common-ruoyi/ruoyi-framework/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java
@@ -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;
+ }
}
diff --git a/ruoyi-service/src/main/java/com/ruoyi/system/user/mapper/UserMapper.xml b/ruoyi-service/src/main/java/com/ruoyi/system/user/mapper/UserMapper.xml
index 0dded07..688c4b5 100644
--- a/ruoyi-service/src/main/java/com/ruoyi/system/user/mapper/UserMapper.xml
+++ b/ruoyi-service/src/main/java/com/ruoyi/system/user/mapper/UserMapper.xml
@@ -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]}
+
+ AND u.api_secret like concat('%', #{apiSecret}, '%')
+
${params.dataScope}
@@ -290,6 +294,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
withdraw_service_value,
area_id,
bonus_delay,
+ api_secret,
create_time
)values(
#{userId},
@@ -315,6 +320,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
#{withdrawServiceValue},
#{areaId},
#{bonusDelay},
+ #{apiSecret},
sysdate()
)
@@ -346,6 +352,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
withdraw_service_value = #{withdrawServiceValue},
area_id = #{areaId},
bonus_delay = #{bonusDelay},
+ api_secret = #{apiSecret},
update_time = sysdate()
where user_id = #{userId}
diff --git a/ruoyi-service/src/main/java/com/ruoyi/system/user/service/impl/UserConverterImpl.java b/ruoyi-service/src/main/java/com/ruoyi/system/user/service/impl/UserConverterImpl.java
index feb6b6a..070483a 100644
--- a/ruoyi-service/src/main/java/com/ruoyi/system/user/service/impl/UserConverterImpl.java
+++ b/ruoyi-service/src/main/java/com/ruoyi/system/user/service/impl/UserConverterImpl.java
@@ -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;
}
diff --git a/ruoyi-service/src/main/java/com/ruoyi/system/user/service/impl/UserServiceImpl.java b/ruoyi-service/src/main/java/com/ruoyi/system/user/service/impl/UserServiceImpl.java
index 97a965d..664e853 100644
--- a/ruoyi-service/src/main/java/com/ruoyi/system/user/service/impl/UserServiceImpl.java
+++ b/ruoyi-service/src/main/java/com/ruoyi/system/user/service/impl/UserServiceImpl.java
@@ -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);
+ }
}
@@ -357,6 +367,10 @@ public class UserServiceImpl implements UserService
"修改用户'" + user.getUserName() + "'失败,手机号码已存在");
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 -> {
// 删除用户与角色关联
@@ -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;
diff --git a/ruoyi-web/src/main/java/com/ruoyi/web/system/SysUserController.java b/ruoyi-web/src/main/java/com/ruoyi/web/system/SysUserController.java
index c3fc523..f4b48ab 100644
--- a/ruoyi-web/src/main/java/com/ruoyi/web/system/SysUserController.java
+++ b/ruoyi-web/src/main/java/com/ruoyi/web/system/SysUserController.java
@@ -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()));
diff --git a/ruoyi-web/src/main/resources/application-env.yml b/ruoyi-web/src/main/resources/application-env.yml
index 3a8096b..875ffe1 100644
--- a/ruoyi-web/src/main/resources/application-env.yml
+++ b/ruoyi-web/src/main/resources/application-env.yml
@@ -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
+
diff --git a/ruoyi-web/src/main/resources/application.yml b/ruoyi-web/src/main/resources/application.yml
index bd0d716..028b621 100644
--- a/ruoyi-web/src/main/resources/application.yml
+++ b/ruoyi-web/src/main/resources/application.yml
@@ -51,7 +51,7 @@ spring:
devtools:
restart:
# 热部署开关
- enabled: true
+ enabled: false
# token配置
token:
@@ -132,7 +132,7 @@ iot:
# token过期时间
daysToExpire: 100
# 推送消息token
- token: tVpNdGKrAFHfKZNgpIWQfZukrcYHNfFM
+ token: tVpNdGKrAFHfKZNgpIWQfZukrcYHNfFM
# 产品ID
productId: Kef0Ssgz72