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 定义 ...
随机推荐
- Spring @Qualifier 注释
可能会有这样一种情况,当你创建多个具有相同类型的 bean 时,并且想要用一个属性只为它们其中的一个进行装配. 在这种情况下,你可以使用 @Qualifier 注释和 @Autowired 注释通过指 ...
- docker启动各种容器命令大全
安装步骤梳理 搜索镜像 拉取镜像 查看镜像 启动镜像 停止容器 移除容器 安装tomcat docker hub好查找tomcat镜像 docker search tomcat 从docker hu ...
- Xftp远程连接出现“无法显示文件夹”的问题补充
网上有很多朋友出现相同的问题,各位热心网友都给出了自己的解决方案,其中大多数网友给出的解决方案都是:将Xftp更换成“被动连接模式”.但是很不幸的是,本人通过这种方式并没有得到有效的解决,网上的各大方 ...
- SOFA入门
简介 scalable open financial architecture stack , 可扩展开放的金融架构栈: github: https://github.com/sofastack/so ...
- [安全] HTTPS的理解
一.概述 在下面的章节,我们要搞明白以下几个问题: HTTP和HTTPS的区别,为什么要使用HTTPS HTTPS如何解决加密问题 HTTPS如何避免中间人攻击 CA证书是什么 CA证书是如何申请和颁 ...
- [JavaWeb基础] 032.第三方插件pinyin4j的使用
突然发现了一个比较新奇的插件,就是可以把我们输入的汉字,输出它所有的拼音的jar包.下面以代码的形式简单的介绍下这个插件 package com.babybus.sdteam.pinyin4j; im ...
- [PHP学习教程 - 网络]002.$_SERVER["SCRIPT_NAME"]、$_SERVER["PHP_SELF"]、$_SERVER["QUERY_STRING"]、$_SERVER["REQUEST_URI"]介绍($_SERVER URL Infomation)
引言:在使用原生PHP的时候,对于URL路径的切割,如:域名,查询参数等等的提取,通常绝大多数兄弟会忽略$_SERVER中定义的内置常量的关系,这里为大家讲解一下. 常用的URL请求路径$_SERVE ...
- Java并没有衰落.大家对它的认识才刚刚开始 Java8全新出发
Java并没有衰落.大家对它的认识才刚刚开始 很高兴能在此给大家分享Java8的新特性.这篇文章将一步一步带你了解Java8的所有新特性.我将通过简单的实例代码向大家展示接口中默认方法,lambda ...
- python常见面试题讲解(十)数字颠倒
题目描述 描述: 输入一个整数,将这个整数以字符串的形式逆序输出 程序不考虑负数的情况,若数字含有0,则逆序形式也含有0,如输入为100,则输出为001 输入描述: 输入一个int整数 输出描述: 将 ...
- jchdl - RTL实例 - AndAnd
https://mp.weixin.qq.com/s/JhUB3M1WhjAyUrN1HPIPTA AndAnd是三输入与门模块,输出为相与的结果. 参考链接 https://github.c ...