Search code examples
spring-mvcspring-securitythymeleaf

Different Thymeleaf layout decorators based on different Spring Securirty roles


I have two user roles and a layout page for each, and a single .html which has layout fragments with the main content, accessible by both users. I want to use the specific layout page depending on the user.

This is what I'm trying to do:

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
    xmlns:th="http://www.thymeleaf.org"
    xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
    xmlns:sec="http://www.thymeleaf.org/extras/spring-security"
    layout:decorate="~{(hasRole('ADMIN') ? adminLayout : customerLayout)}">

<head>...</head>
<body>
    <th:block layout:fragment="someContent">
        <h1>Same main content but replacing layout depending of the user!</h1>
        ....
    </th:block>
</body>

</html>

But I keep getting errors of failed evaluation of the page or that the hasRole method doesn't exist, depending of the syntax that I try:

org.springframework.expression.spel.SpelEvaluationException: EL1004E: Method call: Method hasRole(java.lang.String) cannot be found on type org.thymeleaf.spring5.expression.SPELContextMapWrapper

Is it possible to determine the layout decorator used based on the authenticated user role inside the .html file (not in the Controller, etc)? Or rather, is it possible to access these security methods from a scope like this?


Solution

  • You must refer to the utility bean provided by spring security for thymeleaf to be able to call spring security methods.

    Invoking spring security methods is done in the method expression which is provided by the utility bean and it's return type is boolean. So your code will be like:

    layout:decorate="~{#authorization.expression('hasRole(''ADMIN'')') ? 'adminLayout' : 'customerLayout'}"