Issue
I'm using Spring boot, Spring Security and Thymeleaf. Currently, authentication and authorisation work fine when accessing pages, but I can't make the thymeleaf authorization work. The flow is very simple: I try accessing the admin.html page for which I need to have a role of 'ADMIN'. Spring Security correctly intercepts the request, forwards me to the login page first and when logged is as admin, it allows me to proceed.
Now I'd like to "hide" some content on the admin page based on roles. So in my admin.html page I've got the following:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head th:include="header :: common-header">
<title>Admin Page</title>
</head>
<body>
<div th:replace="navbar :: common-navbar"></div>
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<div class="well">
<div th:if="${#authorization.expression('hasRole(''ROLE_ADMIN'')')}">
Secret Content
</div>
<div class="starter-template">
<h1>Hello Administrator!</h1>
<p class="lead">This page allows you to perform administrative tasks</p>
<form id="f" th:action="@{/logout}" method="post" role="form" class="form-group">
<input type="submit" value="Logout" class="btn btn-primary" />
</form>
</div>
</div>
</div>
</div>
</div><!-- /.container -->
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<div th:include="header :: before-body-script">
</div>
</body>
</html>
My pom.xml:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Thymeleaf Dialect -->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
<version>3.0.0.BETA01</version>
</dependency>
My security configuration class:
@Override
protected void configure(HttpSecurity http) throws Exception {
// Allows for static content
http.authorizeRequests().antMatchers("/webjars/**").permitAll();
http.authorizeRequests().antMatchers("/css/**").permitAll();
http.authorizeRequests().antMatchers("/js/**").permitAll();
// Defines security for everything else
http
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/admin").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login").failureUrl("/login?error").permitAll()
.and()
.logout()
.permitAll();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
.and()
.withUser("admin").password("admin").roles("USER", "ADMIN");
}
I've tried for many hours to solve this problem but without success. Of course, I could avoid using Spring boot and could use JSPs instead of thymeleaf but I really like the combination of Spring boot + Spring Security + Thymeleaf as it's closer to clean HTML.
I've also tried using the sec element as in the following snippet:
<div sec:authorize="hasRole('ROLE_ADMIN1')">
This content is only shown to administrators.
</div>
But, although it doesn't give an error, it shows the secret content for every role, even non existing ones.
I've tried to define a SpringTemplateEngine by adding the SpringSecurityDialect, but I got an error saying I was declaring it twice (this is because of the Maven dependency on the extras library I suppose).
I'd really appreciate some help please?
Solution
Fixed by changing the following dependency in pom.xml:
<!-- Thymeleaf Dialect -->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
Instead of 3.0.0.BETA01. Now the following works:
<div sec:authorize="hasRole('ROLE_ADMIN')">
This content is only shown to administrators.
</div>
Answered By - Marco Tedone
Answer Checked By - Gilberto Lyons (JavaFixing Admin)