Stack: Spring Security and Thymeleaf.
I have the following problem: I want to show or not show some elements in all html templates depending on user's role.
So, I need a boolean variable "isAdmin" in all templates so that I can use it in conditions:
<p th:if="${isAdmin}">Admin functionality</p>
Please help me find the best solution. What I tried:
Option 1. I can add variable to the model in all controllers. But I think it's a bad practice.
Option 2. I can inject variable into the body with "th:with" directly from the session:
<body th:with="isAdmin=
${session
.SPRING_SECURITY_CONTEXT
.getAuthentication()
.getAuthorities()
.contains(T(com.example.model.enums.Role).ADMIN)}">
But it's too long declaration. I also didn't fin information about the scope of global variables in Thymeleaf.
Option 3. I understood I should add custom attribute in user session. And I should add it only one-time after authorization. I couldn't think of something better than overriding successForwardUrl, adding attribute in new controller and redirecting to the main page.
.formLogin()
.loginPage("/login").permitAll()
.successForwardUrl("/login/setAttributes")
@PostMapping ("login/setAttributes")
public String postLoginPage(HttpSession httpSession) {
boolean isAdmin = SecurityContextHolder
.getContext()
.getAuthentication()
.getAuthorities()
.contains(Role.ADMIN);
httpSession.setAttribute("isAdmin", isAdmin);
return "redirect:/";
}
But I still think it's not the best solution.
CodePudding user response:
Looks like you're looking for the best solution
Thymeleaf has it's special integration with Spring Security
You can check docs here
First of all you should add org.thymeleaf.extras
dependency to your project:
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
Next step. Add Thymeleaf sec
namespace to your .html
template:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
Finally, you can check user role and show specific content for different role:
<div sec:authorize="hasRole('ROLE_ADMIN')">
<p>Admin functionality</p>
</div>
Also sec:authentication
can be used to retrieve user name and roles:
<div sec:authorize="isAuthenticated()">
User: <span sec:authentication="name">User name</span>
Roles: <span sec:authentication="principal.authorities">User roles</span>
</div>