多次调用 Spring 安全自定义过滤器

Posted

技术标签:

【中文标题】多次调用 Spring 安全自定义过滤器【英文标题】:Spring security custom filter called multiple times 【发布时间】:2015-05-30 21:23:24 【问题描述】:

我有一个自定义注销过滤器调用了六次。我尝试访问应用程序两次,输入用户名/密码并单击“登录”两次,然后单击“注销”再次两次。

我做错了什么?

配置:

<http auto-config="true" use-expressions="true">
    <intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN_FUNCTIONS')" />      
    <intercept-url pattern="/**" access="hasRole('ROLE_USER')" />

    <form-login login-page="/login"
        authentication-success-handler-ref="customAuthenticationSuccessHandlerBean"
        authentication-failure-handler-ref="customAuthenticationFailureHandlerBean" />
    <logout invalidate-session="true" success-handler-ref="logoutHandlerBean" />
    <session-management session-fixation-protection="migrateSession">
        <concurrency-control max-sessions="1"
            expired-url="/login_sessionexpired" />
    </session-management>

    <custom-filter before="LOGOUT_FILTER" ref="customLogoutFilter" />
</http>

<beans:bean id="customLogoutFilter" class="com.hurontg.libms.security.CustomLogoutFilter" />

过滤器:

public class CustomLogoutFilter extends OncePerRequestFilter 
/**
 * 
 */
private XLogger logger = XLoggerFactory
        .getXLogger(CustomLogoutFilter.class.getName());

@Override
protected void doFilterInternal(HttpServletRequest req,
        HttpServletResponse res, FilterChain chain)
        throws ServletException, IOException 

    logger.error("========================================================================================");
    logger.error("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ Custom Logout Filter $$$$$$$$$$$$$$$$$$$$$$$$$$$$$");
    logger.error("========================================================================================");

    chain.doFilter(req, res);

春季版:4.1.1 Spring 安全性:3.2.5

【问题讨论】:

【参考方案1】:

可能会为正在请求的其他 URL 调用它。例如,如果您在页面上加载了任何 css、javascript、图像,它将为每个页面调用。尝试添加一个显示当前请求信息的日志记录语句,以确定是否是这种情况。例如,

logger.error("URL = " + req.getRequestURL());

【讨论】:

【参考方案2】:

如果您使用的是 Spring Boot,上下文中的任何GenericFilterBean(OncePerRequestFilter 为一)都会自动添加到过滤器链中。这意味着您上面的配置将包含两次相同的过滤器。

最简单的解决方法是在上下文中定义FilterRegistrationBean,并禁用它:

<beans:bean id="customLogoutFilterRegistration" class="org.springframework.boot.context.embedded.FilterRegistrationBean">
    <beans:property name="filter" ref="customLogoutFilter"/>
    <beans:property name="enabled" value="false"/>
</beans:bean>

编辑(2020 年 11 月 3 日):

对于在 SpringBoot 中工作并希望使用注释注册 bean 的任何人。在 Spring Boot 应用初始化程序文件中添加以下代码(带有@SpringBootApplication 注解):

@Bean
public FilterRegistrationBean filterRegistrationBean() 
    FilterRegistrationBean registrationBean = new FilterRegistrationBean();
    registrationBean.setFilter(new YourCustomFilterClassName());
    registrationBean.setEnabled(false);
    return registrationBean;

【讨论】:

谢谢!在此处添加了一个类似的答案(在阅读此答案和其他答案之后)-***.com/a/37904857/1882064,以防它有助于为任何人澄清这个答案。 我想知道为什么我对这些基本的东西有任何解决方法?像这样的事情,Spring 变得过于复杂和违反直觉。【参考方案3】:

只是分享我的案例:(

我没有在 AuthenticationProvider 中设置 authentication.setAuthenticated(true)

因此,AbstractPreAuthenticatedProcessingFilter 调用了一次authenticate,然后AbstractSecurityInterceptor 也调用了authenticateIfNeeded

【讨论】:

【参考方案4】:

Spring security 有大约 12 个过滤器,其中一些会尝试检查用户是否经过身份验证。例如,有一个名为 AnonymousAuthenticationFilter 的过滤器。

如果您提供身份验证提供程序并且您已经对请求进行了一次身份验证,则应在安全上下文中设置身份验证对象。

SecurityContextHolder.getContext().setAuthentication(authentication)

在示例中,AnonymousAuthenticationFilter 尝试从安全上下文中获取身份验证。如果没有找到,它会再次拨打电话。

【讨论】:

以上是关于多次调用 Spring 安全自定义过滤器的主要内容,如果未能解决你的问题,请参考以下文章

即使对于没有安全设置的端点,也总是调用 Spring Security 过滤器[重复]

java.lang.IllegalStateException(未找到方法):使用自定义过滤器在一次测试中多次调用 MockMvc.perform

Spring Security 自定义过滤器被基本 http 安全覆盖

如何使用 Spring Security 为微服务创建自定义安全过滤器

Spring 安全自定义过滤器(在 AuthenticationManager bean 已经存在时创建它的原因)

如何避免自定义过滤器在spring-security中为不安全的url运行