こんにちは、私はこのページで見つけた簡単なログインフォームページを行うことについての簡単な例に従うことを試みています_http://docs.spring.io/autorepo/docs/spring-security/4.0.x/guides/form.html
_
問題は、ログインしようとするたびにこのエラーが発生することです。_Expected CSRF token not found. Has your session expired?
_
このエラーが発生したら、エクスプローラーで[戻る]ボタンを押して、もう一度ログインしてみてください。そうすると、このエラーが表示されます:_HTTP 403 - Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'
_
チュートリアルページには、このメッセージがあります:_We use Thymeleaf to automatically add the CSRF token to our form. If we were not using Thymleaf or Spring MVCs taglib we could also manually add the CSRF token using <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
_
「したがって、thymeleafも使用しているため、そのタグをページに追加しませんでした」
私は別のソリューションを見つけ、それが機能し、このソリューションはこれをセキュリティ設定クラスに追加しています.csrf().disable()
このソリューションは機能しますが、これは私のページでcsrf保護を無効にすることであり、これを無効にしたくないと思います保護のタイプ。
これは私のsecurity-configクラスです:
_@Configuration
@EnableWebSecurity
public class ConfigSecurity extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
@Override
protected void configure( HttpSecurity http ) throws Exception {
http
//.csrf().disable() is commented because i dont want disable this kind of protection
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
}
_
私のセキュリティイニシャル:
_public class InitSecurity extends AbstractSecurityWebApplicationInitializer {
public InicializarSecurity() {
super(ConfigSecurity .class);
}
}
_
私のthymeleaf設定があるapp-configクラス
_@EnableWebMvc
@ComponentScan(basePackages = {"com.myApp.R10"})
@Configuration
public class ConfigApp extends WebMvcConfigurerAdapter{
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/css/**").addResourceLocations("/css/**");
registry.addResourceHandler("/img/**").addResourceLocations("/img/**");
registry.addResourceHandler("/js/**").addResourceLocations("/js/**");
registry.addResourceHandler("/sound/**").addResourceLocations("/sound/**");
registry.addResourceHandler("/fonts/**").addResourceLocations("/fonts/**");
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
@Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasenames("classpath:messages/messages");
messageSource.setUseCodeAsDefaultMessage(true);
messageSource.setDefaultEncoding("UTF-8");
messageSource.setCacheSeconds(0);// # -1 : never reload, 0 always reload
return messageSource;
}
// THYMELEAF
@Bean
public ServletContextTemplateResolver templateResolver() {
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
resolver.setPrefix("/WEB-INF/views/pagLogin/");
resolver.setSuffix(".html");
resolver.setTemplateMode("HTML5");
resolver.setOrder(0);
resolver.setCacheable(false);
return resolver;
}
@Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver( templateResolver() );
engine.setMessageSource( messageSource() );
return engine;
}
@Bean
public ThymeleafViewResolver thymeleafViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine( templateEngine() );
resolver.setOrder(1);
resolver.setCache( false );
return resolver;
}
@Bean
public SpringResourceTemplateResolver thymeleafSpringResource() {
SpringResourceTemplateResolver Vista = new SpringResourceTemplateResolver();
Vista.setTemplateMode("HTML5");
return Vista;
}
}
_
私のapp-config初期化子
_public class InicializarApp extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { ConfigApp .class };
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
@Override
protected Filter[] getServletFilters() {
return new Filter[] { new HiddenHttpMethodFilter() };
}
}
_
ログインコントローラークラス
_@Controller
public class ControllerLogin {
@RequestMapping(value = "/login", method = RequestMethod.GET)
public String pageLogin(Model model) {
return "login";
}
_
私のホームコントローラークラス
_@Controller
public class HomeController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Model model) {
return "home";
}
}
_
私のlogin.html
_<html xmlns:th="http://www.thymeleaf.org" xmlns:tiles="http://www.thymeleaf.org">
<head>
<title tiles:fragment="title">Messages : Create</title>
</head>
<body>
<div tiles:fragment="content">
<form name="f" th:action="@{/login}" method="post">
<fieldset>
<legend>Please Login</legend>
<div th:if="${param.error}" class="alert alert-error">
Invalid username and password.
</div>
<div th:if="${param.logout}" class="alert alert-success">
You have been logged out.
</div>
<label for="username">Username</label>
<input type="text" id="username" name="username"/>
<label for="password">Password</label>
<input type="password" id="password" name="password"/>
<div class="form-actions">
<button type="submit" class="btn">Log in</button>
</div>
<!-- THIS IS COMMENTED it dont work beacuse i am already using thymeleaf <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/> -->
</fieldset>
</form>
</div>
</body>
</html>
_
私のhome.htmlページはログインした後にのみ表示され、セキュリティ設定クラスにput .csrf()。disable()がある場合にログインできる唯一の方法ですが、私がそれを入れていない場合、その保護を無効にしたくない私のセキュリティ設定クラスでは、この質問の冒頭で言及したエラーが表示されます。
CSRF保護は、デフォルトでJava構成。CSRFを無効にする場合、対応するJava構成を参照できます。以下のJavadocを参照してください。 CSRF保護の構成方法の追加のカスタマイズについては、csrf()。
そして、CSRF保護が有効になっている場合
最後のステップは、すべてのPATCH、POST、PUT、およびDELETEメソッドにCSRFトークンを含めることを確認することです。
あなたの場合:
可能な解決策はすでに決定済みです。
http.csrf().disable()
;としてCSRF保護を無効にします。またはThymeleafを使用しているため、ログインページのHTMLテンプレートで次のような操作を行う必要があります。
<form name="f" th:action="@{/login}" method="post">
<fieldset>
<input type="hidden"
th:name="${_csrf.parameterName}"
th:value="${_csrf.token}" />
...
</fieldset>
</form>
Thymeleaf CSRFプロセッサはキックするため、HTMLaction
ではなく、th:action
を使用する必要があることに注意してください。 -前者のみ。
フォーム送信方法をGET
に変更するだけで問題を解決できますが、ユーザーがフォーム内の機密情報を送信するため、これはお勧めできません。
通常、Thymeleafフラグメントを作成します。これは、フォームを含むすべてのページで使用され、CSRFトークンを含むフォームのマークアップを生成します。これにより、アプリ全体の定型コードが削減されます。
@EnableWebMvcSecurity
の代わりに@EnableWebSecurity
を使用して、ThymeleafタグによるCSRFトークンの自動挿入を有効にします。また、Spring 3.2+およびThymeleaf 2.1+で<form th:action>
の代わりに<form action>
を使用して、ThymeleafにCSRFトークンを非表示フィールドとして自動的に含めるようにします(source Spring JIRA )。
OPが望んでいたとおりに実装するソリューションを次に示します。
@EnableWebSecurity
を @EnableWebMvcSecurity
に置き換えます(これがOPの欠落です)th:action
タグで <form>
を使用します@EnableWebMvcSecurity
を使用すると、Spring SecurityはCsrfRequestDataValueProcessor
を登録し、th:action
を使用すると、thymeleafはgetExtraHiddenFields
メソッドを使用して、追加の非表示フィールドをフォームに追加します。そして、csrfは追加の隠しフィールドです。
Spring Security 4.0以降 、@ EnableWebMvcSecurityは廃止され、@ EnableWebSecurityのみが必要です。 _ csrf保護は引き続き自動的に適用されます 。
ThymleafのSpring Securityダイアレクトを追加する必要があります。
1.)Spring Security Dialectモジュールをクラスパスに追加します。
Mavenの例:
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity3</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
2.)SpringTemplateDialectオブジェクトをSpringTemplateEngineに追加します
import org.thymeleaf.extras.springsecurity3.dialect.SpringSecurityDialect;
templateEngine.addDialect(new SpringSecurityDialect()); //add this line in your config
たぶん、その小さな情報の平和はだれでも助けになります。また、th:action
に起因するフォームを持つことも必須です。単純なHTML action
を属性付けするだけでは機能せず、ファイルされた非表示のCSRF入力は自動的に追加されません。
情報の安らぎがどこにも文書化されておらず、それについて2時間の調査に費やしたことがわかりませんでした。フォームにaction="#"
を割り当て、Java script。CSRFトークン入力フィールドは、フォームにth:action="@{#}"
を追加するまで自動的に追加されませんでした。今では魅力として機能します。
以下を追加した後にのみ私のために働いた:
protected void configure(HttpSecurity http) throws Exception {
...
http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
...
}