Spring Security中如何基于access token实现Cookie免登录认证
问题根因
你遇到这个问题核心是两个默认配置没调整:
- Spring Security默认生成的
JSESSIONID是会话级Cookie,max-age属性为-1,浏览器关闭时会自动清除,存在服务端内存里的用户认证上下文(SecurityContext)会因为找不到对应会话ID直接失效 - 你虽然把Google OAuth2的access token存到了Cookie里,但没有配置对应逻辑在请求进入时读取这个有效Cookie、重建认证信息,Security框架默认不会主动识别你自定义存储的token,自然不会放行受保护资源。
可选实现方案
两种方案选一种即可,第一种改动量最小,第二种灵活度更高。
方案1:持久化会话 + 统一Cookie有效期(推荐,改动最少)
这个方案不用修改现有登录逻辑,只要把会话从临时内存改成持久化存储,同时把相关Cookie的有效期从“会话级”改成和access token对齐的固定时长即可。
- 引入Spring Session依赖,选择你方便的持久化存储(Redis/JDBC/MongoDB都支持),比如用JDBC存数据库的话引入
spring-session-jdbc依赖即可。 - 修改配置文件,开启会话持久化、设置Cookie过期时间,参考如下配置:
spring: session: # 会话持久化到指定存储,服务重启、浏览器关闭都不会丢失 store-type: jdbc # 会话超时时间和你拿到的Google access token有效期对齐,比如设置7天 timeout: 7d servlet: cookie: # 核心配置:给JSESSIONID设置固定有效期,不要用默认值-1(浏览器关闭即删除) max-age: 7d # 安全配置,生产环境必须开启 http-only: true secure: true same-site: lax
- 找到你之前OAuth2登录成功后写access token到Cookie的逻辑,把这个Cookie的
max-age也设置成和上面一致的7天,不要用默认的会话级有效期。
配置完成后,只要用户带着未过期的两个Cookie访问,服务端就能从持久化存储里找到对应的会话和已认证的SecurityContext,直接放行受保护资源,不需要重复登录。
方案2:自定义基于Access Token的认证过滤器(适合无状态架构)
如果你不想在服务端存储会话数据,可以自定义过滤器,每次请求主动从Cookie读取access token、校验通过后重建认证上下文。
- 先做好token的绑定和校验逻辑:不要只把access token明文存在Cookie里,建议给token加HMAC签名防篡改,服务端存储token和对应用户ID、授权范围的映射(存在Redis即可,设置和token一致的过期时间)。
- 自定义一个继承
OncePerRequestFilter的认证过滤器,核心逻辑:- 先判断当前SecurityContext里是否已经存在有效认证信息,存在就直接放行
- 从指定名称的Cookie中读取access token值,验签、查询服务端映射判断token是否有效、是否过期、对应用户是否存在
- 校验通过后,构建完整的
OAuth2AuthenticationToken(带上用户权限、Google客户端注册ID、用户信息),设置到SecurityContextHolder中
- 把这个过滤器注册到Spring Security过滤链中,放在
OAuth2LoginAuthenticationFilter之前执行,参考配置:
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth.anyRequest().authenticated()) .oauth2Login(Customizer.withDefaults()) // 注册自定义token认证过滤器 .addFilterBefore(accessTokenAuthFilter(), OAuth2LoginAuthenticationFilter.class) // 无状态架构下打开下面配置,不创建服务端会话 // .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) ; return http.build(); } }
注意事项
- 所有存储认证信息的Cookie必须开启
HttpOnly属性,禁止前端JS读取,生产环境HTTPS场景下必须开启Secure属性,配置合理的SameSite规则,降低XSS、CSRF风险 - Cookie和会话的有效期不要超过Google颁发的access token实际有效期,token过期后自然引导用户重新登录即可,不要设置超长有效期
- 用方案1的时候记得配置定时任务清理存储中过期的会话数据,避免无效数据占满存储空间
- 用方案2的时候必须做token签名校验和有效性校验,不能只要Cookie里有token值就直接放行,避免用户伪造身份
内容的提问来源于stack exchange,提问作者sangeun jo
相关产品推荐
相关产品推荐

