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 定义 ...
随机推荐
- MyCat垂直分库
一.什么是垂直分库 将一类功能的表从一个实例切分到另一个实例,横向扩展实例,增加写负载 目标:将1个实例的4类表拆分多4个实例中 二.垂直切分步骤 2.1收集分析业务模块间的关系,能分几个库 2.2全 ...
- [转载] Objectiv-C 入门一二三
http://my.oschina.net/fuckphp/blog/92993 http://my.oschina.net/fuckphp/blog/93217 http://my.oschina. ...
- IDEA启动springboot项目找不到application.yml配置文件
idea启动项目时读取不到application-pro.yml文件,但是配置文件都在resource目录下: 解决:target/classes 目录是IDEA的classpath目录,项目编译后配 ...
- 全局设置UITableView的属性|正确计算contentSize|MJRefresh mj_footer 能正常隐藏在底部,不因为数据过少展示在页面中部
可在AppDelegate中设置 if (@available(iOS 11.0, *)) { UITableView.appearance.estimatedRowHeight = 0; UITab ...
- poj2449第K小路径问题
Remmarguts' Date Time Limit: 4000MS Memory Limit: 65536K Total Submissions: 30017 Accepted: 8159 ...
- 五、数据类型(1):整数&&带小数点的数
1.整数 int printf("%d",...); scanf("%d",&...); 2.带小数点的数 double printf("%f ...
- 15-2 insert语句介绍
create table TblClass ( tClassId ,) primary key, tClassName ) ) --向班级表中插入一条记录 --insert into 表名(列1,列2 ...
- WordPress免插件生成完整站点地图(sitemap.xml)的php代码
让这个代码更加完善,可以同时生成首页.文章.单页面.分类和标签的 sitemap! 一.PHP 代码 <?php require('./wp-blog-header.php'); header( ...
- Spring_管理bean的生命周期
Spring IOC 容器对 Bean 的生命周期进行管理的过程:通过构造器或工厂方法创建 Bean 实例为 Bean 的属性设置值和对其他 Bean 的引用将 Bean 实例传递给 Bean 后置处 ...
- LM NTML NET-NTLM2理解及hash破解
LM Windows Vista / Server 2008已经默认关闭,在老版本可以遇到,但根据windwos的向下兼容性,可以通过组策略启用它(https://support.microsoft. ...