Spring Boot Thymeleaf variables blocking login page - spring

I'm making a webshop in Spring Boot 2.1.1, with ThymeLeaf 3.0.11
My login page does not appear in every cases, everytime it wants to load it gives a "TemplateInputException" and fails to show up.
I figured it out, if I delete thymeleaf variables from the body or div tags (I mean th:with attributes), then it works until it reaches the next html tag with TL variables, after that, the html page just stops to render. What could be the problem? There is no scenario where i dont use those variables, I need them in the container tag. What is the relation between the Spring Boot login page and template variables?
I copy some code, if you need any more, please let me know.
Any help would be appreciated!
Here is my Webconfig:
#Configuration
public class WebConfig implements WebMvcConfigurer{
#Override
public void addViewControllers(ViewControllerRegistry registry){
registry.addViewController("/login").setViewName("auth/login");
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
}
My security config's configure method:
#Override
public void configure (HttpSecurity httpSec)throws Exception {
httpSec
.authorizeRequests()
.antMatchers("/", "/reg", "/login", "/css/**","/images/**",
"/js/**", "/register", "/error",
"/records", "/search", "/record", "/altercart",
"/showcart", "/category", "/viewchange",
"/images").permitAll()
.antMatchers("/admin").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/login?logout")
.permitAll();
}
My login page(using layout dialect):
<div layout:fragment="content">
<div>
<div th:if="${param.error}" th:text="#{login.error.wrongusernameorpassword}" class="col-12 error-message"/>
<div th:if="${param.logout}" th:text="#{logoutSuccess}" class="col-12 success-message"/>
<p th:text="#{logingreetings}" class="col-12"/>
<form method="post" th:action="#{login}">
<input type="text" name="username" th:placeholder="#{login.ph.username}" required class="col-12"/>
<br />
<input type="password" name="password" th:placeholder="#{login.ph.password}" required class="col-12"/>
<br />
<input type="submit" th:value="#{loginSubmitButton}" class="col-12"/>
<br /><br />
</form>
<br />
<a class="col-12 anchor" th:href="#{register}" th:text="#{misc.registration}">Registration</a>
</div>
</div>
Beggining of stack trace:
org.thymeleaf.exceptions.TemplateInputException: An error happened during
template parsing (template: "class path resource
[templates/auth/login.html]"

Related

CSRF token not provided with spring boot 2.7.1

I was using version 2.6.x of spring boot with success.
I've switched to 2.7.1. and adapted some of my security config to match the new format.
But now the CSRF token are no longer generated for me and injected in my login form, maybe the same with other forms, but I can't test it out.
Here is my security config
#Order(1)
#Bean
public SecurityFilterChain actuatorFilterChain(final HttpSecurity http) throws Exception {
// #formatter:off
return http
.requestMatchers().antMatchers("/jobs/**", "/actuator/**").and()
.authorizeRequests().antMatchers("/jobs/**", "/actuator/**").hasRole("SYSTEM").and()
.httpBasic()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.build()
;
// #formatter:on
}
#Bean
public SecurityFilterChain filterChain(final HttpSecurity http) throws Exception {
// #formatter:off
return http
.requestMatchers().antMatchers(applicationRoutes).and()
.authorizeRequests()
.antMatchers(applicationRoutes).hasAnyRole(applicationAuthorities).and()
.csrf().disabled().and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/")
.and()
.logout()
.logoutSuccessUrl("/")
.and()
.headers()
.httpStrictTransportSecurity().disable()
.and()
.build()
;
// #formatter:on
}
}
Here is my login page
<html>
<head>
</head>
<body>
<form th:action="#{/login}"
method="POST"
>
<div class="field">
<input type="text"
id="username"
name="username"
placeholder="&#xf007 Nom d'utilisateur"
style="font-family:Lato,'Helvetica Neue', FontAwesome">
</div>
<div class="field">
<input type="password"
id="password"
name="password"
placeholder="&#xf023 Mot de passe"
style="font-family:Lato,'Helvetica Neue', FontAwesome">
</div>
<button class="ui primary button"
style="width:100%"
type="submit">Connexion</button>
</form>
</body>
</html>
The error that is shown to me is a 405 saying /login doesn't support POST.
But the form sended to the browser doesn't include CSRF token in the form.
I suspect that I miss some new bits of configuration. But I don't know where to look for.
When adding http.requestMatchers() to a filter chain, the FilterChainProxy will ignore routes that do not match. In your case, /login is not matched by a filter chain. Therefore, no CSRF token is available for your login page.
Ensure /login is available in the applicationRoutes field in your example to fix the issue. You can add a permitAll rule to your /login route with .mvcMatchers("/login").permitAll() or adding .permitAll() to the .formLogin() DSL.

Springboot login from different url

I want to implement Springboot Security for my first project and I don't know how to do the next thing:
I have the frontend and backend in different folders
on the frontend I use live-server with the url http://127.0.0.1:9000/ and the backend with the url http://localhost:8080
my login page is http://127.0.0.1:9000/login.html
Can anyone help me binding the frontend login page with the backend ?
My HTML:
<body>
<div class="login-container">
<div class="login-box">
<h1 class="login-header">LOGIN</h1>
<div class="login-input-container">
<form action="http://localhost:8080/login" method="POST">
<div class="login-input-container-email-wrapper">
<input type="text" class="login-input-email" placeholder="Email" autocorrect="off" autocomplete="off" required/>
<svg class="login-input-email-icon">
<use xlink:href="img/sprite.svg#icon-mail_outline"></use>
</svg>
</div>
<div class="login-input-container-password-wrapper">
<input type="password" class="login-input-password" placeholder="Password" required/>
<svg class="login-input-password-icon">
<use xlink:href="img/sprite.svg#icon-vpn_key"></use>
</svg>
</div>
<div class="login-submit">
<button class="login-submit-button login-submit-button--green">Submit</button>
</div>
</form>
<span class="login-separator">Or Login With</span>
<div class="login-google">
<div class="g-signin2" data-onsuccess="onSignIn" id="my-signin2"
style="display:flex;justify-content:stretch;align-items: stretch;width: 500;" data-longtitle="true"></div>
</div>
</div>
</div>
</div>
</body>
MY Springboot security config:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("http://127.0.0.1:9000/login.html").permitAll()
.defaultSuccessUrl("http://127.0.0.1:9000")
.permitAll();
}
You need to write a login controller with a rest end point where you verify credentials and you need to map that in configure() method. Not the front-end url. From front-end you should call that rest end point. Modify the configure() as below.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").permitAll()
.defaultSuccessUrl("http://127.0.0.1:9000")
.permitAll();
}
And the login controller should be like
#RestController
public class LoginController {
#CrossOrigin
#RequestMapping(value = "/login"", method = RequestMethod.POST)
#ResponseBody
public User getUserByDetails(#RequestBody Map<String, String> credentials, HttpServletResponse response)
throws IOException {
// business logic
}
}
You can refer https://www.baeldung.com/spring-security-login-angular for further details.
Do refer below config and modify your config file as required!
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login") // Specifies the login page URL (goes to controller to look for this URL)
//.loginProcessingUrl("/login") // Specifies the URL,which is used in action on the <from> tag
//.successHandler(successHandler)
.defaultSuccessUrl("http://127.0.0.1:9000")
.and()
.logout()
.logoutUrl("/logout");
// Following is to go to direct controller URL for access denied.
// exceptionHandling().accessDeniedPage("/accessDenied");
}
Here, you must understand the difference between loginPage() and loginProcessingUrl().
Now your controller should have mapping for /login
So, your controller will have method to call your custom-login-page with below config
#GetMapping("/login")
public String customLoginPage() {
return "custom-login-page";
}

