springboot如何使用全局拦截器,并且使用过滤器实现快速失败

前言

简单说一下需求

要做一个项目,简单保证系统内部的安全性,然后还要防止高并发的攻击,于是就要对进入系统的请求做一些限制,其实也就是如何做快速失败,这里我使用的是过滤器来实现的,对于不必要的请求,直接过滤掉就可以了。

思路

  1. 签名算法校验参数有效性,无效直接返回 403
  2. token 校验,拿着 tokenredis 中进行比对,如果 token 校验失败,同样直接返回 403

签名算法是什么

为了防止API调用过程中被黑客恶意篡改,调用任何一个API都需要携带签名,服务端会根据请求参数,对签名进行验证,签名不合法的请求将会被拒绝。

如果我们正常的http请求参数是这样的

{
	"param1": "aaa",
	"param2": "bbb"
}

加了签名之后的参数就是这样的

{
	"param1": "aaa",
	"param2": "bbb",
	"sign": "f2f8ba7d0ac080bf"
}

加了签名之后多了一个名为 sign 的参数,这个sign就是在客户端或者web端对参数进行加密的结果
大概加密就是把参数全部合在一起进行md5加密的结果,到了服务端,再对参数进行一次加密,比对一下和参数重的sign是否相同就好了
在这里插入图片描述

说几句

  1. 逻辑不复杂,稍微用心看点就可以看明白
  2. md5算法可以更换,换成任意自己喜欢的,但是,要保证客户端与服务端的一致
  3. token校验暂且不写,token校验如果写的话还可以单另写一篇,这篇主要讲过滤器实现
  4. 如果有需要,我上传github之后,再来贴链接,或者在下面评论也可以,我每条评论都看
  5. 我认为,大家需要学习的不是代码怎么写,而是要怎么去思考,一旦思考停止了,那就都没意义了

贴代码

ValidParamsFilter

校验参数有效性的过滤器

package com.stu.filter;

import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import java.io.*;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

/**
 * <p>
 * 校验参数有效性的过滤器
 * </p>
 *
 * @author Banana
 * @since 2021/1/30
 */

//@WebFilter(filterName = "validParamsFilter", urlPatterns = "/*")
@Component
public class ValidParamsFilter implements Filter {


    //这里面 填写不需要 被拦截的地址
    private static final Set<String> ALLOWED_PATHS = Collections.unmodifiableSet(
            new HashSet<String>(Arrays.asList("/login", "/isLogin", "/findCategory"))
    );

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        Map<String, String> map;

        // 一个request的包装类,初始化时缓存了body,重写了getInputStream返回缓存的body,实现重复读取body
        BodyReaderRequestWrapper requestWrapper = new BodyReaderRequestWrapper(request);
        String body = ReqGetBody.getBody(requestWrapper);

        boolean flag = false;
        try {
            if (!body.isEmpty()) {
                map = (Map<String, String>) JSON.parse(body);
                // 签名校验算法
                flag = ValidParamUtils.valid(map);
            }
        } catch (Exception e) {
            // 可以记录一下用户行为
        }

        if (flag) {
            filterChain.doFilter(requestWrapper, response);
        } else {
            response.sendError(403, "param valid fail!!!");
        }

    }
}

ValidParamUtils

用来校验参数有效性的小算法

package com.stu.filter;

import java.util.Arrays;
import java.util.Map;

/**
 * <p>
 *
 * </p>
 *
 * @author Banana
 * @since 2021/2/1
 */

public class ValidParamUtils {

    public static Boolean valid(Map<String, String> params) {
        String headerSign = params.get("sign");
        if (headerSign == null) return false;

        params.remove("sign");

        // 第一步:检查参数是否已经排序
        String[] keys = params.keySet().toArray(new String[0]);
        Arrays.sort(keys);

        // 第二步:把所有参数名和参数值串在一起
        StringBuilder query = new StringBuilder();
        for (String key : keys) {
            String value = params.get(key);
            query.append(key).append(value);
        }

        String paramsString = query.toString();
        String sign = MD5Utils.getMD5Str(paramsString);

        return sign.equals(headerSign);
    }
}

FilterConfig

这里用来注入filter,因为需要控制filter开启关闭,所以我把开关抽象在了配置文件中

package com.stu.config;

import com.stu.filter.ValidParamsFilter;
import com.stu.filter.ValidTokenFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * <p>
 *
 * </p>
 *
 * @author 刁琳童
 * @since 2021/1/30
 */

@Configuration
public class FilterConfig {

    @Value("${filter.valid-param}")
    private Boolean validParam;

    @Value("${filter.valid-token}")
    private Boolean validToken;

    @Autowired
    private ValidParamsFilter validParamsFilter;

    @Autowired
    private ValidTokenFilter validTokenFilter;

    @Bean
    public FilterRegistrationBean validParamsFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean(validParamsFilter);
        registration.addUrlPatterns("/*");
        registration.setName("validParamsFilter");
        registration.setEnabled(validParam);
        registration.setOrder(1);
        return registration;
    }

    @Bean
    public FilterRegistrationBean validTokenFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean(validTokenFilter);
        registration.addUrlPatterns("/*");
        registration.setName("validTokenFilter");
        registration.setEnabled(validToken);
        registration.setOrder(2);
        return registration;
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
在Spring Boot中,可以使用@ControllerAdvice注解和@ExceptionHandler注解来实现异常拦截。在给定的引用\[1\]中,GlobalExceptionHandler类使用@ControllerAdvice注解和@ExceptionHandler注解来处理全局异常。该类中的exceptionHandler方法接收HttpServletRequest和Exception参数,并根据异常的类型进行不同的处理逻辑。如果异常是GlobalException类型,则返回对应的错误信息;如果异常是BindException类型,则返回绑定错误的信息;否则返回服务错误的信息。 与拦截相比,过滤器(Filter)是Servlet技术的一部分,用于对所有访问进行增强。而拦截(Interceptor)是Spring MVC技术的一部分,仅对Spring MVC的访问进行增强。引用\[2\]中提到了拦截过滤器的区别,拦截只对Spring MVC的访问进行增强,而过滤器对所有访问进行增强。 在给定的引用\[3\]中,展示了一个处理登录业务的service代码。该代码中的login方法接收一个LoginVal对象作为参数,并根据参数进行登录验证。如果参数为null,则抛出全局异常;如果根据手机号查询不到用户,则抛出相应的异常;如果密码不匹配,则抛出密码错误的异常;否则返回true表示登录成功。 综上所述,Spring Boot中的异常拦截可以通过@ControllerAdvice注解和@ExceptionHandler注解来实现拦截过滤器的区别在于归属和内容,而service中的代码可以根据业务需求进行异常处理。 #### 引用[.reference_title] - *1* *3* [SpringBoot 全局异常拦截](https://blog.csdn.net/weixin_38405253/article/details/122019429)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Springboot——拦截](https://blog.csdn.net/weixin_51351637/article/details/128058053)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Geek-Banana

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

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

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

打赏作者

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

抵扣说明:

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

余额充值