How to add csrf token to the html form?
I tried different ways and eventually I've found the solution:
Previously index.html
was located in the folder /resources/static
I put it in the folder /resources/templates
. Also I've added dependency:
compile('org.thymeleaf:thymeleaf-spring5');
and explicitly declared the controller:
@RequestMapping("/")
public String index(){
return "index";
}
index.html
look like this:
<html lang="en" ng-app="springChat" xmlns:th="http://www.springframework.org/schema/beans">
<head>
...
<meta name="_csrf" th:content="${_csrf.token}"/>
<meta name="_csrf_parameter_name" th:content="${_csrf.parameterName}"/>
....
</body>
<script type="application/javascript">
$('#login-form').submit(function (ev) {
ev.preventDefault(); // to stop the form from submitting
var token = $("meta[name='_csrf']").attr("content");
var paramName = $("meta[name='_csrf_parameter_name']").attr("content");
$('<input>').attr('type', 'hidden').attr('name', paramName).attr('value', token).appendTo('#login-form');
this.submit();
});
</script>
</html>
Looks like spring boot searches in /resources/static
raw html if we don't have explicitly declared mapping and doesn't try to insert values like th:content="${_csrf.token}"
into variables.
Related videos on Youtube
gstackoverflow
Updated on June 04, 2022Comments
-
gstackoverflow almost 2 years
After I enabled csrf(removed line
.csrf().disable()
) in my application my login request stopped working -/login
POST
redirects me to the home page:On the page I have following js:
<script type="text/javascript" src="/webjars/js-cookie/js.cookie.js"></script> ... $('#login-form').submit(function (ev) { ev.preventDefault(); // to stop the form from submitting var headerName = "X-CSRF-TOKEN"; var token = Cookies.get('XSRF-TOKEN') $('<input>').attr('type', 'hidden').attr('name', '_csrf').attr('value', Cookies.get('XSRF-TOKEN')).appendTo('#login-form'); this.submit(); // If all the validations succeeded })
Can you clarify what am doing wrong?
P.S.
I read a lot of related stuff and everywhere I found lines like this:
<meta name="_csrf" content="${_csrf.token}"/> <!-- default header name is X-CSRF-TOKEN --> <meta name="_csrf_header" content="${_csrf.headerName}"/>
I don't understand how should I set value
_csrf.headerName
I tried to add these data to meta bit its doesn't resolve:
and I tried to add it to the form directly:
And no success again.
Additionally i tried this:
But as you can see - it doesn't resolve my attributes too
P.S.2
configuration:
EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { private static final String SECURE_ADMIN_PASSWORD = "rockandroll"; @Override protected void configure(HttpSecurity http) throws Exception { http .formLogin() .loginPage("/index.html") .loginProcessingUrl("/login") .defaultSuccessUrl("/sender.html") .permitAll() .and() .logout() .logoutSuccessUrl("/index.html") .permitAll() .and() .authorizeRequests() .antMatchers("/js/**", "/lib/**", "/images/**", "/css/**", "/index.html", "/","/*.css","/webjars/**", "/*.js").permitAll() .antMatchers("/websocket").hasRole("ADMIN") .requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole("ADMIN") .anyRequest().authenticated(); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(new AuthenticationProvider() { @Override public boolean supports(Class<?> authentication) { return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication); } @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication; List<GrantedAuthority> authorities = SECURE_ADMIN_PASSWORD.equals(token.getCredentials()) ? AuthorityUtils.createAuthorityList("ROLE_ADMIN") : null; return new UsernamePasswordAuthenticationToken(token.getName(), token.getCredentials(), authorities); } }); } }
build.gradle:
buildscript { repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.1.RELEASE") } } apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'org.springframework.boot' apply plugin: 'io.spring.dependency-management' jar { baseName = 'gs-messaging-stomp-websocket' version = '0.1.0' } sourceCompatibility = 1.8 targetCompatibility = 1.8 repositories { mavenCentral() } dependencies { compile("org.springframework.boot:spring-boot-starter-websocket") compile("org.webjars:webjars-locator-core") compile("org.webjars:sockjs-client:1.0.2") compile("org.webjars:stomp-websocket:2.3.3") compile("org.webjars:bootstrap:3.3.7") compile("org.webjars:jquery:3.1.0") compile("org.webjars:js-cookie:2.1.0") compile("org.springframework.boot:spring-boot-starter-actuator") //security compile ('org.springframework.security:spring-security-messaging') compile group: 'org.springframework.security', name: 'spring-security-web' compile group: 'org.springframework.security', name: 'spring-security-config' testCompile("org.springframework.boot:spring-boot-starter-test") }
-
ikos23 about 6 yearsOk, I can see U added more info. I'd like to ask you to add more details about what error you are getting (or what behavior you expect but it does not work that way).
-
holmis83 about 6 yearsDo you use server template language JSP or Thymeleaf?
-
gstackoverflow about 6 years@holmis83 I use raw html
-
gstackoverflow about 6 years@john Result the same). /login responds 302 instead of successful login. Login happens successfuly in case of I disable csrf explicitly(.csrf().disable())
-
-
gstackoverflow about 6 yearsI use raw html so I can't use it
-
venkatReddi over 5 yearsThis solution works, but do you know why in a jsp form we can send that a form data, but when we are doing Ajax we need to add it as a header instead of form data in body? Confusing
-
Guru over 4 yearsthanks! just to get attention th: is very important prefix here.