Issue
I tried replacing the spring security login screen with my custom one. While the default one works perfectly my own one doesn't seem to react to posting the form. It just reloads the login screen.
login.mustache:
{{> partials/header}}
<body class="grey lighten-4">
<div class="container">
<form action="/login" method="POST">
<div class="md-form">
<input type="text" name="username" id="loginField" class="form-control">
<label for="loginField">Login</label>
</div>
<div class="md-form">
<input type="password" name="password" id="passwordField" class="form-control">
<label for="passwordField">Password</label>
</div>
<button class="btn red text-white float-right" type="submit">Log in</button>
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
</form>
</div>
</body>
{{> partials/footer}}
LoginController.kt
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.ui.Model
import org.springframework.ui.set
@Controller
class LoginController {
@GetMapping("/login")
fun loginPage(model: Model): String {
return "login"
}
/*
@PostMapping("/login")
fun loginForm() {
print("post")
}*/
}
It doesn't even trigger the breakpoint in the currently commented part when posting the form.
SecurityConfig.kt
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.core.userdetails.User
import org.springframework.security.provisioning.InMemoryUserDetailsManager
@Configuration
@EnableWebSecurity
class SecurityConfig : WebSecurityConfigurerAdapter() {
override fun configure(http: HttpSecurity) {
http.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/test")
.permitAll()
}
override fun configure(auth: AuthenticationManagerBuilder) {
auth.userDetailsService(
InMemoryUserDetailsManager(
User.withUsername("user").password("user").authorities(mutableListOf()).build()
)
)
}
}
I suspect I'm missing some crucial part to receiving and processing the contents of the form correctly. However after going through like 10 tutorials on this issue I've found so many inconsistencies between them that I'm honestly lost.
Solution
It seems you are using incorrect mustache syntax for the csrf parameter.
You need the {{
to render the context variable.
<input type="hidden" name="{{_csrf.parameterName}}" value="{{_csrf.token}}"/>
Additionally, you need to copy the "_csrf" object to the MVC model by adding this setting to you application.properties
.
spring.mustache.expose-request-attributes=true
Finally, you may see an IllegalArgumentException
because you haven't specified a password encoder. If that occurs, you will see the error in your stacktrace. It can be fixed by specifying a PasswordEncoder
.
Answered By - Eleftheria Stein-Kousathana