在 Broadleaf 项目中 HTTP 状态 403 - 在请求参数“_csrf”或标头“X-CSRF-TOKEN”上发现无效的 CSRF 令牌“null”

Posted

技术标签:

【中文标题】在 Broadleaf 项目中 HTTP 状态 403 - 在请求参数“_csrf”或标头“X-CSRF-TOKEN”上发现无效的 CSRF 令牌“null”【英文标题】:In Broadleaf Project HTTP Status 403 - Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN' 【发布时间】:2015-11-16 07:27:40 【问题描述】:

我尝试将 Oauth2 Security 集成到 Broadleaf Commerce 项目中以进行 api 调用,它适用于 Web 服务。但是当通过网页界面登录时,它显示上述错误..

我的产品 web.xml 依赖项

<dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>3.2.9.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>3.2.9.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>3.2.9.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-config</artifactId>
        <version>4.0.2.RELEASE</version>
    </dependency>

    <dependency>  
       <groupId>org.springframework.security.oauth</groupId>  
       <artifactId>spring-security-oauth2</artifactId>  
       <version>1.0.0.RELEASE</version>  
   </dependency>
   <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>4.2.0.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.2.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>4.2.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-web</artifactId>
        <version>3.2.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.2.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-expression</artifactId>
        <version>4.1.2.RELEASE</version>
    </dependency>

我的 applicationContext-rest-api.xml 是

<context:component-scan
    base-package="org.broadleafcommerce.core.web.api, com.test.api" />

<!-- This is default url to get a token from OAuth -->
<http pattern="/oauth/token" create-session="stateless"
    authentication-manager-ref="blAuthenticationManager"
    xmlns="http://www.springframework.org/schema/security">
    <intercept-url pattern="/oauth/token" requires-channel="any" />
    <anonymous enabled="false" />
    <http-basic entry-point-ref="clientAuthenticationEntryPoint" />
    <!-- include this only if you need to authenticate clients via request 
        parameters -->
    <custom-filter ref="clientCredentialsTokenEndpointFilter"
        after="BASIC_AUTH_FILTER" />
    <access-denied-handler ref="oauthAccessDeniedHandler" />
</http>

<!-- This is where we tells spring security what URL should be protected 
    and what roles have access to them -->
<http pattern="/api/v1/**" create-session="never"
    entry-point-ref="oauthAuthenticationEntryPoint"
    access-decision-manager-ref="accessDecisionManager"
    xmlns="http://www.springframework.org/schema/security">
    <anonymous enabled="false" />
    <intercept-url pattern="/api/v1/cart/**" requires-channel="http" />
    <custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
    <access-denied-handler ref="oauthAccessDeniedHandler" />
</http>

<bean id="oauthAuthenticationEntryPoint"
    class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
    <property name="realmName" value="test" />
</bean>

<bean id="clientAuthenticationEntryPoint"
    class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
    <property name="realmName" value="test/client" />
    <property name="typeName" value="Basic" />
</bean>

<bean id="oauthAccessDeniedHandler"
    class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />

<bean id="clientCredentialsTokenEndpointFilter"
    class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
    <property name="authenticationManager" ref="clientAuthenticationManager" />
</bean>

<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased"
    xmlns="http://www.springframework.org/schema/beans">
    <constructor-arg>
        <list>
            <bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter" />
            <bean class="org.springframework.security.access.vote.RoleVoter" />
            <bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
        </list>
    </constructor-arg>
</bean>

<authentication-manager id="clientAuthenticationManager"
    xmlns="http://www.springframework.org/schema/security">
    <authentication-provider user-service-ref="clientDetailsUserService" />
</authentication-manager>

<bean id="clientDetailsUserService"
    class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
    <constructor-arg ref="clientDetails" />
</bean>


<!-- This defined token store, we have used inmemory tokenstore for now 
    but this can be changed to a user defined one -->
<bean id="tokenStore"
    class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />

<!-- This is where we defined token based configurations, token validity 
    and other things -->
<bean id="tokenServices"
    class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
    <property name="tokenStore" ref="tokenStore" />
    <property name="supportRefreshToken" value="true" />
    <property name="accessTokenValiditySeconds" value="120" />
    <property name="clientDetailsService" ref="clientDetails" />
</bean>

<bean id="userApprovalHandler"
    class="org.springframework.security.oauth2.provider.approval.TokenServicesUserApprovalHandler">
    <property name="tokenServices" ref="tokenServices" />
</bean>


<!-- Used for REST api calls. This just takes in the passed in customerId 
    and uses it to establish the customer. -->
<!-- Additional considerations MUST be made for implementations that are 
    allowing external access to APIs. -->
<!-- <bean id="blRestCustomerStateFilter" class="org.broadleafcommerce.profile.web.core.security.RestApiCustomerStateFilter"/> -->

<oauth:authorization-server
    client-details-service-ref="clientDetails" token-services-ref="tokenServices"
    user-approval-handler-ref="userApprovalHandler">
    <oauth:authorization-code />
    <oauth:implicit />
    <oauth:refresh-token />
    <oauth:client-credentials />
    <oauth:password />
</oauth:authorization-server>

<oauth:resource-server id="resourceServerFilter"
    resource-id="test" token-services-ref="tokenServices" />

<oauth:client-details-service id="clientDetails">
    <!-- client -->

    <oauth:client client-id="restapp" authorized-grant-types="authorization_code,client_credentials" 
        authorities="ROLE_USER" scope="read,write,trust" secret="secret" />

    <oauth:client client-id="restapp"
        authorized-grant-types="password,authorization_code,refresh_token,implicit"
        secret="restapp" authorities="ROLE_USER" />   <!-- ,authorization_code,refresh_token,implicit -->

</oauth:client-details-service>

<sec:global-method-security
    pre-post-annotations="enabled" proxy-target-class="true">

    <sec:expression-handler ref="oauthExpressionHandler" />
</sec:global-method-security>

<oauth:expression-handler id="oauthExpressionHandler" />
<oauth:web-expression-handler id="oauthWebExpressionHandler" />

【问题讨论】:

【参考方案1】:

首先,您的依赖关系非常奇怪。我不确定您为什么指定自己的 spring-beans 版本等。您最终可能会遇到 Broadleaf 依赖冲突。再加上您拥有 3.2 版本的 spring-web 和 4.2 版本的 spring-beans 等事实。这些版本应该匹配。仅这些依赖项配置就会让您在未来遇到奇怪、深奥、难以调试的故障。

为了回答您的问题,Broadleaf 有一个 CsrfFilter,它要求所有 POST 请求在表单中包含一个 _csrfToken。 Thymeleaf 通过使用 &lt;blc:form&gt; html 标签而不是 &lt;form&gt; 自动完成此操作。

但是,根据您的特定错误消息,您似乎遇到了 Spring Security CSRF 过滤器,而不是 Broadleaf 过滤器。见Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'。

【讨论】:

感谢@phillipuniverse,我已经更改了我的依赖项以及 3.2 版本,然后它就像魅力一样工作......

以上是关于在 Broadleaf 项目中 HTTP 状态 403 - 在请求参数“_csrf”或标头“X-CSRF-TOKEN”上发现无效的 CSRF 令牌“null”的主要内容,如果未能解决你的问题,请参考以下文章

通过 BroadLeaf 管理站点添加了类别,但无法在站点中查看

Broadleaf Jboss设置ClassNoFound

Broadleaf电商平台上传图片出现NullPointerException

热门推荐|联想背书,Java后端开发工程师,日薪1802元

项目总结项目开发规范

项目总结项目开发规范