1 – Crear un procesador para el tag

package com.cpe.thymeleaf.processor;

import com.cpe.custom.util.AuthUtil;
import org.springframework.security.core.Authentication;
import org.thymeleaf.context.ITemplateContext;
import org.thymeleaf.engine.AttributeName;
import org.thymeleaf.extras.springsecurity6.auth.AuthUtils;
import org.thymeleaf.model.IProcessableElementTag;
import org.thymeleaf.standard.expression.IStandardExpressionParser;
import org.thymeleaf.standard.expression.StandardExpressions;
import org.thymeleaf.standard.processor.AbstractStandardConditionalVisibilityTagProcessor;
import org.thymeleaf.templatemode.TemplateMode;
import java.util.Arrays;
import java.util.StringTokenizer;

public class HasRolActivoTagProcessor extends AbstractStandardConditionalVisibilityTagProcessor {

// ponemos como precedence 1001 porque el procesador de tag de thymeleaf tiene 1000
   public static final int ATTR_PRECEDENCE = 1001; 
   public static final String ATTR_NAME = "hasRolActivo";

   public HasRolActivoTagProcessor(final TemplateMode templateMode, final String dialectPrefix) {
       super(templateMode, dialectPrefix, ATTR_NAME, ATTR_PRECEDENCE);
   }


   @Override
   protected boolean isVisible(ITemplateContext context, IProcessableElementTag tag, AttributeName attributeName, String attributeValue) {


       final String attrValue = (attributeValue == null? null : attributeValue.replaceAll("'","").trim());


       if (attrValue == null || attrValue.length() == 0) {
           return false;
       }


       final Authentication authentication = AuthUtils.getAuthenticationObject(context);


       if (authentication == null) {
           return false;
       }


       return Arrays.stream(attrValue.split(",")).anyMatch(c-> c.equals(AuthUtil.getRolActivoUsuario().name()));


   }
}

2 – Creamos un dialecto

package com.cpe.thymeleaf.dialect;


import com.cpe.thymeleaf.processor.HasRolActivoTagProcessor;
import org.thymeleaf.dialect.AbstractProcessorDialect;
import org.thymeleaf.processor.IProcessor;
import org.thymeleaf.templatemode.TemplateMode;
import java.util.LinkedHashSet;
import java.util.Set;

public class CustomDialect extends AbstractProcessorDialect {

       public CustomDialect() {
           super(
                   "Custom Dialect",    // Dialect name
                   "custom",            // Dialect prefix (custom:*)
                   1001);              // Dialect precedence
       }


       /*
        * Initialize the dialect's processors.
        *
        * Note the dialect prefix is passed here because, although we set
        * "hello" to be the dialect's prefix at the constructor, that only
        * works as a default, and at engine configuration time the user
        * might have chosen a different prefix to be used.
        */
       public Set<IProcessor> getProcessors(final String dialectPrefix) {

           final Set<IProcessor> processors = new LinkedHashSet<>();

           final TemplateMode[] templateModes = new TemplateMode[] {TemplateMode.HTML, TemplateMode.XML,
                           TemplateMode.TEXT, TemplateMode.JAVASCRIPT, TemplateMode.CSS };

           for (final TemplateMode templateMode : templateModes) {
               processors.add(new HasRolActivoTagProcessor(templateMode, dialectPrefix));
           }

           return processors;

       }

   }

3 – En el controller añadimos un postConstruct

Añadimos el postConstruct para añadir los dialectos al Thymeleaf engine que estemos usando

@PostConstruct
public void addDialect(){
   engineThymeleaf.addDialect(new ArcaDialect());
}