Spring Security getting Acess Denied with Custom Login page

I have created one Inmemory user. Initially I tried with default formLogin. After successful login calling another api using defaultSuccessUrl till here everything fine. Now I have implemented one custom login html page when I try to login with both correct and wrong credentials getting access denied and redirecting login page again.
Anyone please help me.
Security config:
#Configuration
#EnableWebSecurity
public class SecurityConfige extends WebSecurityConfigurerAdapter {
#Autowired
private PasswordEncoder passwordEncoder;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/","index","/courses","login").permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/courses", true);
}
#Override
#Bean
public UserDetailsService userDetailsServiceBean() throws Exception {
UserDetails admin= User.builder()
.username("nithin")
.password(passwordEncoder.encode("nithin"))
.roles("ADMIN")
.authorities(new SimpleGrantedAuthority("ROLE_ADMIN"))
.build();
return new InMemoryUserDetailsManager(admin);
}
}
Html Login page:
<html lang="en">
</head>
<body>
<div class="container">
<form class="form-signin" method="post" action="/login">
<h2 class="form-signin-heading">Please login to Nithincode</h2>
<p>
<label for="username" class="sr-only">Username</label>
<input type="text" id="username" name="username" class="form-control" placeholder="Username" required=""
autofocus="">
</p>
<p>
<label for="password" class="sr-only">Password</label>
<input type="password" id="password" name="password" class="form-control" placeholder="Password"
required="">
</p>
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
<button class="btn btn-lg btn-primary btn-block" type="submit">Login</button>
</form>
</div>
</body>
</html>
Login Api:
#GetMapping("login")
public String getLoginView() {
return "login";
}
I think that you are not configuring the user details service correctly and your user is not found (for which Spring shows bad credentials). Maybe try to change your configuration a bit:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService myService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/","index","/courses","login").permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/courses", true);
}
#Bean
public UserDetailsService myService() throws Exception {
UserDetails admin= User.builder()
.username("nithin")
.password(new BCryptPasswordEncoder().encode("nithin"))
.roles("ADMIN")
.authorities(new SimpleGrantedAuthority("ROLE_ADMIN"))
.build();
return new InMemoryUserDetailsManager(admin);
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth.userDetailsService(myService).passwordEncoder(
new BCryptPasswordEncoder());
}
}

