如何在 Spring webflux 应用程序中使用 Spring WebSessionIdResolver 和 Spring Security 5?

Posted

技术标签:

【中文标题】如何在 Spring webflux 应用程序中使用 Spring WebSessionIdResolver 和 Spring Security 5?【英文标题】:How to use Spring WebSessionIdResolver with Spring Security 5 in a Spring webflux application? 【发布时间】:2018-03-26 12:13:47 【问题描述】:

目前我正在体验新的 Spring 响应式堆栈,并希望在 Spring Session 2.0 中使用响应式功能。

在传统的 Servlet 方法中,Spring Session 提供了一个HttpSessionStrategy 来检测 cookie 或请求标头中的会话。使用HeaderHttpSessionStrategy 为RESTful API 实现类似身份验证的令牌(默认名称为X-AUTH-TOKEN)很容易。

Spring 5 核心提供了一个 WebSessionIdResolver 来为 Reactive 环境做同样的事情。

但是当它与 Spring Security 一起使用并希望它以传统方式工作时,我无法让它工作。

SessionConfig 文件。

@EnableSpringWebSession
public class SessionConfig 

    @Bean
    public ReactorSessionRepository sessionRepository() 
        return new MapReactorSessionRepository(new ConcurrentHashMap<>());
    

    @Bean
    public WebSessionIdResolver headerWebSessionIdResolver() 
        HeaderWebSessionIdResolver resolver = new HeaderWebSessionIdResolver();
        resolver.setHeaderName("X-SESSION-ID");
        return resolver;
    

部分SecurityConfig。

@EnableWebFluxSecurity
class SecurityConfig 

    @Bean
    SecurityWebFilterChain springWebFilterChain(HttpSecurity http) throws Exception 
        return http
            .authorizeExchange()
            .pathMatchers(HttpMethod.GET, "/posts/**").permitAll()
            .pathMatchers(HttpMethod.DELETE, "/posts/**").hasRole("ADMIN")
            //.pathMatchers("/users/user/**").access(this::currentUserMatchesPath)
            .anyExchange().authenticated()
            .and()
            .build();

一个测试rest控制器文件,它返回当前的Session ID。

@RestController
public class SessionRestController 


    @GetMapping("/sessionId")
    public Map<String, String> sessionId(WebSession session)
        Map<String, String> map = new HashMap<>();
        map.put("id", session.getId());
       return map ;
    


当我启动应用程序并使用 curl 访问 /sessionId 时,响应头中没有会话信息。

curl -v -u "user:password" http://localhost:8080/sessionId

我在查询结果中得到了会话id,放入请求头中访问受保护的资源,得到401。

curl -v -X POST -H "X-SESSION-ID:xxxx" http://localhost:8080/posts

更新:可以在here找到一个工作示例。

【问题讨论】:

【参考方案1】:

Spring Framework 的 spring-web 模块默认使用它的 CookieWebSessionIdResolver,它是基于 cookie 的。如果您创建一个 HeaderWebSessionIdResolver 类型的替代 bean,它将被 Spring Session 自动拾取并切换到基于 header 的策略。

在任一策略中,它都适合读取传入的 ServerExchange 标头,并查找会话 ID,无论是读取 Cookie 标头还是 SESSION http 标头。

这些策略还创建响应标头,无论是用于客户端(Web 浏览器或您的代码)填充 Cookie 的 set-cookie 指令,还是为您提供 SESSION 标头(HeaderWebSessionIdResolver 标头名称的默认名称)。

【讨论】:

这点我很清楚,我也看过WebSessionIdResolver的测试代码。但在我的示例中与 Spring Session 和 Spring Security 一起使用时,它不能按预期工作。我使用curl 来测试我的API,会话信息没有附加到响应头中,也没有验证我在后续步骤中从第一个请求中获得的会话。 将我的代码更新到 Spring Boot 2.0.0.M6 并使其工作,检查sample codes。

以上是关于如何在 Spring webflux 应用程序中使用 Spring WebSessionIdResolver 和 Spring Security 5?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Spring webflux 应用程序中使用 Spring WebSessionIdResolver 和 Spring Security 5?

如何使用 WebFlux 在 Spring Boot 2 中设置登录页面?

如何在 Spring Boot WebFlux 中使用 GET 请求注销

如何使用WebFlux在Spring Boot 2中设置登录页面?

如何使用 Spring Boot 对 WebFlux 进行异常处理?

如何在 spring-mvc 中将日志记录添加到 webflux 端点?