Java中的拦截器配置-- HandlerInterceptor

========================
开发记录:拦截器配置笔记(token认证拦截器和JWT校验拦截器)
1、创建配置类WebInterceptorConfig实现WebMvcConfigurer;
2、向InterceptorRegistry中依次注册拦截器;
3、总结:多个拦截器的执行顺序

1. 配置类WebInterceptorConfig

package com.tal.markms.config;

import com.tal.markms.interceptor.AuthenticationInterceptor;
import com.tal.markms.interceptor.JWTInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;


@Configuration
public class WebInterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new AuthenticationInterceptor())
                .addPathPatterns("/markms/login");
        registry.addInterceptor(new JWTInterceptor())
                .addPathPatterns("/**").excludePathPatterns("/markms/login");
    }
}

2.1 创建AuthenticationInterceptor拦截器

package com.tal.markms.interceptor;

import com.tal.markms.exception.BizException;
import com.tal.markms.exception.ErrorCode;
import com.tal.markms.utils.EmptyHelper;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.UUID;

import static com.tal.markms.common.CommonConstant.RPCID;
import static com.tal.markms.common.CommonConstant.TRACEID;


@Slf4j
@Component
public class AuthenticationInterceptor implements HandlerInterceptor {

    private static String token;

    @Value("${server-access.token}")
    public void setToken(String token) {
        AuthenticationInterceptor.token = token;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        log.info("AuthenticationInterceptor preHandle start ==== ");
        MDC.put("startTime", String.valueOf(System.currentTimeMillis()));

        String token = request.getHeader("token");
        if (EmptyHelper.isEmpty(token)) {
            log.info(" token is null ==== ");
            throw new BizException(ErrorCode.SystemError.ERROR_TOKEN_NULL);
        }
        if (!token.equals(AuthenticationInterceptor.token)) {
            log.info(" token is not match ==== ");
            throw new BizException(ErrorCode.SystemError.ERROR_TOKEN_NOT_MATCH);
        }
        String traceId = request.getHeader(TRACEID);
        if (EmptyHelper.isEmpty(traceId)) {
            traceId = UUID.randomUUID().toString().replace("-", "");
            log.info("traceId is null, generate traceId: {} ", traceId);
        }
        log.info("traceId:{}", traceId);
        MDC.put("traceId", traceId);

        String rpcId = request.getHeader(RPCID);
        if (EmptyHelper.isEmpty(rpcId)) {
            rpcId = "1.1";
            log.info("rpcId is null, generate rpcId: {} ", rpcId);
        }
        MDC.put("rpcId", rpcId);
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("responseEnd, useTime:{}", System.currentTimeMillis() - Long.parseLong(MDC.get("startTime")));
        MDC.clear();
    }
}

2.2 创建JWTInterceptor拦截器

package com.tal.markms.interceptor;

