Skip to content

Spring 拦截器(Interceptor)

🏷️ Spring Boot

1. 创建方法注解

创建一个名为 AllowAnonymousUser 的注解用以标记接口方法。

java
import java.lang.annotation.*;

/**
 * 允许匿名用户访问
 *
 * @author jiajia
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface AllowAnonymousUser {
}

2. 创建拦截器

拦截器通过获取方法的注解以判断当前接口是否允许匿名用户访问。

java
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.Objects;

/**
 * 匿名用户拦截器
 *
 * @author jiajia
 */
@Component
@RequiredArgsConstructor
@Slf4j
@Order(900)
public class AllowAnonymousUserInterceptor extends HandlerInterceptorAdapter {

    private final ObjectMapper objectMapper;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
        if (isLogin()) {
            return true;
        }

        if (!(handler instanceof HandlerMethod)) {
            return false;
        }
        Method method = ((HandlerMethod) handler).getMethod();

        // 存在该注解,即表示允许匿名用户访问
        AllowAnonymousUser annotation = method.getAnnotation(AllowAnonymousUser.class);
        boolean isAllow = !Objects.isNull(annotation);

        if (!isAllow) {
            fillResponse(response, ResponseCode.UN_LOGIN_USER_ERROR, "未登录用户不允许访问当前接口。");
        }

        return isAllow;
    }

    /**
     * 填充响应
     *
     * @param response
     * @param code
     * @param msg
     * @throws IOException
     */
    private void fillResponse(HttpServletResponse response, Integer code, String msg) throws IOException {
        // 校验失败返回前端
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter out = response.getWriter();
        PublicResponse publicResponse = new PublicResponse();
        publicResponse.setCode(code);
        publicResponse.setMsg(msg);
        out.append(objectMapper.writeValueAsString(publicResponse));
    }
}

3. 注册拦截器

通过自定义 WebMvcConfigurer 接口的实现来注册拦截器。

java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * Web MVC 配置
 *
 * @author jiajia
 */
@Configuration
public class MyWebMvcConfiguration implements WebMvcConfigurer {

    @Autowired
    private AllowAnonymousUserInterceptor allowAnonymousUserInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(allowAnonymousUserInterceptor)
                .addPathPatterns("/**");
    }
}

4. 标记接口

在接口的方法上添加 @AllowAnonymousUser 注解,即可将当前接口标记为匿名用户可访问。
同时也表示,其它未添加该注解的接口,匿名用户都是不可访问的。

java
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;

/**
 * Test Controller
 *
 * @author jiajia
 */
@ApiIgnore
@Slf4j
@Validated
@RestController
@RequestMapping("test")
@RequiredArgsConstructor
public class TestController {

    @AllowAnonymousUser
    @GetMapping("hello")
    public PublicResponse<String> sayHello() {
        return new PublicResponse().data("Hello, World.");
    }

}