Spring Security + Angular App REST Token Based Authentication = 403 Forbidden on POST

Posted

技术标签:

【中文标题】Spring Security + Angular App REST Token Based Authentication = 403 Forbidden on POST【英文标题】: 【发布时间】:2015-11-16 14:18:39 【问题描述】:

我有一个应用程序,它在前端有 Angular 组件,在后端有 Java。我正在使用基于令牌的身份验证来提供安全性。但是我遇到了一个问题,当我发出 POST 请求时,我得到 403-Forbidden 状态码。所有 GET 请求都可以正常工作。我检查了我在 Java 端的所有实现,看起来还不错。我从 ***.com 和其他论坛查看了其他解决方案,他们建议禁用 CSRF。即使我实现了这一点,我仍然得到 403。有人对此有任何想法吗?提前致谢,这是我的代码。

这是我的 security.xml

<security:http 
        realm="Portected API" 
        use-expressions="true" 
        auto-config="false" 
        create-session="stateless"
        entry-point-ref="unauthorzedEntiryPoint"
        authentication-manager-ref="authenticationManager">
        <security:csrf disabled="true"/>
        <security:custom-filter ref="authenticationTokenProcessingFilter" position="FORM_LOGIN_FILTER"/>
        <security:intercept-url pattern="/foo" method="POST" access="hasAnyRole('USER', 'ADMIN')"/>
        <security:intercept-url pattern="/bar" method="POST" access="hasAnyRole('USER', 'ADMIN')"/>
    </security:http>

如您所见,我在代码的第 8 行禁用了 CSRF。这是我剩下的 XML 部分。

<security:global-method-security secured-annotations="enabled"/>

<security:authentication-manager id="authenticationManager">
    <security:authentication-provider user-service-ref="userDetailService">
            </security:authentication-provider>
</security:authentication-manager>


<beans:bean id="unauthorzedEntiryPoint" class="org.sec.config.security.UnauthorizedEntryPoint"/>

<beans:bean id="authenticationTokenProcessingFilter" class="org.sec.config.security.AuthenticationTokenProcessingFilter">
    <constructor-arg ref="userDetailService"/>
</beans:bean>

<beans:bean id="userDetailService" class="org.sec.config.security.UserDetailService"/>

<beans:bean name="bcryptEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>

在我的 Angular 方面,我这样调用资源:

Restangular.all('bar').post(barModel, , 'Sec-Token': $localStorage.userToken)
      .then(function (response) 
        deferred.resolve(response);
        vm.currentBlog = response;
        //rest of the code.

【问题讨论】:

【参考方案1】:

1) 如下图添加过滤器类

public class CsrfHeaderFilter extends OncePerRequestFilter 
 @Override
protected void doFilterInternal(HttpServletRequest request,
  HttpServletResponse response, FilterChain filterChain)
  throws ServletException, IOException 
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class
    .getName());
if (csrf != null) 
  Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
  String token = csrf.getToken();
  if (cookie==null || token!=null && !token.equals(cookie.getValue())) 
    cookie = new Cookie("XSRF-TOKEN", token);
    cookie.setPath("/");
    response.addCookie(cookie);
  

filterChain.doFilter(request, response);


2) 更新安全配置类以包含上述过滤器,如下所示

  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.context.annotation.Configuration;
  import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
  import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  import org.springframework.security.web.csrf.CsrfFilter;
  import org.springframework.security.web.csrf.CsrfTokenRepository;
  import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;

  @Configuration
  @EnableWebSecurity
  public class SecurityConfig extends WebSecurityConfigurerAdapter



  protected void configure(HttpSecurity http) throws Exception 
    http
    .httpBasic().and()
    .authorizeRequests()
      .antMatchers("/login", "/login?logout" ).permitAll().anyRequest()
      .authenticated().and()
    .addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class).csrf().csrfTokenRepository(csrfTokenRepository());
 

private CsrfTokenRepository csrfTokenRepository() 
      HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
      repository.setHeaderName("X-XSRF-TOKEN");
      return repository;
    

3) 现在不需要在 Restangular post call 中包含任何额外的 header,示例代码如下所示。

$Restangular.all('/addData').customPOST(
                     amount:$scope.newExpense.amount, reason:$scope.newExpense.reason,dateStr:''+$scope.newExpense.date  ,
                    '',
                    ,
                    
                        'ContentType':'application/x-www-form-urlencoded'
                    
                ).then(function() 

来源:https://spring.io/blog/2015/01/12/the-login-page-angular-js-and-spring-security-part-ii

【讨论】:

以上是关于Spring Security + Angular App REST Token Based Authentication = 403 Forbidden on POST的主要内容,如果未能解决你的问题,请参考以下文章

Angular集成Spring Boot,Spring Security,JWT和CORS

Angular 2/Spring Security CSRF 实现问题

Angular 4.0 + Spring boot + Spring Security:TemplateInputException:解析模板“登录”时出错

如何使用 Spring Security + Angular 登录/验证

Angular 2 Spring Security CSRF 令牌

带有 Spring Boot 和 Spring Security 的 Angular2