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

Spring Security整合Freemarker时Session对象为空或缺失问题求助

在Freemarker中正确使用Session对象及基于用户角色控制HTML元素

用户尝试通过Session获取Spring Security上下文时遇到引用错误,代码及报错信息如下:

模板代码

<#assign
known = Session.SPRING_SECURITY_CONTEXT??
>

<#if known>
    <#assign
    user = Session.SPRING_SECURITY_CONTEXT.authentication.principal
    name = user.getUsername()
    isAdmin = user.isAdmin()
    currentUserId = user.getId()
    >
<#else>
    <#assign
    name = "unknown"
    isAdmin = false
    currentUserId = -1
    >
</#if>

错误信息

freemarker.core.InvalidReferenceException: The following has evaluated to null or missing:
==> Session [in template "parts/security.ftlh" at line 2, column 9]


一、正确使用Session对象的解决方案

出现Session引用为空的核心原因是Freemarker默认不会直接暴露HttpSession对象,需通过以下方式修正:

1. 切换为小写session变量访问

多数Spring环境中,Freemarker默认暴露小写的session变量而非大写Session,直接替换变量名即可:

<#assign
known = session.SPRING_SECURITY_CONTEXT??
>

2. 通过Spring Security内置变量简化代码

Spring Security整合Freemarker时,会自动将authentication对象暴露到模板中,无需手动从Session获取,代码可简化为:

<#if authentication??>
    <#assign
    user = authentication.principal
    name = user.username  <!-- 等价于user.getUsername(),Freemarker支持直接访问属性 -->
    isAdmin = user.admin
    currentUserId = user.id
    >
<#else>
    <#assign
    name = "unknown"
    isAdmin = false
    currentUserId = -1
    >
</#if>

3. 配置RequestContext暴露Session

若上述方法无效,可在Spring配置中开启RequestContext支持,通过requestContextAttribute访问Session:

@Bean
public FreeMarkerConfigurer freeMarkerConfigurer() {
    FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
    configurer.setTemplateLoaderPath("/WEB-INF/templates/");
    Properties props = new Properties();
    // 暴露request上下文变量,命名为rc
    props.setProperty("requestContextAttribute", "rc");
    return configurer;
}

模板中通过rc.session访问:

<#assign
known = rc.session.SPRING_SECURITY_CONTEXT??
>

二、基于用户角色隐藏HTML元素的其他方法

除手动判断角色外,还有更简洁的方案:

1. 使用Spring Security标签库

引入Spring Security标签库依赖后,可在Freemarker中直接使用角色授权指令:

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

模板中使用:

<#assign security=JspTaglibs["http://www.springframework.org/security/tags"]>

<!-- 仅ADMIN角色可见 -->
<@security.authorize access="hasRole('ADMIN')">
    <button>管理员专属操作</button>
</@security.authorize>

<!-- 仅已登录用户可见 -->
<@security.authorize access="isAuthenticated()">
    <span>欢迎,${authentication.name}</span>
</@security.authorize>

2. 自定义Freemarker角色指令

若需要更灵活的逻辑,可自定义指令封装角色判断:

public class RoleAuthorizeDirective implements TemplateDirectiveModel {
    @Override
    public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        String role = params.get("role").toString();
        // 判断用户是否拥有目标角色
        boolean hasRole = auth != null && auth.getAuthorities().stream()
                .anyMatch(a -> a.getAuthority().equals("ROLE_" + role));
        if (hasRole && body != null) {
            body.render(env.getOut());
        }
    }
}

配置到Freemarker后,模板中使用:

<@roleAuthorize role="ADMIN">
    <div>管理员专属内容</div>
</@roleAuthorize>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 15:50:38