import com.tal.markms.config.JWTWebConfig;
import com.tal.markms.utils.JWTUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class JWTInterceptor implements HandlerInterceptor {

    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) {
        try {
            String token = httpServletRequest.getHeader("JWT");

            if (token == null) {
                refuseResult(httpServletResponse);
                return false;
            }
            if(!JWTUtils.verify(token)){
                //先检查并更新 后用更新后的再次校验
                if(JWTWebConfig.checkAndRefreshSecretKey()||!JWTUtils.verify(token)){
                    refuseResult(httpServletResponse);
                    return false;
                }
            }
            return true;
        }catch (Exception e){
            try {
                refuseResult(httpServletResponse);
                return false;
            }catch (Exception exception){
                return false;
            }
        }
    }

    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

    }

    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

    }

    public void refuseResult(HttpServletResponse httpServletResponse){
        try {
            httpServletResponse.setContentType("text/html;charset=UTF-8");
            httpServletResponse.setCharacterEncoding("UTF-8");
            httpServletResponse.setStatus(200);
            httpServletResponse.getWriter().print("{\"code\":2001,\"message\":\"登录信息有误或已失效,请重新登录\"}");
            httpServletResponse.getWriter().flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
创建JWT配置类设置JWT公钥、私钥、加密算法、过期时间:
package com.tal.markms.config;

import com.auth0.jwt.algorithms.Algorithm;
import com.tal.markms.enums.EnvEnum;
import com.tal.markms.factory.AlgorithmFactory;
import com.tal.markms.interceptor.JWTInterceptor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.json.JacksonJsonParser;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.annotation.PostConstruct;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;


@Configuration
public class JWTWebConfig implements WebMvcConfigurer {

    public static String PUBLIC_KEY = "2580eb1e23fa21a84117bbd865f038a5";
    public static String PRIVATE_KEY = "2580eb1e23fa21a84117bbd865f038a5";
    public static final long EXPIRES_TIME = 60*60*1000*24*5L;

    @Value("${jwt.interceptor.paths:}")
    String interceptorPaths;

    @Value("${jwt.interceptor.exclude.paths:}")
    String excludePaths;

    @Value("${jwt.algorithm:}")
    String algorithmStr;

    public static String url;


    private static Algorithm algorithm;

    EnvEnum envEnum;

    @Value("${jwt.public_key:}")
    public void setPublicKey(String arg){
        PUBLIC_KEY =arg;
    }

    @Value("${jwt.private_key:}")
    public void setPrivateKey(String arg){
        PRIVATE_KEY =arg;
    }

    @Value("${jwt.url:}")
    public void setURL(String arg){
        url=arg;
    }

    @Value("${jwt.env:}")
    public void setEnv(String env) {
        if(env == null || "".equals(env)){
            env = "DEV";
        }
        envEnum = EnvEnum.valueOf(env.toUpperCase());
    }

    @PostConstruct
    protected void init() throws Exception {
        if(!EnvEnum.OTHER.equals(envEnum)){
            url = envEnum.getKeyURL();
        }
        //other环境下不配置url不会更新public_key 以配置文件为主
        if(url == null||"".equals(url)) {
            algorithm = AlgorithmFactory.getInstance(algorithmStr, PUBLIC_KEY,PRIVATE_KEY);
        }

        checkAndRefreshSecretKey();
        System.out.println("JWT url load success, url is "+url);
        System.out.println("JWT SECRET_KEY load success, key is "+ PUBLIC_KEY);
    }

    public static boolean checkAndRefreshSecretKey(){
        try {
            if(url == null || "".equals(url)) {
                return true;
            }
            String str = getSecretKey(url);
            JacksonJsonParser parser = new JacksonJsonParser();
            Map result = parser.parseMap(str);
            Map dataMap = (Map)result.get("data");
            String newPublicKey = (String)dataMap.get("publicKey");
            String algorithmName = (String)dataMap.get("algorithm");
            if(PUBLIC_KEY.equals(newPublicKey)) {
                return true;
            }
            PUBLIC_KEY = newPublicKey;
            algorithm = AlgorithmFactory.getInstance(algorithmName, PUBLIC_KEY,null);
            return false;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    public static String getSecretKey(String urlStr){
        if(urlStr == null||"".equals(urlStr)) {
            return null;
        }
        String result = "";
        BufferedReader in = null;
        try {
            URL url = new URL(urlStr);
            // 打开和URL之间的连接
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            // 设置通用的请求属性
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            // 建立实际的连接
            connection.connect();
            if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
                System.out.println("connect failed for code " + connection.getResponseCode());
                return null;
            }
            in = new BufferedReader(new InputStreamReader(
                    connection.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
            return result;
        } catch (Exception e) {
            System.out.println("JWT SECRET_KEY get failed" + e);
            e.printStackTrace();
            return null;
        } finally {
            // 使用finally块来关闭输入流
            try {
                if (in != null) {
                    in.close();
                }
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
    }

    public static Algorithm getAlgorithm(){
        return algorithm;
    }

    /**
     * 添加jwt拦截器
     * @param registry
     */
    public void addInterceptors(InterceptorRegistry registry) {
        InterceptorRegistration registration = null;
        if(!(interceptorPaths == null||"".equals(interceptorPaths))) {
            registration = registry.addInterceptor(JWTInterceptor());
            System.out.println("加载拦截器 路径为="+interceptorPaths);
            String[] interceptorPathArray=interceptorPaths.split(",");
            registration.addPathPatterns(interceptorPathArray);
        }
        if(!(excludePaths == null||"".equals(excludePaths))) {
            System.out.println("加载拦截器 排除路径="+excludePaths);
            String[] excludePathArray=excludePaths.split(",");
            registration.excludePathPatterns(excludePathArray);
        }

    }

    /**
     * jwt拦截器
     * @return
     */
    @Bean
    public JWTInterceptor JWTInterceptor() {
        return new JWTInterceptor();
    }
}

注意:在 Spring 配置中添加了多个拦截器,拦截器的执行顺序如下:

  • preHandle 方法
    preHandle 方法是按照配置的顺序依次执行的。
    如果某个 preHandle 方法返回 false,那么后续的 preHandle 不会被执行,请求也不会到达控制器。
  • postHandle 和 afterCompletion 方法
    postHandle 和 afterCompletion 方法的执行顺序与 preHandle 相反,即按照配置顺序的倒序执行。
    这是因为 postHandle 和 afterCompletion 负责处理响应,在处理完请求后再逆序执行。
  • 异常处理
    如果在拦截器链中或控制器中抛出异常,afterCompletion 方法仍然会被执行,用于进行资源清理等操作。

示例

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new Interceptor1());
        registry.addInterceptor(new Interceptor2());
        registry.addInterceptor(new Interceptor3());
    }
}
  • 执行顺序:
    preHandle: Interceptor1 -> Interceptor2 -> Interceptor3
    postHandle: Interceptor3 -> Interceptor2 -> Interceptor1
    afterCompletion: Interceptor3 -> Interceptor2 -> Interceptor1
  • 7
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JavaHandlerInterceptor拦截器是用来拦截请求并进行处理的。以下是使用HandlerInterceptor拦截器的步骤: 1. 声明一个拦截器类,实现HandlerInterceptor接口,并重写相应的拦截方法。可以参考引用的LoginInterceptor类的示例。 2. 在拦截器,根据需要重写preHandle方法,在该方法可以进行一些前置处理,如验证用户登录状态等。如果需要拦截登录之后才能访问的资源页面,可以在preHandle方法进行相应的判断和处理。 3. 在配置(一般是通过@Configuration注解标识的类),注册拦截器对象。可以参考引用的LoginInterceptorConfig类的示例。需要实现WebMvcConfigurer接口,并在addInterceptors方法进行拦截器的注册。 4. 在addInterceptors方法,创建拦截器对象,并定义一个集合来存储将不进行过滤的资源路径。使用addPathPatterns方法添加需要拦截的资源路径,使用excludePathPatterns方法添加不需要拦截的资源路径。 通过以上步骤,就可以使用HandlerInterceptor拦截器来对请求进行拦截和处理了。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [handlerInterceptor拦截器的解析及使用](https://blog.csdn.net/weixin_46038915/article/details/124142136)[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^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [java拦截器](https://download.csdn.net/download/qq_40675079/10689996)[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^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值