一、添加自定义注解类
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义ip拦截注解
* @author 牛马
*/
@Target({ElementType.METHOD}) //在方法上运行
@Retention(RetentionPolicy.RUNTIME)
public @interface IpApiFilter{
/**
* 也可直接在注解中添加白名单(目前是以数据库添加的方式)
* @return
*/
String[] whiteIpList();
}
二、实现自定义拦截器
import com.alibaba.fastjson.JSONObject;
import com.kunyuan.annotation.IpApiFilter;
import com.kunyuan.constant.HttpStatus;
import com.kunyuan.utils.StringUtils;
import com.kunyuan.wangdian.domain.IpWhite;
import com.kunyuan.wangdian.mapper.WangDianMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @program: kunyuan
* @description: ip拦截器
* @author: 牛马
* @create: 2023-11-30 16:10
**/
@Component
public class IpInterceptor implements AsyncHandlerInterceptor {
@Resource
private WangDianMapper wangDianMapper;
public static IpInterceptor interceptor;
@PostConstruct
private void init() {
interceptor = this;
interceptor.wangDianMapper = this.wangDianMapper;
}
private static final Logger log = LoggerFactory.getLogger(IpInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 1.获取自定义注解
HandlerMethod handlerMethod = (HandlerMethod) handler;
// 注:判断是否添加了相应注解
IpApiFilter ipWhite = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), IpApiFilter.class);
if (ipWhite == null) {
return true;
}
// 2.获取客户端真实ip地址
String clientIp = getClientIpAddr(request);
// 3.校验ip地址(这里可以从数据库查ip校验)
List<IpWhite> whiteIpList = interceptor.wangDianMapper.getIpWhiteList();
// String[] whiteIpList = ipWhite.whiteIpList();
for (IpWhite ipList : whiteIpList) {
if (ipList.getIp().equals(clientIp)) {
return true;
}
}
fallback(clientIp, response);
return false;
}
private void fallback(String clientIp, HttpServletResponse response) {
response.setCharacterEncoding("UTF-8");
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
PrintWriter writer = null;
try {
String message = String.format("您的IP地址为[%s],已被系统禁止访问,请联系管理员处理!", clientIp);
Map<String, Object> map = new HashMap<>();
map.put("status", HttpStatus.FORBIDDEN);
map.put("msg", message);
JSONObject json = new JSONObject(map);
writer = response.getWriter();
writer.append(json.toString());
} catch (IOException e) {
log.error(String.valueOf(e));
} finally {
if (writer != null) {
writer.close();
}
}
}
private String getClientIpAddr(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
// 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
if (ip != null && ip.length() > 15) { // "***.***.***.***".length() = 15
if (ip.indexOf(",") > 0) {
ip = ip.substring(0, ip.indexOf(","));
}
}
return ip;
}
}
三、对应接口controller添加注解,whiteIpList 可以写死ip,但是目前我们使用的是动态读取数据库配置!
@RequestMapping(value = "/stockout/order/query/trade")
// ip白名单校验注解
@IpApiFilter(whiteIpList = {})
public R getStockoutOrder(@RequestBody WangDianParams wangDianParams) {
return wangDianService.getStockoutOrder(wangDianParams);
}
OK完美实现!