Commit 5db3bca0 authored by 向怀芳's avatar 向怀芳 🎱

1. IP白名单03

parent 48c7badf
......@@ -12,6 +12,7 @@ import lombok.Getter;
@AllArgsConstructor
public enum BizCodeConstant {
/* */
USER_PWD_LIMIT(99,""),
TEMP(0,"");
private Integer code;
......
......@@ -193,6 +193,37 @@ public class WebUtils extends org.springframework.web.util.WebUtils {
return StringUtils.isBlank(ip) ? null : ip.split(",")[0];
}
public String getIP(ServerHttpRequest request) {
HttpHeaders headers = request.getHeaders();
String ip = headers.getFirst("x-forwarded-for");
if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
// 多次反向代理后会有多个ip值,第一个ip才是真实ip
if (ip.indexOf(",") != -1) {
ip = ip.split(",")[0];
}
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = headers.getFirst("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = headers.getFirst("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = headers.getFirst("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = headers.getFirst("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = headers.getFirst("X-Real-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddress().getAddress().getHostAddress();
}
return ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
}
/**
* 从request 获取CLIENT_ID
*
......
package cn.sh.stc.sict.cloud.common.gateway.config;
import lombok.Data;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;
/**
* @Description 网关不校验终端配置
* @Author
* @Date
*/
@Data
@Configuration
@RefreshScope
@ConditionalOnExpression("!'${whiteip}'.isEmpty()")
@ConfigurationProperties(prefix = "whiteip")
public class WhitIPConfig {
private List<String> whites = new ArrayList<>();
}
package cn.sh.stc.sict.cloud.common.gateway.filter;
import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.cloud.common.core.constant.SecurityConstants;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.core.util.WebUtils;
import cn.sh.stc.sict.cloud.common.gateway.config.WhitIPConfig;
import cn.sh.stc.sict.cloud.common.gateway.util.IPStrUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
......@@ -18,57 +28,85 @@ import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.G
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.addOriginalRequestUrl;
/**
* @Description
* <p>
* 全局拦截器,作用所有的微服务
* <p>
* 1. 对请求头中参数进行处理 from 参数进行清洗
* 2. 重写StripPrefix = 1,支持全局
* <p>
* 支持swagger添加X-Forwarded-Prefix header (F SR2 已经支持,不需要自己维护)
* @Description <p>
* 全局拦截器,作用所有的微服务
* <p>
* 1. 对请求头中参数进行处理 from 参数进行清洗
* 2. 重写StripPrefix = 1,支持全局
* <p>
* 支持swagger添加X-Forwarded-Prefix header (F SR2 已经支持,不需要自己维护)
* @Author
* @Date
*/
@Slf4j
@Component
@AllArgsConstructor
public class RequestGlobalFilter implements GlobalFilter, Ordered {
private static final String HEADER_NAME = "X-Forwarded-Prefix";
private static final String HEADER_NAME = "X-Forwarded-Prefix";
private final WhitIPConfig whitIPConfig;
private final ObjectMapper objectMapper;
/**
* Process the Web request and (optionally) delegate to the next
* {@code WebFilter} through the given {@link GatewayFilterChain}.
*
* @param exchange the current server exchange
* @param chain provides a way to delegate to the next filter
* @return {@code Mono<Void>} to indicate when request processing is complete
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1. 清洗请求头中from 参数
ServerHttpRequest request = exchange.getRequest().mutate()
.headers(httpHeaders -> {httpHeaders.remove(SecurityConstants.FROM);})
.build();
/**
* Process the Web request and (optionally) delegate to the next
* {@code WebFilter} through the given {@link GatewayFilterChain}.
*
* @param exchange the current server exchange
* @param chain provides a way to delegate to the next filter
* @return {@code Mono<Void>} to indicate when request processing is complete
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1. 清洗请求头中from 参数
ServerHttpRequest request = exchange.getRequest().mutate()
.headers(httpHeaders -> {
httpHeaders.remove(SecurityConstants.FROM);
})
.build();
// IP白名单
log.error("RemoteAddress ===================> {}", request.getRemoteAddress());
// IP白名单
String ip = WebUtils.getIP(request);
log.error("RemoteAddress ===================> {}", request.getRemoteAddress());
try {
if (!IPStrUtil.matches(ip, whitIPConfig.getWhites())) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.PRECONDITION_REQUIRED);
response.getHeaders().set("Content-type", "application/json; charset=utf-8");
return response.writeWith(Mono.just(response.bufferFactory()
.wrap(objectMapper.writeValueAsBytes(
R.builder().msg("没有权限访问")
.code(Constant.BYTE_NO).build()))));
}
} catch (
Exception e) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.PRECONDITION_REQUIRED);
response.getHeaders().set("Content-type", "application/json; charset=utf-8");
try {
return response.writeWith(Mono.just(response.bufferFactory()
.wrap(objectMapper.writeValueAsBytes(
R.builder().msg(e.getMessage())
.code(Constant.BYTE_NO).build()))));
} catch (JsonProcessingException e1) {
log.error("对象输出异常", e1);
}
}
// 2. 重写StripPrefix
addOriginalRequestUrl(exchange, request.getURI());
String rawPath = request.getURI().getRawPath();
String newPath = "/" + Arrays.stream(StringUtils.tokenizeToStringArray(rawPath, "/"))
.skip(1L).collect(Collectors.joining("/"));
ServerHttpRequest newRequest = request.mutate()
.path(newPath)
.build();
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, newRequest.getURI());
// 2. 重写StripPrefix
addOriginalRequestUrl(exchange, request.getURI());
String rawPath = request.getURI().getRawPath();
String newPath = "/" + Arrays.stream(StringUtils.tokenizeToStringArray(rawPath, "/"))
.skip(1L).collect(Collectors.joining("/"));
ServerHttpRequest newRequest = request.mutate()
.path(newPath)
.build();
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, newRequest.getURI());
return chain.filter(exchange.mutate()
.request(newRequest.mutate()
.build()).build());
}
return chain.filter(exchange.mutate()
.request(newRequest.mutate()
.build()).build());
}
@Override
public int getOrder() {
return -1000;
}
@Override
public int getOrder() {
return -1000;
}
}
package cn.sh.stc.sict.cloud.common.gateway.util;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import java.util.List;
public class IPStrUtil {
static char START = '*';
/**
* 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
*
* @param str 指定字符串
* @param strs 需要检查的字符串数组
* @return 是否匹配
*/
public static boolean matches(String str, List<String> strs) {
if (StrUtil.isEmpty(str) || CollUtil.isEmpty(strs)) {
return false;
}
for (String testStr : strs) {
if (matches(str, testStr)) {
return true;
}
}
return false;
}
/**
* 查找指定字符串是否匹配指定字符串数组中的任意一个字符串
*
* @param str 指定字符串
* @param strs 需要检查的字符串数组
* @return 是否匹配
*/
public static boolean matches(String str, String... strs) {
if (StrUtil.isEmpty(str) || StrUtil.isAllEmpty(str)) {
return false;
}
for (String testStr : strs) {
if (matches(str, testStr)) {
return true;
}
}
return false;
}
/**
* 查找指定字符串是否匹配
*
* @param str 指定字符串
* @param pattern 需要检查的字符串
* @return 是否匹配
*/
public static boolean matches(String str, String pattern) {
if (StrUtil.isEmpty(pattern) || StrUtil.isEmpty(str)) {
return false;
}
pattern = pattern.replaceAll("\\s*", ""); // 替换空格
int beginOffset = 0; // pattern截取开始位置
int formerStarOffset = -1; // 前星号的偏移位置
int latterStarOffset = -1; // 后星号的偏移位置
String remainingURI = str;
String prefixPattern = "";
String suffixPattern = "";
boolean result = false;
do {
formerStarOffset = StrUtil.indexOf(pattern, START, beginOffset);
prefixPattern = StrUtil.sub(pattern, beginOffset, formerStarOffset > -1 ? formerStarOffset : pattern.length());
// 匹配前缀Pattern
result = remainingURI.contains(prefixPattern);
// 已经没有星号,直接返回
if (formerStarOffset == -1) {
return result;
}
// 匹配失败,直接返回
if (!result)
return false;
if (!StrUtil.isEmpty(prefixPattern)) {
remainingURI = StrUtil.subAfter(str, prefixPattern, true);
}
// 匹配后缀Pattern
latterStarOffset = StrUtil.indexOf(pattern, START, formerStarOffset + 1);
suffixPattern = StrUtil.sub(pattern, formerStarOffset + 1, latterStarOffset > -1 ? latterStarOffset : pattern.length());
result = remainingURI.contains(suffixPattern);
// 匹配失败,直接返回
if (!result)
return false;
if (!StrUtil.isEmpty(suffixPattern)) {
remainingURI = StrUtil.subAfter(str, suffixPattern, true);
}
// 移动指针
beginOffset = latterStarOffset + 1;
}
while (!StrUtil.isEmpty(suffixPattern) && !StrUtil.isEmpty(remainingURI));
return true;
}
@SuppressWarnings("unchecked")
public static <T> T cast(Object obj) {
return (T) obj;
}
}
......@@ -142,6 +142,8 @@ public class SysUserBase extends Model<SysUserBase> {
@ApiModelProperty(hidden = true, value = "")
private Date updateTime;
private Date lastPwdTime;
/**
* 主键值
*/
......
......@@ -2,6 +2,7 @@ package cn.sh.stc.sict.cloud.upms.controller.web;
import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.cloud.common.core.constant.enums.BizCodeConstant;
import cn.sh.stc.sict.cloud.common.core.util.NumberUtil;
import cn.sh.stc.sict.cloud.common.log.annotation.SysLog;
import cn.sh.stc.sict.cloud.common.security.util.SecurityUtils;
......@@ -118,7 +119,7 @@ public class SysUserBaseController {
dto.setRoleList(roleList);
dto.setMenuList(menuList);
return new R(dto);
return new R(dto).setBizCode(BizCodeConstant.USER_PWD_LIMIT.getCode());
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment