Springboot拦截器IP防刷 + IP黑名单功能

为了方便查看 尽量把方法都放到一个文件内

先创建一个WebMvcConfigurer

@Configuration
@EnableConfigurationProperties(FileUploadProperties.class)
public class WebMvcConfigurer extends WebMvcConfigurationSupport {

	// 前面省略...
	
	@Bean
    public UserUrlInterceptor userUrlInterceptor() {
        return new UserUrlInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(userUrlInterceptor()).addPathPatterns("/**").excludePathPatterns("/sys/getVerifyToBase");
    }
}

接下来进入拦截器内部 UserUrlInterceptor

@Component
public class UserUrlInterceptor implements HandlerInterceptor {

    private static final int time = 30000;
    private static final int count = 10;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @Autowired
    private BlacklistService blacklistService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 获取请求的url
        String url = request.getRequestURI();
        String ip = IPUtils.getIpAddr(request);

        BlacklistEntity domain = blacklistService.getByIP(ip);
        if (domain != null) {
            domain.setDisableTime(new Date(new Date().getTime() + 300000));
            blacklistService.saveOrUpdate(domain);
            throw new BusinessException(BaseResponseCode.IP_BANNED.getCode(), BaseResponseCode.IP_BANNED.getMsg());
        };

        StringBuilder sb = new StringBuilder();
        sb.append("crazeidea:").append(ip).append(url);
        // 先查询redis中是否有这个键
        String key = sb.toString().replaceAll("/", ".");
        String value = get(key);
        if (StringUtils.isBlank(value)) {
            // 为空则插入新数据
            set(key, "1", time);
        } else {
            if ("/website/other/contactus".equals(request.getRequestURI())) {
                // 为联系我们的时候 不能重复提交
                set(key, "1", 60000 * 10);
                throw new BusinessException(BaseResponseCode.CONTACT_US.getCode(), BaseResponseCode.CONTACT_US.getMsg());
            }
            if (Integer.parseInt(value) < count) {
                // 没有超过就累加
                long redisTime = getExpire(key);
                set(key, (Integer.parseInt(value) + 1) + "", Math.toIntExact(redisTime));
            } else {
                // 超过访问次数
                String cou = get(ip);
                if (StringUtils.isBlank(cou)) {
                    setNoTime(ip, "1");
                } else {
                    if (Integer.parseInt(cou) <= 5) {
                        setNoTime(ip, (Integer.parseInt(cou) + 1) + "");
                    } else {
                        // 超过访问次数 5次以上 进入黑名单
                        blacklistService.save(init(ip));
                        del(ip);
                    }
                }
                throw new BusinessException(BaseResponseCode.LIMIT_ERROR_USER.getCode(), BaseResponseCode.LIMIT_ERROR_USER.getMsg());
            }
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {

    }

    public BlacklistEntity init(String ip) {
        BlacklistEntity domain = new BlacklistEntity();
        domain.setIp(ip);
        domain.setDisableTime(new Date(new Date().getTime() + 300000));
        return domain;
    }

    // 根据key获取value
    public String get(String key) {
        return this.redisTemplate.opsForValue().get(key);
    }

    // 根据key删除数据
    public void del(String key) {
        boolean boo = this.redisTemplate.hasKey(key);
        if (boo) {
            this.redisTemplate.delete(key);
        }
    }

    // 向redis存入数据
    public void setNoTime(String key, String value) {
        redisTemplate.opsForValue().set(key, value);
    }

    // 向redis存入数据 带失效时间
    public void set (String key, String value, int redisTime) {
        redisTemplate.opsForValue().set(key, value);
        redisTemplate.expire(key, redisTime, TimeUnit.MILLISECONDS);
    }

    // 获取redis当前键的失效时间
    public Long getExpire(String key) {
        if (null == key) {
            throw new BusinessException(BaseResponseCode.DATA_ERROR.getCode(), "key or TomeUnit 不能为空");
        }
        return redisTemplate.getExpire(key, TimeUnit.MILLISECONDS);
    }

}

接下来就是黑名单了 创建BlackListEntity实体

@Data
@TableName("blacklist")
public class BlacklistEntity extends BaseEntity implements Serializable {
	private static final long serialVersionUID = 1L;

	/**
	 * 主键
	 */
	@TableId("id")
	@ApiModelProperty(value = "id")
	private String id;

	/**
	 * IP
	 */
	@TableField("ip")
	@ApiModelProperty(value = "ip")
	private String ip;

	/**
	 * 黑名单结束时间
	 */
	@TableField("disable_time")
	@ApiModelProperty(value = "disable_time")
	private Date disableTime;

	/**
	 * 创建时间
	 */
	@TableField("create_time")
	@ApiModelProperty(value = "create_time")
	private Date createTime;

	/**
	 * 更新时间
	 */
	@TableField("update_time")
	@ApiModelProperty(value = "update_time")
	private Date updateTime;

	/**
	 * 是否删除(1未删除;0已删除)
	 */
	@TableField("deleted")
	@ApiModelProperty(value = "deleted")
	private Integer deleted;


}

数据库表设计

CREATE TABLE `blacklist` (
  `id` varchar(64) NOT NULL COMMENT '主键',
  `ip` varchar(255) DEFAULT NULL COMMENT 'IP',
  `disable_time` datetime DEFAULT NULL COMMENT '黑名单结束时间',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  `deleted` tinyint(4) DEFAULT '1' COMMENT '是否删除(1未删除;0已删除)',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='IP黑名单';

使用mybatis-plus
感谢观看!!!如果喜欢望一键三连 0v0

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

欧阳锋feng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值