You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Security的sec:authorize表达式失效问题求助

问题:Thymeleaf中sec:authorize表达式不生效,无法根据用户权限显示登录/登出按钮

我需要为匿名用户显示登录标签,为拥有ROLE_USER权限的已认证用户显示登出标签,但使用sec:authorize表达式完全没有效果,也未抛出任何错误。以下是相关配置信息:

1. pom依赖配置

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.32</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webflux</artifactId>
    </dependency>

    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.10.1</version>
    </dependency>
    <dependency>
        <groupId>io.projectreactor.netty</groupId>
        <artifactId>reactor-netty-http</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>org.thymeleaf</groupId>
        <artifactId>thymeleaf-spring5</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>

    <dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-springsecurity5</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-taglibs</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.ldap</groupId>
        <artifactId>spring-ldap-core</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-ldap</artifactId>
    </dependency>

    <dependency>
        <groupId>com.unboundid</groupId>
        <artifactId>unboundid-ldapsdk</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.hibernate.validator</groupId>
        <artifactId>hibernate-validator</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

2. 匿名用户与已认证用户的Principal信息

匿名用户:

AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=127.0.0.1, SessionId=null], Granted Authorities=[ROLE_ANONYMOUS]]

已认证用户:

UsernamePasswordAuthenticationToken [Principal=org.springframework.security.core.userdetails.User [Username=Balza, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[ROLE_USER]], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=A2C735A0D12E494E89DC72BB9BAD7119], Granted Authorities=[ROLE_USER]]

3. Thymeleaf页面命名空间及sec:authorize代码

页面命名空间:

<html xmlns:th="http://www.thymeleaf.org"
  xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5" lang="it">

按钮代码:

<li sec:authorize="hasRole('ROLE_ANONYMOUS')"><a class="dropdown-item" href="login">Login</a></li>
<li sec:authorize="hasRole('ROLE_USER')"><a class="dropdown-item" href="perform_logout">Logout</a></li>

4. Security配置类代码

@Override
protected void configure (final HttpSecurity http) throws Exception{

    http
            .authorizeRequests()
            .antMatchers("/anonymus*").anonymous() //role anonymus
            .antMatchers("/login*").permitAll()
            .antMatchers("/static/**").permitAll() //resources
            .antMatchers("/addAuthors").hasRole("USER")
            .antMatchers("/*").permitAll()
            .anyRequest().authenticated()

            .and()
            .formLogin()
            .loginPage("/login")
            .loginProcessingUrl("/perform_login")
            .failureUrl("/login?error=true")
            .permitAll()
            .defaultSuccessUrl("/", true)

            .and()
            .rememberMe()
            .key("superSecretKey")
            .tokenValiditySeconds(18000) //5 ore
            .tokenRepository(tokenRepository())

            .and()
            .logout()
            .logoutSuccessUrl("/")
            .logoutRequestMatcher(new AntPathRequestMatcher("/perform_logout", "GET"))
            .invalidateHttpSession(true)
            .deleteCookies("JSESSIONID")
            .permitAll();
}

我尝试过使用<sec:authorize access="hasAnyAuthority('ANONYMOUS')">,但出现“Unknown html tag sec:authorize thymeleaf”错误;尝试获取登录用户名也无效,仿佛无法获取访问用户的信息。目前使用临时方案:

<li><a th:if="${role == '[ROLE_ANONYMOUS]'}" class="dropdown-item" href="login">Login</a></li>
<li><a th:if="${role == '[ROLE_USER]'}" class="dropdown-item" href="perform_logout">Logout</a></li>

但不确定该方案是否正确,寻求正确的解决方法。


正确解决步骤

1. 修正sec:authorize表达式写法

  • 匿名用户判断不要用hasRole('ROLE_ANONYMOUS'),Spring Security提供了专门的isAnonymous()表达式,直接判断用户是否为匿名:
    <li sec:authorize="isAnonymous()"><a class="dropdown-item" href="login">Login</a></li>
    
  • 已认证用户的ROLE_USER判断,hasRole('USER')即可,因为hasRole会自动拼接ROLE_前缀,与用户实际权限ROLE_USER匹配:
    <li sec:authorize="hasRole('USER')"><a class="dropdown-item" href="perform_logout">Logout</a></li>
    

2. 确保Thymeleaf集成Spring Security的方言被注册

如果Spring Boot自动配置未生效,手动添加配置类注册SpringSecurityDialect,让Thymeleaf能解析sec标签:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.thymeleaf.extras.springsecurity5.dialect.SpringSecurityDialect;

@Configuration
public class ThymeleafConfig {
    @Bean
    public SpringSecurityDialect springSecurityDialect() {
        return new SpringSecurityDialect();
    }
}

3. 排查环境冲突问题

你依赖中同时包含了spring-webflux和Servlet相关依赖,确保项目是基于Spring MVC(Servlet)环境运行,WebFlux和Servlet混合可能导致Security上下文无法正确传递,影响sec标签解析。

4. 替换临时方案

你当前的临时方案依赖手动将权限放入Model,虽然能工作,但不够优雅且易出错,建议替换为上述标准的sec表达式写法。


内容的提问来源于stack exchange,提问作者Niccolò Balzarotti

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 06:42:06