Issue in configuring spring security 4

I googled and searched on stackoverflow but I had no success
I'm trying to setup spring security in my web app. I'm using and embedded jetty and these spring versions:
spring applicationframework 4.3.5
spring security 4.2.1
tiles 3
I wrote the following security config (a very simple one)
#Configuration
#EnableWebSecurity
public class WebSecurityCfg extends WebSecurityConfigurerAdapter
{
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception
{
auth.inMemoryAuthentication().withUser("admin").password("123456").roles("ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.authorizeRequests()
.antMatchers("/adminWebTheme/**")
.permitAll()
.antMatchers("/pages/**")
.access("hasRole('ADMIN')")
.and()
.formLogin()
.loginPage("/pages/loginPage")
.permitAll()
.usernameParameter("username")
.passwordParameter("password")
.defaultSuccessUrl("/pages/adminHome")
.failureUrl("/pages/loginPage?error=true")
.and()
.logout()
.permitAll()
.logoutSuccessUrl("/pages/loginPage?logout=true")
.and()
.csrf();
}
}
This is my security initializer
public class WebSecurityInitializer extends AbstractSecurityWebApplicationInitializer
{
}
Basically I want to use my custom login form.
This is my login JSP body:
<%# taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles"%>
<%# taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%# taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%# page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<tiles:insertDefinition name="loginPageTemplate">
<tiles:putAttribute name="head">
<title><spring:message code="comm.server.login.page.title" /></title>
</tiles:putAttribute>
<tiles:putAttribute name="body">
<div class="container">
<div class="row">
<div class="col-md-4 col-md-offset-4">
<div class="login-panel panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"><spring:message code="comm.server.login.msg" /></h3>
</div>
<div class="panel-body">
<c:if test="${not empty param.error && param.error }">
<div class="alert alert-error">
<spring:message code="comm.server.login.error.msg" />
</div>
</c:if>
<c:if test="${not empty param.logout && param.logout }">
<div class="alert alert-succes">
<spring:message code="comm.server.login.logout.msg" />
</div>
</c:if>
<form role="form" method="post" action='<spring:url value="/login" />'>
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>.
<fieldset>
<div class="input-group input-sm">
<label class="input-group-addon" for="username"><i class="fa fa-user"></i></label>
<input class="form-control" placeholder='<spring:message code="comm.server.login.username.placeholder" />' name="username" id="username"
type="text" autofocus>
</div>
<div class="input-group input-sm">
<label class="input-group-addon" for="password"><i class="fa fa-lock"></i></label>
<input class="form-control" placeholder='<spring:message code="comm.server.login.password.placeholder" />'
name="password" id="password" type="password" value="">
</div>
<div class="checkbox">
<label> <input name="remember" id="remember" type="checkbox"
value='<spring:message code="comm.server.login.rememberme" />'><spring:message code="comm.server.login.rememberme" />
</label>
</div>
<!-- Change this to a button or input when using this as a form -->
<!-- Login -->
<button id="accedi" name="accedi" class="btn btn-lg btn-success btn-block"><spring:message code="comm.server.login.button" /></button>
</fieldset>
</form>
</div>
</div>
</div>
</div>
</div>
</tiles:putAttribute>
</tiles:insertDefinition>
From the previous code it seems to me all correct. I tried the access to the login page and i can access to the page successfully.
Now I have 2 kind of problem:
If i try to access to the page ..../pages/adminHome the login page is not showed
If I put username and password in my login page, the submit to the url "/login" fails because it tells me no login url is found
By the previous behaviour it's like is spring secuirty is not called at all and i can't figure the reasong
When I start my application i see the following logs:
2017-01-01 12:11:47,470 5469 [main] INFO org.apache.tiles.access.TilesAccess - Publishing TilesContext for context: org.springframework.web.servlet.view.tiles3.SpringWildcardServletTilesApplicationContext
2017-01-01 12:11:47,522 5521 [main] DEBUG o.s.s.c.a.a.c.AuthenticationConfiguration$EnableGlobalAuthenticationAutowiredConfigurer - Eagerly initializing {webSecurityCfg=it.eng.tz.comm.svr.web.config.WebSecurityCfg$$EnhancerBySpringCGLIB$$26b9578a#16a49a5d}
2017-01-01 12:11:47,679 5678 [main] DEBUG o.s.s.w.a.e.ExpressionBasedFilterInvocationSecurityMetadataSource - Adding web access control expression 'permitAll', for ExactUrl [processUrl='/pages/loginPage?error=true']
2017-01-01 12:11:47,680 5679 [main] DEBUG o.s.s.w.a.e.ExpressionBasedFilterInvocationSecurityMetadataSource - Adding web access control expression 'permitAll', for ExactUrl [processUrl='/pages/loginPage']
2017-01-01 12:11:47,681 5680 [main] DEBUG o.s.s.w.a.e.ExpressionBasedFilterInvocationSecurityMetadataSource - Adding web access control expression 'permitAll', for ExactUrl [processUrl='/pages/loginPage']
2017-01-01 12:11:47,682 5681 [main] DEBUG o.s.s.w.a.e.ExpressionBasedFilterInvocationSecurityMetadataSource - Adding web access control expression 'permitAll', for Ant [pattern='/logout', POST]
2017-01-01 12:11:47,682 5681 [main] DEBUG o.s.s.w.a.e.ExpressionBasedFilterInvocationSecurityMetadataSource - Adding web access control expression 'permitAll', for ExactUrl [processUrl='/pages/loginPage?logout=true']
2017-01-01 12:11:47,682 5681 [main] DEBUG o.s.s.w.a.e.ExpressionBasedFilterInvocationSecurityMetadataSource - Adding web access control expression 'permitAll', for Ant [pattern='/adminWebTheme/**']
2017-01-01 12:11:47,683 5682 [main] DEBUG o.s.s.w.a.e.ExpressionBasedFilterInvocationSecurityMetadataSource - Adding web access control expression 'hasRole('ADMIN')', for Ant [pattern='/pages/**']
2017-01-01 12:11:47,693 5692 [main] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Validated configuration attributes
2017-01-01 12:11:47,695 5694 [main] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Validated configuration attributes
2017-01-01 12:11:47,713 5712 [main] INFO o.s.s.w.DefaultSecurityFilterChain - Creating filter chain: org.springframework.security.web.util.matcher.AnyRequestMatcher#1, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter#3a175162, org.springframework.security.web.context.SecurityContextPersistenceFilter#18acfe88, org.springframework.security.web.header.HeaderWriterFilter#7fd8c559, org.springframework.security.web.csrf.CsrfFilter#5c534b5b, org.springframework.security.web.authentication.logout.LogoutFilter#3a543f31, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#7569ea63, org.springframework.security.web.savedrequest.RequestCacheAwareFilter#772861aa, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter#7c1e32c9, org.springframework.security.web.authentication.AnonymousAuthenticationFilter#1640190a, org.springframework.security.web.session.SessionManagementFilter#8f2098e, org.springframework.security.web.access.ExceptionTranslationFilter#53ed09e8, org.springframework.security.web.access.intercept.FilterSecurityInterceptor#4743a322]
Now it seems to me all correctly configured.... but i can't protect my web application
Can anybody help me?
Thank you
Angelo
UPDATED AS SUGGESTED
As suggested I modified my Spring security configuration by doing:
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.authorizeRequests()
.antMatchers("/adminWebTheme/**")
.permitAll()
.antMatchers("/pages/**")
.authenticated()
.antMatchers("/pages/**")
.access("hasRole('ADMIN')")
.and()
.formLogin()
.loginPage("/pages/loginPage")
.permitAll()
.usernameParameter("username")
.passwordParameter("password")
.defaultSuccessUrl("/pages/adminHome")
.failureUrl("/pages/loginPage?error")
.and()
.logout()
.permitAll()
.logoutSuccessUrl("/pages/loginPage?logout")
.and()
.csrf()
.and()
.exceptionHandling()
.accessDeniedPage("/pages/accessDenied");
}
Nothing changed. It seems to me like if Spring security filter doesn't intercept urls... and I don't know the reason. I'm sure it's a configuration issue but I can't figure where I'm wrong...
Angelo
I figured what I was missing
I'm using and embedded Jetty where I manually added the spring dispatcher servlet
So I had to add the Spring security filter too....
In my jetty I added the following (the most important thing is the secFilter section):
DispatcherServlet springSvlt = new DispatcherServlet(context);
contextHandler.addServlet(new ServletHolder(springSvlt), MAPPING_URL);
contextHandler.addEventListener(new ContextLoaderListener(context));
contextHandler.setResourceBase(new ClassPathResource("webapp").getURI().toString());
//Filtro eTag
ServletHandler sh = new ServletHandler();
FilterHolder eTagFilter = sh.addFilterWithMapping(ShallowEtagHeaderFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
contextHandler.addFilter(eTagFilter, "/*", EnumSet.of(DispatcherType.REQUEST));
//Filtro Gzip
FilterHolder gZipFilter = sh.addFilterWithMapping(ShallowEtagHeaderFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
gZipFilter.setInitParameter("varyHeader", "true");
contextHandler.addFilter(gZipFilter, "/*", EnumSet.of(DispatcherType.REQUEST));
// //Filtro sicurezza
FilterHolder secFilter = new FilterHolder( new DelegatingFilterProxy("springSecurityFilterChain") );
contextHandler.addFilter(secFilter, "/*", EnumSet.allOf(DispatcherType.class));
Now it works correctly
Thank you to all and I hope this can be useful
Angelo

how could I use csrf in spring security

My login page.
<form class="form-horizontal" ng-controller="loginCtrl" action="/login" method="post">
<div class="form-group input-login">
<div ng-if="message.error" class="alert alert-danger">
<p>Invalid username and password.</p>
</div>
<div ng-if="message.logout" class="alert alert-success">
<p>You have been logged out successfully.</p>
</div>
<label class="control-label sr-only">Email</label>
<div class="col-md-12">
<input type="text" class="form-control" ng-model="user.username" name="username" placeholder="NickName"/>
</div>
</div>
<div class="form-group input-login">
<label class="control-label sr-only">Password</label>
<div class="col-md-12">
<input type="password" class="form-control" ng-model="user.password" name="password" placeholder="Password"/>
</div>
</div>
<input name="_csrf" type="hidden" value="6829b1ae-0a14-4920-aac4-5abbd7eeb9ee" />
<div class="form-group sub-login">
<div class=" col-md-12">
<button name="submit" type="submit" class="btn btn-primary btn-login">Login</button>
</div>
</div>
</form>
But if I didn't disable the csrf,it alway be accessDenied.I don't know where is the problem.
My config code below.
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDao userDao;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(new UserService(userDao)).passwordEncoder(new MD5Util());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/index").access("hasRole('USER')")
.and()
.formLogin()
.loginPage("/login")
.failureUrl("/login#/signin?error=1")
.successHandler(new LoginSuccessHandler())
.usernameParameter("username").passwordParameter("password")
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login#/signin?logout=1")
.and()
.exceptionHandling().accessDeniedPage("/Access_Denied")
.and().csrf().disable(); // If I disable this csrf,it worked!
}
}
And does anyone knows how to ues thymeleaf in ng-route's partial page.Just see this question.
Your best bet would be to have a look at this link: https://spring.io/blog/2015/01/12/the-login-page-angular-js-and-spring-security-part-ii
Particularly, the relevant section is:
CSRF Protection
That’s good because it means that Spring Security’s built-in CSRF protection has kicked in to prevent us from shooting ourselves in the foot. All it wants is a token sent to it in a header called “X-CSRF”. The value of the CSRF token was available server side in the HttpRequest attributes from the initial request that loaded the home page. To get it to the client we could render it using a dynamic HTML page on the server, or expose it via a custom endpoint, or else we could send it as a cookie. The last choice is the best because Angular has built in support for CSRF (which it calls “XSRF”) based on cookies.
So all we need on the server is a custom filter that will send the cookie. Angular wants the cookie name to be “XSRF-TOKEN” and Spring Security provides it as a request attribute, so we just need to transfer the value from a request attribute to a cookie:
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);
}
}
After a bit more work, the last sentence is:
With those changes in place we don’t need to do anything on the client side and the login form is now working.
You should include an input hidden to send the CSRF token in the POST method when the user submit the form.
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
You already included a input hidden _csrf in your template, but the value is wrong, just change it.
You can read more about CSRF here:
https://docs.spring.io/spring-security/site/docs/current/reference/html/csrf.html

Resources