Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thymeleaf authorization with Spring Security doesn't work [duplicate]

I'm using Spring Security in my Spring Boot app and it seems that Thymeleaf authorization doesn't work properly.

I have the Thymeleaf template with the following code:

<div class="container">
    <div class="row" sec:authorize="isAuthenticated()">
        <h2 style="color:green">User is Logged In</h2>
        <p sec:authentication="principal.username">username</p>
    </div>

    <div class="row" sec:authorize="!isAuthenticated()">
        <h2 style="color:red">User is Logged Out</h2>
    </div>

    <div class="row" sec:authorize="hasRole('ROLE_SUPERUSER')">
        <h2>This will only be displayed if authenticated user has role ROLE_SUPERUSER.</h2>
    </div>

    <div class="row" sec:authorize="hasRole('ROLE_ADMIN')">
        <h2>This will only be displayed if authenticated user has role ROLE_ADMIN.</h2>
    </div>

    <div class="row" sec:authorize="hasRole('ROLE_USER')">
        <h2>This will only be displayed if authenticated user has role ROLE_USER.</h2>
    </div>

    <div th:if="${#authorization.expression('hasRole(''ROLE_ADMIN'')')}">
        This will only be displayed if authenticated user has role ROLE_ADMIN.
    </div>

    <div th:if="${#authorization.expr('hasRole(''ROLE_ADMIN'')')}">
        This will only be displayed if authenticated user has role ROLE_ADMIN.
    </div>
</div>

Examples are taken from: https://github.com/thymeleaf/thymeleaf-extras-springsecurity

However the only content that is shown is sec:authorize="isAuthenticated()" and sec:authorize="!isAuthenticated()" and the authorization is always ignored, regardless of the user's role.

My thymeleaf configuration is:

@Configuration
public class ThymeleafConfig {

    @Bean
    public TemplateResolver defaultTemplateResolver() {
        TemplateResolver resolver = new TemplateResolver();
        resolver.setResourceResolver(thymeleafResourceResolver());
        resolver.setPrefix("classpath:/templates/");
        resolver.setSuffix(".html");
        resolver.setTemplateMode("HTML5");
        resolver.setCharacterEncoding("UTF-8");
        resolver.setCacheable(true);
        return resolver;
    }

    @Bean
    public SpringResourceResourceResolver thymeleafResourceResolver() {
        return new SpringResourceResourceResolver();
    }

    @Bean
    public SpringTemplateEngine templateEngine(TemplateResolver templateResolver) {
        SpringTemplateEngine engine = new SpringTemplateEngine();
        engine.setTemplateResolver(templateResolver);
        engine.addDialect(new SpringSecurityDialect());
        engine.addDialect(new LayoutDialect());
        return engine;
    }

    @Bean
    public ThymeleafViewResolver thymeleafViewResolver(SpringTemplateEngine templateEngine) {
        ThymeleafViewResolver resolver = new ThymeleafViewResolver();
        resolver.setTemplateEngine(templateEngine);
        resolver.setCharacterEncoding("UTF-8");
        resolver.setContentType("text/html");
        resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 5);
        return resolver;
    }

}

And I use the following dependency for thymeleaf-extras-springsecurity4:

<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-springsecurity4</artifactId>
    <version>2.1.3.RELEASE</version>
</dependency>

Version 3.0.2.RELEASE didn't work at all, and sec namespace was always ignored by Thymeleaf.
My Spring Boot version is 1.5.2.RELEASE.

What could be the reason?

UPDATE. The configure(HttpSecurity http) method in SecurityConfig looks as:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().ignoringAntMatchers("/h2-console").disable()
            .authorizeRequests()
                .antMatchers("/webjars/**", "/static/**", "/images/**", "/**/favicon.ico").permitAll()
                .antMatchers("/heat/**", "/power/**", "/water/**").permitAll()

            // start allowing h2-console
                .antMatchers("/h2-console/**").permitAll();
            http.csrf().disable();
            http.headers().frameOptions().disable()
            // end allowing h2-console

            .and().authorizeRequests().antMatchers("/info").permitAll()
            .and().authorizeRequests().antMatchers("/users/**").authenticated()
            .and().authorizeRequests().antMatchers("/users/**").hasAnyAuthority("ADMIN", "SUPERUSER")

            .and().formLogin()
                    .loginPage("/login")
                    .permitAll()
            .and()
                    .logout()
                    .permitAll()
                    .deleteCookies("remove")
                    .logoutUrl("/logout")
                    .logoutSuccessUrl("/")
                    .invalidateHttpSession(true)

            .and().exceptionHandling().accessDeniedPage("/access_denied");
}

and the mapping from the IndexController is pretty simple, it just returns the login template:

@RequestMapping("/login")
public String loginForm() {
    return "login";
}
like image 855
DimaSan Avatar asked Apr 23 '17 22:04

DimaSan


1 Answers

An alternative way of solving the task is to use this syntax to check role:

<div class="row" th:if="${#request.isUserInRole('SUPERUSER')}">
    <h2>This will only be displayed if authenticated user has role ROLE_SUPERUSER.</h2>
</div>

It does not use the sec namespace and actually the thymeleaf-extras-springsecurity4 dependency is not needed at all to use this.

like image 172
holmis83 Avatar answered Oct 20 '22 21:10

holmis83