Spring boot 2 在安全拦截器之前添加拦截器
Posted
技术标签:
【中文标题】Spring boot 2 在安全拦截器之前添加拦截器【英文标题】:Spring boot 2 add Interceptor before Security Interceptors 【发布时间】:2020-01-21 05:42:50 【问题描述】:如何在 spring 安全检查拦截器之前添加自定义拦截器(当安全 oauth 中止请求时我需要日志请求数据)。
【问题讨论】:
我怀疑这样做的唯一方法是使用 org.springframework.web.filter.GenericFilterBean 而不是拦截器,并以某种方式设置它的顺序在安全事物拒绝请求之前发生(如果可能的话) 【参考方案1】:万一其他人在这里绊倒......
正如我在评论中提到的,使用过滤器而不是拦截器似乎可以工作。不过,我会对此持谨慎态度,并且由于我是初学者,因此会进行更多研究...
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;
import lombok.extern.slf4j.Slf4j;
/**
* Logs an incoming request method, url and querystring and then continues the chain.
* NOTE: A HandlerInterceptor only executes AFTER spring security has allowed the request through, hence this approach.
*/
@Slf4j
@Component
public class RequestLoggingFilter extends GenericFilterBean
@Override
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain chain
) throws IOException, ServletException
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
StringBuilder requestURL = new StringBuilder(httpServletRequest.getRequestURL().toString());
String queryString = httpServletRequest.getQueryString();
String url;
if (queryString == null)
url = requestURL.toString();
else
url = requestURL.append('?').append(queryString).toString();
log.info("Incoming request: " + httpServletRequest.getMethod()+ " " + url);
chain.doFilter(request, response);
然后我就这样注册了:
@EnableWebSecurity
public class SecurityConfig
@Autowired
RequestLoggingFilter requestLoggingFilter;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception
http
.addFilterBefore(requestLoggingFilter, UsernamePasswordAuthenticationFilter.class)
// ... SNIP ...
return http.build();
我随机选择在UsernamePasswordAuthenticationFilter.class
之前添加,所以请谨慎使用。我真的不知道 spring security 如何决定它将运行哪些过滤器(例如,我的应用程序使用 JWT 进行身份验证,因此 UsernamePasswordAuthenticationFilter 似乎完全没有意义运行)。
编辑:https://docs.spring.io/spring-security/site/docs/5.3.9.RELEASE/reference/html5/#servlet-security-filters 也许在第一个(ChannelProcessingFilter)之前添加它是最好的?
【讨论】:
【参考方案2】:Spring 处理程序拦截器
在框架上使用 HandlerMapping 的拦截器必须实现 HandlerInterceptor 接口。
该接口包含三个主要方法:
prehandle()
– 在实际处理程序执行之前调用,但尚未生成视图
postHandle()
– 在处理程序执行后调用
afterCompletion()
– 在完成请求并生成视图后调用
这三种方法可以灵活地进行各种预处理和后处理。
还有一个简短的说明 - HandlerInterceptor
和 HandlerInterceptorAdapter
之间的主要区别在于,在第一个中我们需要覆盖所有三个方法:preHandle(), postHandle() and afterCompletion()
,而在第二个中我们可能只实现必需的方法。
public class LoggerInterceptor extends HandlerInterceptorAdapter
@Override
public boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,Object handler) throws Exception
log.info("[preHandle][" + request + "]" + "[" + request.getMethod()
+ "]" + request.getRequestURI() + getParameters(request));
return true;
由于您使用的是 Spring Boot,我假设您希望尽可能依赖 Spring 的自动配置。要添加额外的自定义配置,如拦截器,只需提供 WebMvcConfigurerAdapter 的配置或 bean。
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter
@Autowired
HandlerInterceptor yourInjectedInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry)
registry.addInterceptor(...)
...
registry.addInterceptor(getYourInterceptor());
registry.addInterceptor(yourInjectedInterceptor);
// next two should be avoid -- tightly coupled and not very testable
registry.addInterceptor(new YourInterceptor());
registry.addInterceptor(new HandlerInterceptor()
...
);
【讨论】:
在 Spring Boot 2.x WebMvcConfigurerAdapter 已弃用,应该只实现 WebMvcConfigurer 接口而不是扩展已弃用的 WebMvcConfigurerAdapter @Configuration public class WebMvcConfig implements WebMvcConfigurer ... 这不能回答问题。他在询问如何在弹簧安全过滤器启动并拒绝请求之前添加一个拦截器(用于记录)。我也在努力解决一个问题。以上是关于Spring boot 2 在安全拦截器之前添加拦截器的主要内容,如果未能解决你的问题,请参考以下文章
(021)Spring Boot之拦截器HandlerInterceptor