From ff169f9a0417b73f0afac554cf2f9d048ac56c80 Mon Sep 17 00:00:00 2001 From: 无关风月 <443237572@qq.com> Date: 星期一, 19 八月 2024 20:57:08 +0800 Subject: [PATCH] Merge branch 'master' of http://120.76.84.145:10101/gitblit/r/java/mx_charging_pile --- ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/AuthFilter.java | 305 +++++++++++++++++++++++++++++++++----------------- 1 files changed, 200 insertions(+), 105 deletions(-) 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 e829417..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,113 +24,209 @@ 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; + /** * 网关鉴权 - * + * * @author ruoyi */ @Component public class AuthFilter implements GlobalFilter, Ordered { - private static final Logger log = LoggerFactory.getLogger(AuthFilter.class); - - // 排除过滤的 uri 地址,nacos自行添加 - @Autowired - private IgnoreWhiteProperties ignoreWhite; - - @Autowired - private RedisService redisService; - - - @Override - public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { - ServerHttpRequest request = exchange.getRequest(); - ServerHttpRequest.Builder mutate = request.mutate(); - - String url = request.getURI().getPath(); - // 跳过不需要验证的路径 - if (StringUtils.matches(url, ignoreWhite.getWhites())) { - return chain.filter(exchange); - } - 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); - addHeader(mutate, SecurityConstants.DETAILS_USER_ID, userid); - addHeader(mutate, SecurityConstants.DETAILS_USERNAME, username); - // 内部请求来源参数清除 - removeHeader(mutate, SecurityConstants.FROM_SOURCE); - return chain.filter(exchange.mutate().request(mutate.build()).build()); - } - - private void addHeader(ServerHttpRequest.Builder mutate, String name, Object value) { - if (value == null) { - return; - } - String valueStr = value.toString(); - String valueEncode = ServletUtils.urlEncode(valueStr); - mutate.header(name, valueEncode); - } - - private void removeHeader(ServerHttpRequest.Builder mutate, String name) { - mutate.headers(httpHeaders -> httpHeaders.remove(name)).build(); - } - - private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, String msg) { - log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath()); - return ServletUtils.webFluxResponseWriter(exchange.getResponse(), msg, HttpStatus.UNAUTHORIZED); - } - - /** - * 获取缓存key - */ - private String getTokenKey(String token) - { - return CacheConstants.LOGIN_TOKEN_KEY + token; - } - - /** - * 获取请求token - */ - private String getToken(ServerHttpRequest request) { - String token = request.getHeaders().getFirst(TokenConstants.AUTHENTICATION); - // 如果前端设置了令牌前缀,则裁剪掉前缀 - if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX)) - { - token = token.replaceFirst(TokenConstants.PREFIX, StringUtils.EMPTY); - } - return token; - } - - - @Override - public int getOrder() - { - return -300; - } + private static final Logger log = LoggerFactory.getLogger(AuthFilter.class); + + // 排除过滤的 uri 地址,nacos自行添加 + @Autowired + private IgnoreWhiteProperties ignoreWhite; + + @Autowired + private RedisService redisService; + + @Resource + private AppUserClient appUserClient; + + @Resource + private SysUserClient sysUserClient; + + + + @Override + public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { + ServerHttpRequest request = exchange.getRequest(); + ServerHttpRequest.Builder mutate = request.mutate(); + + String url = request.getURI().getPath(); + // 跳过不需要验证的路径 + 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); + Claims claims = JwtUtils.parseToken(token); + String userkey = JwtUtils.getUserKey(claims); + String userid = JwtUtils.getUserId(claims); + String username = JwtUtils.getUserName(claims); + + // 设置用户信息到请求 + addHeader(mutate, SecurityConstants.USER_KEY, userkey); + addHeader(mutate, SecurityConstants.DETAILS_USER_ID, userid); + addHeader(mutate, SecurityConstants.DETAILS_USERNAME, username); + // 内部请求来源参数清除 + removeHeader(mutate, SecurityConstants.FROM_SOURCE); + return chain.filter(exchange.mutate().request(mutate.build()).build()); + } + + private void addHeader(ServerHttpRequest.Builder mutate, String name, Object value) { + if (value == null) { + return; + } + String valueStr = value.toString(); + String valueEncode = ServletUtils.urlEncode(valueStr); + mutate.header(name, valueEncode); + } + + private void removeHeader(ServerHttpRequest.Builder mutate, String name) { + mutate.headers(httpHeaders -> httpHeaders.remove(name)).build(); + } + + private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, String msg) { + log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath()); + return ServletUtils.webFluxResponseWriter(exchange.getResponse(), msg, HttpStatus.UNAUTHORIZED); + } + + /** + * 获取缓存key + */ + private String getTokenKey(String token) { + return CacheConstants.LOGIN_TOKEN_KEY + token; + } + + /** + * 获取请求token + */ + private String getToken(ServerHttpRequest request) { + String token = request.getHeaders().getFirst(TokenConstants.AUTHENTICATION); + // 如果前端设置了令牌前缀,则裁剪掉前缀 + if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX)) { + token = token.replaceFirst(TokenConstants.PREFIX, StringUtils.EMPTY); + } + return token; + } + + + /** + * 防抖处理 + */ + 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() { + return -300; + } } \ No newline at end of file -- Gitblit v1.7.1