未找到预期的CSRF令牌。错误403

时间:2016-01-07 23:02:04

标签: spring-mvc spring-security csrf

我有一个使用Spring Security 3.2的Spring Web应用程序。最初我是针对内存凭据对用户进行身份验证。我的安全配置文件是:

import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.rememberme.InMemoryTokenRepositoryImpl;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;

@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
      .formLogin()
        .loginPage("/login")
      .and()
        .logout()
          .logoutSuccessUrl("/")
      .and()
      .rememberMe()
        .tokenRepository(new InMemoryTokenRepositoryImpl())
        .tokenValiditySeconds(2419200)
        .key("spittrKey")
      .and()
       .httpBasic()
         .realmName("Spittr")
      .and()
      .authorizeRequests()
        .antMatchers("/admin").authenticated()
        .antMatchers("spitter/me").authenticated()
        .antMatchers(HttpMethod.POST, "/spittles").authenticated()
        .anyRequest().permitAll();
  }

  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth
    .inMemoryAuthentication()
        .withUser("admin").password("secman").roles("ADMIN").and()
        .withUser("mike").password("secman").roles("USER");
  }

}

我的部分应用程序有一个用于创建新帐户的页面:

<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:th="http://www.thymeleaf.org">
  <head>
    <title>Spitter</title>
    <link rel="stylesheet" type="text/css" 
      th:href="@{/resources/styles.css}"></link>
  </head>
  <body>
    <div id="header" th:include="page :: header"></div>

    <div id="content">
      <h1>Register</h1>

      <form method="POST" th:object="${spitter}">
        <div class="errors" th:if="${#fields.hasErrors('*')}">
             <h3 color="red">Please fix the following errors:</h3>
          <ul class="errsul">
            <li th:each="err : ${#fields.errors('*')}" 
                th:text="${err}">Input is incorrect</li>
          </ul>
        </div>

        <label th:class="${#fields.hasErrors('firstName')}? 'error'">First Name</label>:
          <input type="text" th:field="*{firstName}"  
             th:class="${#fields.hasErrors('firstName')}? 'error'" /><br/>             

        <label th:class="${#fields.hasErrors('lastName')}? 'error'">Last Name</label>:
          <input type="text" th:field="*{lastName}"
             th:class="${#fields.hasErrors('lastName')}? 'error'" /><br/>

        <label th:class="${#fields.hasErrors('email')}? 'error'">Email</label>:
          <input type="text" th:field="*{email}"
             th:class="${#fields.hasErrors('email')}? 'error'" /><br/>

        <label th:class="${#fields.hasErrors('username')}? 'error'">Username</label>:
          <input type="text" th:field="*{username}"
             th:class="${#fields.hasErrors('username')}? 'error'" /><br/>

        <label th:class="${#fields.hasErrors('password')}? 'error'">Password</label>:
          <input type="password" th:field="*{password}"  
             th:class="${#fields.hasErrors('password')}? 'error'" /><br/>

        <label>Confirm Password</label>:
          <input type="password" th:field="*{confirmPassword}" /><br/>

        <input type="submit" value="Register" />

      </form>
    </div>
    <div id="footer" th:include="page :: copy"></div>
  </body>
</html>

以角色身份登录USER或ADMIN工作正常,就像创建新帐户一样。我没有显示控制器,因为我认为它们与我的问题无关。我更改了安全配置,以便我现在对MySQL数据库中的帐户表进行身份验证。对SecutrityConfig.java的更改在configure方法中:

  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth
      .jdbcAuthentication()
          .dataSource(dataSource)
            .usersByUsernameQuery("select username, password, enabled"
                                   +" from account where username = ?")
            .authoritiesByUsernameQuery("select a.username, r.name from account a,"
                                        +" role r, account_role ar where ar.account_id = a.id" 
                                        +" and ar.role_id = r.id and a.username = ?");

  }

当然,我还将我的dataSource自动装入SecurityConfig.java中的私有属性。当我更改为基于jdbc的身份验证时,我在提交表单以注册新帐户时突然开始获取CSRF null异常。对于此问题的其他stackoverflow帖子,我必须将以下内容添加到我的注册表单中:

      <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>

这解决了这个问题。我知道使用spring标签库会自动执行上述操作,使用

<form method="POST" th:action="@{/....}"/> 

在您的表单上,但我没有使用任何一个。我的表单提交URL由GET请求中用于显示表单的URL隐含。所以我的问题是,我做的唯一改变是从内存中身份验证到基于jdbc的身份验证。我做的唯一更改是对SecurityConfig.java的上述更改。这样做,似乎CSRF过滤从非活动状态变为活动状态。这听起来不错吗?我在Spring Security文档页面上找不到任何内容来表明这一点。

0 个答案:

没有答案