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

How to use Spring WebSessionIdResolver with Spring Security 5 in a Spring webflux application?

目前我正在体验新的 Spring 反应式堆栈,并想在 Spring Session 2.0.

中使用反应式功能

在传统的 Servlet 方法中,Spring Session 提供了一个 HttpSessionStrategy 来检测 cookie 或请求 header 中的 session。使用 HeaderHttpSessionStrategy 可以很容易地为 RESTful API 实现类似身份验证的令牌(默认情况下,他的名称是 X-AUTH-TOKEN)。

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

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

Session配置文件。

@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 控制器文件,它 returns 当前 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 时,没有 session 信息响应 header。

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

然后我在查询结果中获取了sessionid,放入请求headers中去访问受保护的资源,得到了401。

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

更新:可以找到工作样本here

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

在任一策略中,它都适合读取传入的 ServerExchange headers,并查找 session id,无论是读取 Cookie header 还是 SESSION http header.

这些策略还会创建响应 headers,无论是 set-cookie 客户端(网络浏览器或您的代码)填充 Cookie 的指令,还是给您 SESSION header(HeaderWebSessionIdResolver 的header 名称的默认名称)。