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

Spring Boot自定义Cookie认证集成 适配HTTP认证与@PreAuthorize

适配方案实现步骤

整体思路

不改动现有控制器代码、不影响原有HTTP认证逻辑,通过Spring Security过滤器链的扩展能力接入自定义Cookie认证流程,最终复用框架原生权限匹配能力打通@PreAuthorize校验逻辑。

第一步:实现自定义Cookie认证过滤器

直接复用已有的LoginToken解密、有效性校验逻辑,编写请求级过滤器专门处理携带EncryptedLoginToken的请求:

  • 从当前请求的Cookie数组中提取EncryptedLoginToken值
  • 未检测到该Cookie时直接放行,交给原有HTTP认证流程处理,完全不干扰现有逻辑
  • 检测到Cookie时,调用现有解密逻辑生成LoginToken对象并执行有效性校验
  • 校验通过后,把Token中携带的所有权限转换为Spring Security可识别的权限对象,构造完整的认证信息存入全局安全上下文

核心实现代码示例:

public class EncryptedLoginTokenAuthFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        Cookie[] cookies = request.getCookies();
        String encryptedTokenValue = null;
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if ("EncryptedLoginToken".equals(cookie.getName())) {
                    encryptedTokenValue = cookie.getValue();
                    break;
                }
            }
        }
        // 无目标Cookie直接放行,走原有认证流程
        if (!StringUtils.hasText(encryptedTokenValue)) {
            filterChain.doFilter(request, response);
            return;
        }
        try {
            LoginToken loginToken = LoginToken.decrypt(encryptedTokenValue);
            // Token无效直接返回401
            if (!loginToken.isValid()) {
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                return;
            }
            // 将Token中的权限转换为框架识别的权限列表
            List<GrantedAuthority> authorityList = loginToken.getPermissions().stream()
                    .map(SimpleGrantedAuthority::new)
                    .collect(Collectors.toList());
            // 构造认证对象存入安全上下文
            Authentication authentication = new UsernamePasswordAuthenticationToken(
                    loginToken.getUserId(),
                    encryptedTokenValue,
                    authorityList
            );
            SecurityContextHolder.getContext().setAuthentication(authentication);
        } catch (Exception e) {
            // 解密异常直接返回401
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return;
        }
        filterChain.doFilter(request, response);
    }
}

第二步:将自定义过滤器接入Spring Security过滤链

在原有安全配置类中,把自定义过滤器注册到过滤链的靠前位置,确保它先于原有HTTP认证过滤器执行,同时不破坏原有认证逻辑:

@Configuration
@EnableWebSecurity
@EnableMethodSecurity // Spring Boot 3.x版本开启方法级权限校验的注解,旧版本替换为@EnableGlobalMethodSecurity(prePostEnabled = true)
public class CustomSecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        // 保留全部原有安全配置,包括原有HTTP认证、接口路径规则、CSRF设置等逻辑完全不做修改
        http
                // 原有配置比如http.httpBasic()、请求路径授权规则等
                .addFilterBefore(new EncryptedLoginTokenAuthFilter(), BasicAuthenticationFilter.class);
        return http.build();
    }
}

第三步:打通@PreAuthorize的权限校验链路

这一步不需要写额外代码,也不需要修改原有控制器上的@PreAuthorize注解:

  • Spring Security的权限校验逻辑是统一从SecurityContextHolder中读取当前认证用户的身份、权限列表,框架原生的hasAuthority('xxx')表达式,本质就是在当前认证对象的权限列表中匹配对应字符串
  • 我们在认证过滤器中已经把自定义Cookie解密出的权限值,全部转换为了框架可识别的SimpleGrantedAuthority对象,因此权限匹配逻辑可以无缝衔接
  • 只要解密后的Token有效、且包含hasAuthority指定的权限值,校验就会自动通过,和原本手写的userHasPermission(permission)逻辑完全等价
  • 原来业务代码中手动调用userHasPermission的逻辑可以完全移除,所有校验会由框架在方法级拦截时自动触发

注意事项

  • 两种认证方式可完全共存:未携带自定义Cookie的请求会被过滤器直接放行,走原有HTTP认证流程,没有侵入性
  • 自定义Token校验要做好异常兜底:包括解密失败、签名不匹配、Token过期的场景,要直接返回401,不要将无效认证信息存入安全上下文
  • 如果业务需要处理请求同时携带两种认证凭证的场景,可在过滤器逻辑中增加判断,定义优先级规则,比如优先使用Cookie认证、校验两种凭证的身份一致性等

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.25 13:36:07