From 0e9d35f36f3b022a2dafa189198293c836e41dc0 Mon Sep 17 00:00:00 2001
From: zhibing.pu <393733352@qq.com>
Date: 星期一, 19 八月 2024 19:21:56 +0800
Subject: [PATCH] 增加网关账户校验
---
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/SecurityConstants.java | 5 +
ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/service/TokenService.java | 2
ruoyi-gateway/pom.xml | 20 ++---
ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/AuthFilter.java | 139 ++++++++++++++++++++++++++++------
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/JwtUtils.java | 25 ++++++
5 files changed, 155 insertions(+), 36 deletions(-)
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/SecurityConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/SecurityConstants.java
index 8f56ebf..be3a1e7 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/SecurityConstants.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/SecurityConstants.java
@@ -36,6 +36,11 @@
* 用户标识
*/
public static final String USER_KEY = "user_key";
+
+ /**
+ * 用户类型(system/applet)
+ */
+ public static final String USER_TYPE = "user_type";
/**
* 小程序登录用户标识
*/
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/JwtUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/JwtUtils.java
index b5f5b92..c70bcd2 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/JwtUtils.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/JwtUtils.java
@@ -62,6 +62,31 @@
{
return getValue(claims, SecurityConstants.USER_KEY);
}
+
+ /**
+ * 根据令牌获取用户类型
+ *
+ * @param token 令牌
+ * @return 用户类型
+ */
+ public static String getUserType(String token)
+ {
+ Claims claims = parseToken(token);
+ return getValue(claims, SecurityConstants.USER_TYPE);
+ }
+
+ /**
+ * 根据令牌获取用户类型
+ *
+ * @param claims 身份信息
+ * @return 用户类型
+ */
+ public static String getUserType(Claims claims)
+ {
+ return getValue(claims, SecurityConstants.USER_TYPE);
+ }
+
+
/**
* 小程序根据令牌获取用户标识
diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/service/TokenService.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/service/TokenService.java
index 2735380..2cdbed5 100644
--- a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/service/TokenService.java
+++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/service/TokenService.java
@@ -60,6 +60,7 @@
Map<String, Object> claimsMap = new HashMap<String, Object>();
claimsMap.put(SecurityConstants.USER_KEY, token);
claimsMap.put(SecurityConstants.DETAILS_USER_ID, userId);
+ claimsMap.put(SecurityConstants.USER_TYPE, "system");
claimsMap.put(SecurityConstants.DETAILS_USERNAME, userName);
// 接口返回信息
@@ -82,6 +83,7 @@
Map<String, Object> claimsMap = new HashMap<String, Object>();
claimsMap.put(SecurityConstants.USER_APPLET_KEY, token);
claimsMap.put(SecurityConstants.DETAILS_USER_ID, userId);
+ claimsMap.put(SecurityConstants.USER_TYPE, "applet");
claimsMap.put(SecurityConstants.DETAILS_USERNAME, name);
// 接口返回信息
Map<String, Object> rspMap = new HashMap<String, Object>();
diff --git a/ruoyi-gateway/pom.xml b/ruoyi-gateway/pom.xml
index 055df92..ade8e7d 100644
--- a/ruoyi-gateway/pom.xml
+++ b/ruoyi-gateway/pom.xml
@@ -114,18 +114,14 @@
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
-
-<!-- <dependency>-->
-<!-- <groupId>org.springframework.boot</groupId>-->
-<!-- <artifactId>spring-boot-starter-websocket</artifactId>-->
-<!-- <optional>true</optional>-->
-<!-- </dependency>-->
- <!--hutool-all-->
-<!-- <dependency>-->
-<!-- <groupId>cn.hutool</groupId>-->
-<!-- <artifactId>hutool-all</artifactId>-->
-<!-- <version>5.0.3</version>-->
-<!-- </dependency>-->
+ <dependency>
+ <groupId>com.ruoyi</groupId>
+ <artifactId>ruoyi-api-account</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.ruoyi</groupId>
+ <artifactId>ruoyi-api-system</artifactId>
+ </dependency>
</dependencies>
diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/AuthFilter.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/AuthFilter.java
index 1b0eb25..f46470c 100644
--- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/AuthFilter.java
+++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/AuthFilter.java
@@ -1,18 +1,17 @@
package com.ruoyi.gateway.filter;
-import com.alibaba.fastjson.JSONObject;
-import org.apache.commons.codec.binary.Base64;
+import com.ruoyi.account.api.feignClient.AppUserClient;
+import com.ruoyi.account.api.model.TAppUser;
+import com.ruoyi.system.api.domain.SysUser;
+import com.ruoyi.system.api.feignClient.SysUserClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
-import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
-import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import com.ruoyi.common.core.constant.CacheConstants;
@@ -25,14 +24,12 @@
import com.ruoyi.common.redis.service.RedisService;
import com.ruoyi.gateway.config.properties.IgnoreWhiteProperties;
import io.jsonwebtoken.Claims;
-import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicReference;
+import javax.annotation.Resource;
+import java.util.HashMap;
+import java.util.Map;
+
/**
* 网关鉴权
@@ -50,6 +47,13 @@
@Autowired
private RedisService redisService;
+ @Resource
+ private AppUserClient appUserClient;
+
+ @Resource
+ private SysUserClient sysUserClient;
+
+
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
@@ -61,24 +65,26 @@
if (StringUtils.matches(url, ignoreWhite.getWhites())) {
return chain.filter(exchange);
}
+ //防抖校验
+ try {
+ antiShake(request);
+ }catch (Exception e){
+ log.error("[重复提交]请求路径:{}", exchange.getRequest().getPath());
+ return ServletUtils.webFluxResponseWriter(exchange.getResponse(), e.getMessage(), HttpStatus.SUCCESS);
+ }
+
+ //校验账户是否有效
+ try {
+ verifyToken(request);
+ verifyAccount(request);
+ }catch (Exception e){
+ return unauthorizedResponse(exchange, e.getMessage());
+ }
String token = getToken(request);
- if (StringUtils.isEmpty(token)) {
- return unauthorizedResponse(exchange, "令牌不能为空");
- }
Claims claims = JwtUtils.parseToken(token);
- if (claims == null) {
- return unauthorizedResponse(exchange, "令牌已过期或验证不正确!");
- }
String userkey = JwtUtils.getUserKey(claims);
- boolean islogin = redisService.hasKey(getTokenKey(userkey));
- if (!islogin) {
- return unauthorizedResponse(exchange, "登录状态已过期");
- }
String userid = JwtUtils.getUserId(claims);
String username = JwtUtils.getUserName(claims);
- if (StringUtils.isEmpty(userid) || StringUtils.isEmpty(username)) {
- return unauthorizedResponse(exchange, "令牌验证失败");
- }
// 设置用户信息到请求
addHeader(mutate, SecurityConstants.USER_KEY, userkey);
@@ -130,9 +136,94 @@
/**
* 防抖处理
*/
+ public void antiShake(ServerHttpRequest request) throws Exception{
+ HttpHeaders headers = request.getHeaders();
+ String client = headers.getFirst("client");
+ String timestamp = headers.getFirst("timestamp");
+ String url = request.getURI().getPath();
+ Map<String, Object> cacheMap = redisService.getCacheMap(client);
+ if(null == cacheMap){
+ cacheMap = new HashMap<>();
+ cacheMap.put(url, timestamp);
+ redisService.setCacheMap(client, cacheMap);
+ }else{
+ Object o = cacheMap.get(url);
+ if(null == o){
+ cacheMap.put(url, timestamp);
+ }else{
+ Long old_timestamp = Long.valueOf(o.toString());
+ Long new_timestamp = Long.valueOf(timestamp);
+ //两个请求时间差小于1秒,判定为重复提交
+ if((new_timestamp - old_timestamp) <= 1000){
+ throw new RuntimeException("重复提交");
+ }else{
+ cacheMap.put(url, timestamp);
+ }
+ }
+ redisService.setCacheMap(client, cacheMap);
+ }
+ }
+ /**
+ * 验证token
+ * @param request
+ * @throws Exception
+ */
+ public void verifyToken(ServerHttpRequest request) throws Exception{
+ String token = getToken(request);
+ if (StringUtils.isEmpty(token)) {
+ throw new RuntimeException("令牌不能为空");
+ }
+ Claims claims = JwtUtils.parseToken(token);
+ if (claims == null) {
+ throw new RuntimeException("令牌已过期或验证不正确!");
+ }
+ String userkey = JwtUtils.getUserKey(claims);
+ boolean islogin = redisService.hasKey(getTokenKey(userkey));
+ if (!islogin) {
+ throw new RuntimeException("登录状态已过期");
+ }
+ String userid = JwtUtils.getUserId(claims);
+ String username = JwtUtils.getUserName(claims);
+ if (StringUtils.isEmpty(userid) || StringUtils.isEmpty(username)) {
+ throw new RuntimeException("令牌验证失败");
+ }
+ }
+
+ /**
+ * 校验账户是否有效
+ * @param request
+ * @throws Exception
+ */
+ public void verifyAccount(ServerHttpRequest request) throws Exception{
+ String token = getToken(request);
+ Claims claims = JwtUtils.parseToken(token);
+ String userid = JwtUtils.getUserId(claims);
+ String userType = JwtUtils.getUserType(claims);
+ //管理后台用户
+ if ("system".equals(userType)) {
+ SysUser sysUser = sysUserClient.getSysUser(Long.valueOf(userid)).getData();
+ if(null == sysUser || "2".equals(sysUser.getDelFlag())){
+ throw new RuntimeException("无效的账户");
+ }
+ if("1".equals(sysUser.getStatus())){
+ throw new RuntimeException("账户已被停用,请联系系统管理员!");
+ }
+ }
+ //小程序用户
+ if ("applet".equals(userType)) {
+ TAppUser appUser = appUserClient.getUserById(Long.valueOf(userid)).getData();
+ if(null == appUser || appUser.getDelFlag() || 3 == appUser.getStatus()){
+ throw new RuntimeException("无效的账户");
+ }
+ if(2 == appUser.getStatus()){
+ throw new RuntimeException("账户已被冻结,请联系系统管理员!");
+ }
+ }
+ }
+
@Override
public int getOrder() {
--
Gitblit v1.7.1