salut j'essaie de suivre un exemple simple pour faire une page de formulaire de connexion simple que j'ai trouvée dans cette page http://docs.spring.io/autorepo/docs/spring-security/4.0.x/guides/form.html
le problème est que je reçois cette erreur à chaque fois que j'essaie de me connecter et que je reçois cette erreur: Expected CSRF token not found. Has your session expired?
Quand j'obtiens cette erreur, j'appuie sur le bouton retour dans mon explorateur et essaie une seconde fois de me connecter et quand je fais ça, j'obtiens cette erreur: HTTP 403 - Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'
dans la page du didacticiel se trouve le message suivant: 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}"/>
"donc parce que j'utilise aussi thymeleaf je n'ai pas ajouté cette balise à ma page"
j'ai trouvé une autre solution et cela fonctionne et cette solution ajoute ceci à ma classe de configuration de sécurité .csrf().disable()
cette solution fonctionne mais je suppose que ce que cela fait est de désactiver la protection de CSRF dans ma page et je ne veux pas désactiver ce type de protection.
voici ma classe de configuration de sécurité:
@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();
}
}
mon initialzer de sécurité:
public class InitSecurity extends AbstractSecurityWebApplicationInitializer {
public InicializarSecurity() {
super(ConfigSecurity .class);
}
}
ma classe app-config où j'ai ma configuration thymeleaf
@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;
}
}
mon initialiseur 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() };
}
}
ma classe de contrôleur de connexion
@Controller
public class ControllerLogin {
@RequestMapping(value = "/login", method = RequestMethod.GET)
public String pageLogin(Model model) {
return "login";
}
ma classe de contrôleur à la maison
@Controller
public class HomeController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Model model) {
return "home";
}
}
mon 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>
ma page home.html ne s'affiche qu'après que je me suis connecté et que je ne puisse me connecter que si un put .csrf (). disable () dans ma classe de configuration de sécurité mais je ne veux pas désactiver cette protection, si je ne le mets pas Dans ma classe de configuration de sécurité, je reçois les erreurs que je mentionne au début de cette question.
À partir de documentation Spring Security
La protection CSRF est activée par défaut avec la configuration Java. Si vous souhaite désactiver CSRF, la configuration Java correspondante peut être vu ci-dessous. Reportez-vous à la Javadoc de csrf () pour plus d'informations personnalisations dans la configuration de la protection CSRF.
Et quand la protection CSRF est activée
La dernière étape consiste à vous assurer que vous incluez le jeton CSRF à tous Méthodes PATCH, POST, PUT et DELETE.
Dans ton cas:
Vous avez déjà déterminé les solutions possibles:
http.csrf().disable()
; ouPuisque vous utilisez Thymeleaf, vous devrez procéder de la manière suivante dans votre modèle HTML pour la page de connexion:
<form name="f" th:action="@{/login}" method="post">
<fieldset>
<input type="hidden"
th:name="${_csrf.parameterName}"
th:value="${_csrf.token}" />
...
</fieldset>
</form>
Notez que vous devez utiliser th:action
et non HTML action
car le processeur CSRF de Thymeleaf n'entre en jeu qu'avec l'ancien.
Vous pouvez modifier la méthode de soumission du formulaire en GET
uniquement pour résoudre le problème, mais cela n'est pas recommandé car les utilisateurs vont soumettre des informations sensibles dans le formulaire.
Je crée généralement un fragment Thymeleaf qui est ensuite utilisé dans toutes les pages avec des formulaires pour générer le balisage des formulaires avec le jeton CSRF inclus. Cela réduit le code passe-partout dans l'application.
Utilisez @EnableWebMvcSecurity
au lieu de @EnableWebSecurity
pour activer l'injection automatique de jeton CSRF avec des balises Thymeleaf. Utilisez également <form th:action>
au lieu de <form action>
avec Spring 3.2+ et Thymeleaf 2.1+ pour forcer Thymeleaf à inclure automatiquement le jeton CSRF en tant que champ masqué (source Spring JIRA ).
Voici la solution qui l'implémente exactement comme l'OP voulait:
@EnableWebSecurity
par @EnableWebMvcSecurity
(c'est ce qui manque à OP)th:action
sur la balise <form>
Lorsque vous utilisez @EnableWebMvcSecurity
, Spring Security enregistre la CsrfRequestDataValueProcessor
et lorsque vous utilisez th:action
, thymeleaf utilise sa méthode getExtraHiddenFields
pour ajouter des champs cachés supplémentaires au formulaire. Et le CSRF est le champ caché supplémentaire.
Depuis Spring Security 4.0 , @EnableWebMvcSecurity est obsolète et seul @EnableWebSecurity est nécessaire. La protection _csrf continue de s'appliquer automatiquement .
Vous devez ajouter le dialecte de sécurité Spring de Thymleaf.
1.) Ajoutez le module Spring Security Dialect à votre chemin de classe.
Exemple Maven:
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity3</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
2.) Ajoutez l'objet SpringSecurityDialect à votre SpringTemplateEngine
import org.thymeleaf.extras.springsecurity3.dialect.SpringSecurityDialect;
templateEngine.addDialect(new SpringSecurityDialect()); //add this line in your config
Source: Spring in Action 4ème édition
Peut-être que cette petite quantité d’informations aide tout le monde: il est également obligatoire d’attribuer le formulaire avec th:action
. Il ne suffit pas d'attribuer du HTML pur action
et le fichier d'entrée CSRF masqué ne sera pas ajouté automatiquement.
Impossible de trouver cette paix d'informations documentée nulle part et de passer 2h de recherche à ce sujet. J'avais attribué le formulaire avec action="#"
et défini la valeur correspondante à l'aide d'un script Java. Le champ de saisie de jeton CSRF n'a pas été ajouté automatiquement jusqu'à ce que th:action="@{#}"
soit ajouté au formulaire. Fonctionne comme un charme maintenant.
N'a travaillé pour moi qu'après avoir ajouté ce qui suit:
protected void configure(HttpSecurity http) throws Exception {
...
http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
...
}