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

Spring Boot中Shiro 1.4.0 Starter如何在Thymeleaf获取PrincipalCollection数据

在Thymeleaf中获取Shiro PrincipalCollection里的用户数据

嘿,我来帮你搞定这个问题~首先明确说:你把轻量用户数据存进Shiro PrincipalCollection的方案完全可行,而且是Shiro设计中推荐的身份信息存储方式,没必要额外自己存会话(当然备选方案也能用,但有点多此一举)。下面给你详细说怎么实现:

一、当前方案的可行性与实现步骤

你用HashMap存储用户信息并加入Principals的做法没问题,Shiro允许在PrincipalCollection中存放任意可序列化的自定义数据(你的HashMap本身是可序列化的,完全符合要求)。要在Thymeleaf里拿到这些数据,你可以借助Shiro和Thymeleaf的集成能力:

1. 确保引入Shiro-Thymeleaf依赖

如果还没加,在你的pom.xml(Maven)里添加:

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-thymeleaf</artifactId>
    <version>1.4.0</version>
</dependency>

Gradle项目对应添加依赖即可。

2. 在Thymeleaf模板中直接获取数据

Shiro的Thymeleaf集成会自动把当前Subject对象放到模板上下文里,你可以通过它直接提取PrincipalCollection中的HashMap:

<p th:text="#{welcome.lastlogin.message(${subject.principals.oneByType(T(java.util.HashMap)).firstName},${subject.principals.oneByType(T(java.util.HashMap)).lastLoginTime})}">Hello, user, how are you today?</p>

这里T(java.util.HashMap)是Thymeleaf中引用Java类的语法,oneByType方法会从PrincipalCollection里找出第一个HashMap类型的对象,也就是你存的用户数据。

优化建议:用自定义对象替代HashMap

虽然HashMap能用,但更推荐把用户数据封装成一个自定义的UserInfo类(比如包含userId、firstName、lastLoginTime等字段),这样类型更明确,避免模板里的类型转换问题,代码可读性也更高:

public class UserInfo implements Serializable {
    private Integer userId;
    private String firstName;
    private Date lastLoginTime;
    // 构造器、getter/setter方法
}

然后在UserRealm的认证方法中,把UserInfo对象加入PrincipalCollection:

@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    // 省略认证逻辑...
    UserInfo userInfo = new UserInfo(1, "John", new Date());
    return new SimpleAuthenticationInfo(userInfo, credentials, getName());
}

之后模板里的表达式就更简洁了:

<p th:text="#{welcome.lastlogin.message(${subject.principals.oneByType(com.yourpackage.UserInfo).firstName},${subject.principals.oneByType(com.yourpackage.UserInfo).lastLoginTime})}">Hello, user, how are you today?</p>

二、关于备选方案:自行存入会话

这个方案确实可行,但并不推荐——因为Shiro的PrincipalCollection本身就是用来绑定当前用户身份信息的,已经自动同步到会话中(你看到的org.apache.shiro.subject.support.DefaultSubjectContext_PRINCIPALS_SESSION_KEY就是Shiro自动存储的键)。自己存会话的话,还要额外处理序列化、会话同步、数据一致性等问题,反而增加了不必要的复杂度,不如直接用Shiro原生的机制更省心。

额外小技巧:通过Controller传递数据到模板

如果觉得模板里的表达式太长,也可以在Controller中先提取用户数据,放到Model里再传递给模板:

@GetMapping("/index")
public String index(Model model) {
    Subject subject = SecurityUtils.getSubject();
    // 这里如果是自定义UserInfo类,就换成UserInfo.class
    Map<String, Object> userData = (Map<String, Object>) subject.getPrincipals().oneByType(Map.class);
    model.addAttribute("currentUser", userData);
    return "index";
}

然后模板里直接用:

<p th:text="#{welcome.lastlogin.message(${currentUser.firstName},${currentUser.lastLoginTime})}">Hello, user, how are you today?</p>

这样模板的表达式更简洁,也更易维护。


内容的提问来源于stack exchange,提问作者Stego

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:53:54