| | |
| | | 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; |
| | |
| | | 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; |
| | | |
| | | |
| | | /** |
| | | * 网关鉴权 |
| | |
| | | @Autowired |
| | | private RedisService redisService; |
| | | |
| | | @Resource |
| | | private AppUserClient appUserClient; |
| | | |
| | | @Resource |
| | | private SysUserClient sysUserClient; |
| | | |
| | | |
| | | |
| | | @Override |
| | | public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { |
| | |
| | | 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); |
| | |
| | | /** |
| | | * 防抖处理 |
| | | */ |
| | | 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() { |