Search code examples
springspring-bootspring-securityjwtthymeleaf

display spring security authentication object when SessionCreationPolicy.STATELESS


@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

@Autowired
MyUserDetailsService myUserDetailsService;


@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().antMatchers("/index").permitAll();
    http.authorizeRequests().antMatchers("/main").permitAll();
    http.formLogin().loginPage("/login").permitAll().successHandler(successHandler());
    http
    .csrf().disable()
    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); // Session is STATELESS
}

I set spring security sessionpolicy to STATLESS

because I'm using JWT so that STATLESS would be better but STATELESS cause one problem

it's impossible to dispaly authentication object in thymeleaf

<h1>[[${#authentication }]]</h1>

if I changed session policy I could display authentication object

but but that's not what i want

in short

can i use authentication object with thymeleaf when spring's session policy is STATELESS


Solution

  • Form based log in requires a session, so marking as stateless would mean that the user is not available. Likely you can see the page because it is marked as permitAll which means no user is necessary to see it.

    To fix this, you can switch to a form of authentication that is stateless too (i.e. it is included in every request). For example:

    // @formatter:off
    http
        .authorizeRequests()
            .mvcMatchers("/index", "/main").permitAll()
            .and()
        .httpBasic()
            .and()
        .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS); 
    // @formatter:on
    

    I'm also not sure about the syntax the themleaf template is using. For me, I use something like this:

    <!DOCTYPE html>
    
    <html xmlns:th="http://www.thymeleaf.org">
    
    <head>
        <title>Test</title>
    </head>
    
    <body>
    
    <h1 th:text="${authentication?.name}"></h1>
    
    </body>
    
    </html>
    

    Then I use the following to expose the Authentication as a model attribute:

    @Controller
    public class IndexController {
        @GetMapping("/")
        String index() {
            return "index";
        }
    
        @ModelAttribute
        Authentication authentication(Authentication authentication) {
            return authentication;
        }
    }
    

    I have a test that validates it works

    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    class DemoApplicationTests {
        @Autowired
        TestRestTemplate rest;
    
        @Test
        void indexWhenAnonymous() throws Exception{
            ResponseEntity<String> result = rest.exchange(RequestEntity.get(URI.create("/")).build(), String.class);
            assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
            assertThat(result.getBody()).doesNotContain("user");
        }
    
        @Test
        void indexWhenAuthenticated() throws Exception{
            ResponseEntity<String> result = rest.exchange(RequestEntity.get(URI.create("/")).headers(h -> h.setBasicAuth("user", "password")).build(), String.class);
            assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
            assertThat(result.getBody()).contains("user");
        }
    }
    

    You can find the complete sample at https://github.com/rwinch/spring-security-sample/tree/display-auth-stateless-thymeleaf which allows log in with the username user and password password.