【Spring Security】 Session 管理

Metadata

title: 【Spring Security】 Session 管理
date: 2023-02-02 14:43
tags:
  - 行动阶段/完成
  - 主题场景/组件
  - 笔记空间/KnowladgeSpace/ProgramSpace/ModuleSpace
  - 细化主题/Module/SpringSecurity
categories:
  - SpringSecurity
keywords:
  - SpringSecurity
description: 【Spring Security】 Session 管理

【Spring Security】 Session 管理

用户认证成功后,在服务端生成用户相关的数据保存在 session(当前会话) 中,发给客户端的 sesssion_id 存放到 cookie 中,这样用户客户端请求时带上 session_id 就可以验证服务器端是否存在 session 数 据,以此完成用户的合法校验,当用户退出系统或 session 过期销毁时, 客户端的 session_id 也就无效了。基于 session 的认证方式目前不常用了,而且不适用于现在分布式微服务场景。

用户认证通过后,为了避免用户的每次操作都进行认证可将用户的信息保存在会话中。spring security 提供会话管理,认证通过后将身份信息放入 SecurityContextHolder 上下文,SecurityContext 与当前线程进行绑定,方便获取用户身份。

        SecurityContext context = SecurityContextHolder.getContext();
        Authentication authentication = context.getAuthentication();
        MyUser principal = (MyUser) authentication.getPrincipal();

可以查到到登录后,在浏览器中保存了 session_id。

session 创建策略

Spring Security 下的枚举 SessionCreationPolicy 类, 管理 session 的创建策略。

/**
 * Specifies the various session creation policies for Spring Security.
 * 指定 Spring Security 的各种会话创建策略
 */
public enum SessionCreationPolicy {
    ALWAYS,
    NEVER,
    IF_REQUIRED,
    STATELESS
}

可以通过以下选项准确控制会话何时创建以及 Spring Security 如何与之交互:

机制 描述
ALWAYS 如果没有 session 存在就创建一个
NEVER SpringSecurity 将不会创建 Session,但是如果应用中其他地方创建了 Session,那么 Spring Security 将会使用它。
IF_REQUIRED 如果需要就创建一个 Session(默认)登录时
STATELESS SpringSecurity 将绝对不会创建 Session,也不使用 Session

通过以下配置方式对该选项进行配置:

@Override
protected void configure(HttpSecurity http) throws Exception { 
    http.sessionManagement() 
    .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) 
}

默认情况下,Spring Security 会为每个登录成功的用户会新建一个 Session,就是 ifRequired 。

若选用 never,则指示 Spring Security 对登录成功的用户不创建 Session 了,但若你的应用程序在某地方新建了 session,那么 Spring Security 会用它的。

若使用 stateless,则说明 Spring Security 对登录成功的用户不会创建 Session 了,你的应用程序也不会允许新建 session。并且它会暗示不使用 cookie,所以每个请求都需要重新进行身份验证。这种无状态架构适用于 REST API 及其无状态认证机制。

配置项

SessionManagementConfigurer 是会话管理配置类,它提供了很多配置项及方法处理 session。

public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
        extends AbstractHttpConfigurer<SessionManagementConfigurer<H>, H> {

    private final SessionAuthenticationStrategy DEFAULT_SESSION_FIXATION_STRATEGY = createDefaultSessionFixationProtectionStrategy();

    private SessionAuthenticationStrategy sessionFixationAuthenticationStrategy = this.DEFAULT_SESSION_FIXATION_STRATEGY;

    private SessionAuthenticationStrategy sessionAuthenticationStrategy;

    private SessionAuthenticationStrategy providedSessionAuthenticationStrategy;

    // 设置session id无效时要应用的策略InvalidSessionStrategy。如果设置了该属性,浏览器端提供了无效的session id时,服务器端会调用该策略对象。
    // 通常情况下,这里也会是一个跳转策略对象SimpleRedirectInvalidSessionStrategy。
    private InvalidSessionStrategy invalidSessionStrategy;

    private SessionInformationExpiredStrategy expiredSessionStrategy;

    private List<SessionAuthenticationStrategy> sessionAuthenticationStrategies = new ArrayList<>();

    private SessionRegistry sessionRegistry;
    // 设置每个用户的最大并发会话数量。此方法返回一个ConcurrencyControlConfigurer,这也是一个安全配置器,设置每个用户会话数量超出单用户最大会话并发数时如何处理。
    private Integer maximumSessions;

    private String expiredUrl;

    private boolean maxSessionsPreventsLogin;
    // 设置会话创建策略SessionCreationPolicy。如果不设置,则会尝试使用公共对象中设置的SessionCreationPolicy。
    // 如果公共对象中也没有设置会话创建策略,则使用缺省的会话创建策略SessionCreationPolicy.IF_REQUIRED。
    private SessionCreationPolicy sessionPolicy;
    // 调用该方法设置属性enableSessionUrlRewriting.如果enableSessionUrlRewriting属性被设置为true,
    // 使用HttpServletResponse#encodeRedirectURL(String)/HttpServletResponse#encodeURL(String)时,
    // 允许将HTTP session信息重写到URL中。该方法对应的属性enableSessionUrlRewriting缺省为false,不允许Http session重写到URL。
    private boolean enableSessionUrlRewriting;

    // 设置session id无效时的跳转URL。如果设置了该属性,浏览器端提供了无效的session id时,服务器端会将其跳转到所设置的URL。
    private String invalidSessionUrl;
    // 定义SessionAuthenticationStrategy抛出异常时要跳转的URL。如果未设置该属性,SessionAuthenticationStrategy抛出异常时,会返回402给客户端。
    private String sessionAuthenticationErrorUrl;
    // 定义SessionAuthenticationStrategy抛出异常时要应用的认证失败处理器AuthenticationFailureHandler。
    // 如果未设置该属性,SessionAuthenticationStrategy抛出异常时,会返回402给客户端。
    private AuthenticationFailureHandler sessionAuthenticationFailureHandler;
    // -----省略大量源码
}

会话超时时间

可以再 sevlet 容器中设置 Session 的超时时间, 如下设置 Session 有效期为 3600s

server:
  servlet:
    session:
      timeout: 3600s

跳转路径

session 超时之后,可以通过 Spring Security 设置跳转的路径,expired 指 session 过期,invalidSession 指传入的 sessionid 无效。

http.sessionManagement() 
.expiredUrl("/login‐view?error=EXPIRED_SESSION") 
.invalidSessionUrl("/login‐view?error=INVALID_SESSION");

安全会话

我们可以使用 httpOnly 和 secure 标签来保护我们的会话 cookie: httpOnly:如果为 true,那么浏览器脚本将无法访问 cookie secure:如果为 true,则 cookie 将仅通过 HTTPS 连接发送 spring boot 配置文件:

server:
 servlet:
     session:
         timeout: 3600s
     cookie:
         http-only: true
         secure: true