如何通过 XML 配置仅针对特定 URL 模式在 Spring Security 4 中禁用 CSRF?

Posted

技术标签:

【中文标题】如何通过 XML 配置仅针对特定 URL 模式在 Spring Security 4 中禁用 CSRF?【英文标题】:How to disable CSRF in Spring Security 4 only for specific URL pattern through XML configuration? 【发布时间】:2015-11-04 19:15:39 【问题描述】:

如何在 Spring Security 4 中通过 XML 配置仅针对特定 URL 模式禁用 CSRF?

Spring-security.xml

<security:http auto-config="true" use-expressions="true" pattern="/ext/**">
    <csrf disabled="true" />
</security:http>

<security:http auto-config="true" use-expressions="true" authentication-manager-ref="authenticationManager">
    <security:intercept-url pattern="/auth/**" access="hasAnyRole('ROLE_USER')" />
    <security:form-login login-page="/login" authentication-success-handler-ref="loginSuccessHandler" authentication-failure-url="/login" login-processing-url="/j_spring_security_check" />
    <security:logout invalidate-session="true" logout-url="/logout" success-handler-ref="logoutSuccessHandler" />
</security:http>

如果我只使用一个 security:http 块,我的代码可以正常工作,但是在我添加另一个块后,它会抛出如下错误:

错误

Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter gov.in.controller.filter.LoginAdtAuthFailHdlr.usernamePasswordAuthenticationFilter; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter] is defined: expected single matching bean but found 2: org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#0,org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#1
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:561)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
    ... 58 more
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter] is defined: expected single matching bean but found 2: org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#0,org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#1
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1054)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:942)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:533)
    ... 60 more

【问题讨论】:

【参考方案1】:

仅通过 XML 更改无法实现。下面对我有用

Spring-security.xml

中的更改
<security:http  use-expressions="true" authentication-manager-ref="authenticationManager">
    <security:intercept-url pattern="/auth/**" access="hasAnyRole('ROLE_USER')" />
    <security:form-login login-page="/login" authentication-success-handler-ref="loginSuccessHandler" authentication-failure-url="/login" login-processing-url="/j_spring_security_check" />
    <security:logout invalidate-session="true" logout-url="/logout" success-handler-ref="logoutSuccessHandler" />

    <security:csrf request-matcher-ref="csrfSecurityRequestMatcher"  />
</security:http>

CsrfSecurityRequestMatcher

public class CsrfSecurityRequestMatcher implements RequestMatcher 
    private Pattern allowedMethods = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$");
    private RegexRequestMatcher unprotectedMatcher = new RegexRequestMatcher("/ext/**", null);

    @Override
    public boolean matches(HttpServletRequest request)           
        if(allowedMethods.matcher(request.getMethod()).matches())
            return false;
        
        return !unprotectedMatcher.matches(request);
    

【讨论】:

像魅力一样工作。感谢分享。我必须把@Component 放在类定义之前,这样spring 才能对匹配器进行组件扫描。 嘿,对不起,我是 java 新手,你能告诉我我需要创建 CsrfSecurityRequestMatcher 类的位置吗 您需要在安全 xml 中创建一个 id 为 csrfSecurityRequestMatcher 的 bean,并对您的文件路径进行分类【参考方案2】:

您可以有两个(或更多)过滤器链:

<http pattern="/your-specific/**">
  <!-- ... -->
  <csrf disabled="true"/>
</http>
<http>
  <!-- ... -->
</http>

【讨论】:

感谢您的回复。我在上面添加了一些 xml 和错误。当我添加第二个 http 块时,它会引发重复的 bean 错误。有什么建议吗? @ad-inf 您在LoginAdtAuthFailHdlr 中有对 UsernamePasswordAuthenticationFilter 的引用。使用两个form-login,您将获得两个UsernamePasswordAuthenticationFilter,您需要更改您的课程或删除一个表单登录。 也试过了。删除了所有元素,但错误仍然相同。更新了 xml @ad-inf auto-config="true"form-login 等的简写(参见参考文档),我建议不要使用它。 ' '与其他

以上是关于如何通过 XML 配置仅针对特定 URL 模式在 Spring Security 4 中禁用 CSRF?的主要内容,如果未能解决你的问题,请参考以下文章

如何仅针对特定 url 添加 Spring Security 验证码过滤器

如何仅针对特定规则扫描java文件?

仅针对 nginx 上的特定 url 使用 https 重定向

仅针对特定用户的 SSH 身份验证绕过密码身份验证

Oauth2Login 仅用于特定的 url

Spring security:在 3.1 中,仅针对“GET”请求绕过安全过滤器