thymeleaf 中的身份验证对象为 null 或为空

Posted

技术标签:

【中文标题】thymeleaf 中的身份验证对象为 null 或为空【英文标题】:authentication object in thymeleaf is null or empty 【发布时间】:2016-04-01 03:32:07 【问题描述】:

我正在使用 Spring Boot、Spring Security 和 Thymeleaf。目前,访问页面时身份验证和授权工作正常,但我无法使百里香授权工作。流程非常简单:我尝试访问需要具有“管理员”角色的 admin.html 页面。 Spring Security 正确拦截了请求,首先将我转发到登录页面,当以管理员身份登录时,它允许我继续。

现在我想根据角色在管理页面上“隐藏”一些内容。所以在我的 admin.html 页面中,我有以下内容:

<!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>
我面临的问题是#authorization 对象为空,尽管我显然已经过身份验证和授权,否则我将无法看到管理页面。

我的 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>

我的安全配置类:

@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");

我已经尝试了很多小时来解决这个问题,但没有成功。当然,我可以避免使用 Spring boot,并且可以使用 JSP 代替 thymeleaf,但我真的很喜欢 Spring boot + Spring Security + Thymeleaf 的组合,因为它更接近于干净的 HTML。

我也尝试过使用 sec 元素,如下面的 sn-p:

  <div sec:authorize="hasRole('ROLE_ADMIN1')">
      This content is only shown to administrators.
  </div>

但是,虽然它没有给出错误,但它显示了每个角色的秘密内容,甚至是不存在的角色。

我试图通过添加 SpringSecurityDialect 来定义 SpringTemplateEngine,但我收到一个错误,说我声明了两次(这是因为 Maven 依赖于我猜想的额外库)。

非常感谢您的帮助?

【问题讨论】:

【参考方案1】:

通过更改 pom.xml 中的以下依赖项来修复:

 <!-- Thymeleaf Dialect -->
    <dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-springsecurity4</artifactId>
        <version>2.1.2.RELEASE</version>
    </dependency>

而不是 3.0.0.BETA01。现在以下工作:

<div sec:authorize="hasRole('ROLE_ADMIN')">
                    This content is only shown to administrators.
                </div>

【讨论】:

【参考方案2】:

您可能忘记使用@Controller 注释标记您的任何控制器。它发生在我的案例中,修复它有助于修复错误。这可能是故障排除步骤之一。

发生这种情况是因为当您不使用 @controller 标记控制器并尝试从模板语言(在我的情况下为 Thymeleaf)进行引用时,在运行时,它会在上下文中向下返回并返回丢失身份验证对象因此错误是这样的:

Caused by: org.attoparser.ParseException: Exception evaluating SpringEL expression: "#authorization.expression('!isAuthenticated()')" (template: "fragments/layout" - line 64, col 8)
    at org.attoparser.MarkupParser.parseDocument(MarkupParser.java:393)
    at org.attoparser.MarkupParser.parse(MarkupParser.java:257)
    at org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parse(AbstractMarkupTemplateParser.java:230)
    ... 47 more
Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "#authorization.expression('!isAuthenticated()')" (template: "fragments/layout" - line 64, col 8)
    at org.thymeleaf.spring5.expression.SPELVariableExpressionEvaluator.evaluate(SPELVariableExpressionEvaluator.java:290)
...
...
...
...
... 49 more
Caused by: java.lang.IllegalArgumentException: Authentication object cannot be null
    at org.springframework.security.access.expression.SecurityExpressionRoot.<init>(SecurityExpressionRoot.java:61)

如果有效,请告诉我!

【讨论】:

以上是关于thymeleaf 中的身份验证对象为 null 或为空的主要内容,如果未能解决你的问题,请参考以下文章

如何在单元测试期间为Thymeleaf模板传递身份验证

Thymeleaf sec:身份验证标签不显示角色

Spring boot 如何让 Thymeleaf 网页和 REST API 具有不同的身份验证方案

Grails:Spring Security Core 自定义身份验证 getUserByUserName 返回 null 对象

Thymeleaf:对象中的对象,无法像jsp那样访问值?属性或字段 - 在 null 上找不到

RFC7619 -- IKEv2中的NULL身份验证方法