Springboot拦截器实现IP黑名单
Springboot拦截器实现IP黑名单
一·业务场景和需要实现的功能
以redis作为IP存储地址实现。
业务场景:针对秒杀活动或者常规电商业务场景等,防止恶意脚本不停的刷接口。
实现功能:写一个拦截器拦截掉黑名单IP,额外增加一个接口,将ip地址添加到redis中,并且返回redis中当前全部ip
二·Springboot中定义一个拦截器
@Order(0)
@Aspect
@Component
public class AopInterceptor {
/**
* 定义拦截器规则
*/
@Pointcut("execution(* com.test.test.api.controller.test.test.*(..))")
public void pointCut() {
}
/**
* 拦截器具体实现
*
* @throws Throwable
*/
@Around(value = "pointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
try {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
//判断是否为黑名单用户
String ip = getIpAddress(request);
if (checkIpBlack(ip)) {
//ip在黑名单中返回false
//return false;
DefaultResponse defaultResponse = new DefaultResponse();
defaultResponse.setCode(-1);
defaultResponse.setMessage("ip在黑名单中,拒绝访问.");
SysLogHelper.log("IpBlackAopInterceptor", "当前请求ip" + ip, "ip在黑名单中,拒绝访问");
return defaultResponse;
} else {
//ip不在黑名单中返回true
SysLogHelper.log("IpBlackAopInterceptor", "当前请求ip" + ip, "ip正常,允许访问");
return point.proceed();
}
} catch (Exception e) {
e.printStackTrace();
SysLogHelper.error("IpBlackAopInterceptor黑名单拦截异常:", ExceptionUtils.getMessage(e) + "详细" + ExceptionUtils.getStackTrace(e), null);
}
return point.getArgs();
}
//对比当前请求IP是否在黑名单中,注意(对比黑名单ip存放在redis中)
public boolean checkIpBlack(String ip) throws Exception {
IpBlackBody body = new IpBlackBody();
body = cacheHelper.get("IpBlack:ips", IpBlackBody.class);
if (body != null) {
for (int i = 0; i < body.getIp().length; i++) {
if (body.getIp()[i].equals(ip))
return true;
}
}
return false;
}
}
三·获取请求主机IP地址
public final static String getIpAddress(HttpServletRequest request)
throws IOException {
// 获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
if (ip == null || ip.length() == 0
|| "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0
|| "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0
|| "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0
|| "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0
|| "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
} else if (ip.length() > 15) {
String[] ips = ip.split(",");
for (int index = 0; index < ips.length; index++) {
String strIp = (String) ips[index];
if (!("unknown".equalsIgnoreCase(strIp))) {
ip = strIp;
break;
}
}
}
return ip;
}
四·扩展接口,实现将黑名单IP写入redis当中,并返回当前所有黑名单IP
@RestController
public class IpBlackController {
@Autowired(required = false)
private CacheHelper cacheHelper;
@PostMapping("/testIpBlack")
public IpBlackBody IpBlack(@RequestBody IpBlackBody ipBlackBody) throws Exception {
IpBlackBody body = new IpBlackBody();
body = cacheHelper.get("IpBlack:ips", IpBlackBody.class);
if (body != null) {
//拼接当前IP与redis中现有ip
linkArray(body.getIp(), ipBlackBody.getIp());
//将数据赋给body
body.setIp(linkArray(body.getIp(), ipBlackBody.getIp()));
//setex中第二个参数时间为S,根据业务场景相应调整,此处我设置为一天
//将body中拼接后的ip地址数据写入redis中
cacheHelper.setex("IpBlack:ips", 86400, body);
} else {
cacheHelper.setex("IpBlack:ips", 86400, ipBlackBody);
body = cacheHelper.get("IpBlack:ips", IpBlackBody.class);
return body;
}
return body;
}
//拼接两个String[]的方法
public static String[] linkArray(String[] array1, String[] array2) {
List<String> list = new ArrayList<>();
if (array1 == null) {
return array2;
}
if (array2 == null) {
return array1;
}
for (int i = 0; i < array1.length; i++) {
list.add(array1[i]);
}
for (int i = 0; i < array2.length; i++) {
list.add(array2[i]);
}
String[] returnValue = new String[list.size()];
for (int i = 0; i < list.size(); i++) {
returnValue[i] = list.get(i);
}
return returnValue;
}
}
总结:首先根据需要拦截的controller拦截响应请求controller层,然后根据编写相关拦截器的具体实现,其中包含两部主要操作:
1.获取到远程请求主机的实际ip地址
2.对比当前ip是否在黑名单中(此次操作需要读取redis中的黑名单ip列表)
然后根据当前需求增加了一个redis接口,实现将需要封禁的IP地址增加到redis黑名单中并返回当前所有的黑名单IP地址。
至此:至此springboot通过拦截器实现拦截黑名单功能已经实现。
Springboot拦截器实现IP黑名单的更多相关文章
- spring boot 学习(十二)拦截器实现IP黑名单
拦截器实现IP黑名单 前言 最近一直在搞 Hexo+GithubPage 搭建个人博客,所以没怎么进行 SpringBoot 的学习.所以今天就将上次的”?秒防刷新”进行了一番修改.上次是采用注解加拦 ...
- SpringBoot自定义拦截器实现IP白名单功能
SpringBoot自定义拦截器实现IP白名单功能 转载请注明源地址:http://www.cnblogs.com/funnyzpc/p/8993331.html 首先,相关功能已经上线了,且先让我先 ...
- Java结合SpringBoot拦截器实现简单的登录认证模块
Java结合SpringBoot拦截器实现简单的登录认证模块 之前在做项目时需要实现一个简单的登录认证的功能,就寻思着使用Spring Boot的拦截器来实现,在此记录一下我的整个实现过程,源码见文章 ...
- SpringBoot拦截器中Bean无法注入(转)
问题 这两天遇到SpringBoot拦截器中Bean无法注入问题.下面介绍我的思考过程和解决过程: 1.由于其他bean在service,controller层注入一点问题也没有,开始根本没意识到Be ...
- 【SpringBoot】SpringBoot拦截器实战和 Servlet3.0自定义Filter、Listener
=================6.SpringBoot拦截器实战和 Servlet3.0自定义Filter.Listener ============ 1.深入SpringBoot2.x过滤器Fi ...
- SpringBoot拦截器中无法注入bean的解决方法
SpringBoot拦截器中无法注入bean的解决方法 在使用springboot的拦截器时,有时候希望在拦截器中注入bean方便使用 但是如果直接注入会发现无法注入而报空指针异常 解决方法: 在注册 ...
- Springboot拦截器未起作用
之前遇到要使用springboot拦截器却始终未生效的状况,查了网上的博客,大抵都是@Component,@Configuration注解未加,或是使用@ComponentScan增加包扫描,但是尝试 ...
- SpringBoot拦截器中service或者redis注入为空的问题
原文:https://my.oschina.net/u/1790105/blog/1490098 这两天遇到SpringBoot拦截器中Bean无法注入问题.下面介绍我的思考过程和解决过程: 1.由于 ...
- springboot + 拦截器 + 注解 实现自定义权限验证
springboot + 拦截器 + 注解 实现自定义权限验证最近用到一种前端模板技术:jtwig,在权限控制上没有用springSecurity.因此用拦截器和注解结合实现了权限控制. 1.1 定义 ...
随机推荐
- 苏浪浪 201771010120 第三周 Java基本程序设计总结
理论知识: Java有五种语句: (1)方法调用语句(2)表达式语句(3)复合语句(4)控制语句(5)package.import语句 3.8控制流程 3.9大数值 *如果基本的整型和浮点型数据无法达 ...
- JVM调优总结(七)-调优方法
JVM调优工具 Jconsole,jProfile,VisualVM Jconsole : jdk自带,功能简单,但是可以在系统有一定负荷的情况下使用.对垃圾回收算法有很详细的跟踪.详细说明参考这里 ...
- mysql排序,同样的语句 查询结果不一样的问题
一个项目,某段数据顺序出现异常导致运行异常.早期没有问题,用开发版本也没有问题,同样的查询排序语句在mysql客户端执行也没有问题. 这个排序不一致问题,这里记录下. 如下查询语句,根据‘order’ ...
- 安卓全屏或沉浸式状态栏下输入框(EditText)被键盘遮挡解决方法
沉浸式状态栏用了一段时间了,一直没发现安卓在这方面的坑.最近在集成环信自定义UI的过程中,发现将环信界面设置为沉浸式之后最底部的消息输入框不随键盘弹起而变化了,一直显示在屏幕最下方,体验非常差. 后来 ...
- 设计带构造函数的Dog类 代码参考
#include <iostream> #include <string> using namespace std; class Dog { private: string n ...
- meavn项目由打包方式jar改为war报Cannot install Dynamic Web Module 2.5 facet. It is incompatibile with already installed facets: Utility Module. Please modify project configuration.处理方式
找到 \项目名\.setting\文件夹下的 org.eclipse.wst.common.project.facet.core.xml xml文件. 添加或修改 <installed ...
- html css javascript实现弹弹球
效果如图: 原创代码: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> & ...
- api.versioning 版本控制 自动识别最高版本
Microsoft.AspNetCore.Mvc.Versioning //引入程序集 .net core 下面api的版本控制作用不需要多说,可以查阅https://www.cnblogs.com/ ...
- Java实现 LeetCode 822 翻转卡片游戏(暴力)
822. 翻转卡片游戏 在桌子上有 N 张卡片,每张卡片的正面和背面都写着一个正数(正面与背面上的数有可能不一样). 我们可以先翻转任意张卡片,然后选择其中一张卡片. 如果选中的那张卡片背面的数字 X ...
- Java实现 LeetCode 467 环绕字符串中唯一的子字符串
467. 环绕字符串中唯一的子字符串 把字符串 s 看作是"abcdefghijklmnopqrstuvwxyz"的无限环绕字符串,所以 s 看起来是这样的:"-zabc ...