【问题标题】:where to put username and password of WebClient of Spring Webflux?Spring Webflux的WebClient的用户名和密码放在哪里?
【发布时间】:2019-11-15 20:10:14
【问题描述】:

我尝试使用路由器和处理程序类制作 spring webflux 安全应用程序。首先,下面的代码是webflux安全的配置代码。

@Configuration
@EnableWebFluxSecurity
public class BlogWebFluxSecurityConfig {

    @Bean
    public MapReactiveUserDetailsService userDetailsService() {

        UserDetails userWebFlux = User.withUsername("joseph").password("password").roles("USER").build();
        return new MapReactiveUserDetailsService(userWebFlux);
    }

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http
        .authorizeExchange()
        .pathMatchers("/route/user/all", "/route/post/all").permitAll()
        .pathMatchers(HttpMethod.GET, "/route/user/**", "/route/post/**").hasRole("USER")
        .anyExchange().authenticated()
        .and()
        .httpBasic();

        return http.build();
    } 
}

接下来的代码是关于路由器类的。

@Configuration
@EnableWebFlux
public class BlogWebFluxEndpointRouter {

    @Bean
    public RouterFunction<ServerResponse> routesUser(UserHandler handler) {

        return RouterFunctions.route(RequestPredicates.GET("/route/user/all"), handler::findAll)
                    .andRoute(RequestPredicates.GET("/route/user/id/{id}"), handler::findById)
                    .andRoute(RequestPredicates.GET("/route/user/username/{username}"), handler::findByUsername)
                    .andRoute(RequestPredicates.GET("/route/user/email/{email}"), handler::findByEmail)
                    .andRoute(RequestPredicates.POST("/route/user/create"), handler::register)
                    .andRoute(RequestPredicates.GET("/route/user/login/{username}/{password}"), handler::authenticate);
    }

    @Bean
    public RouterFunction<ServerResponse> routesPost(PostHandler handler) {

        return RouterFunctions.route(RequestPredicates.GET("/route/post/all"), handler::findAll)
                    .andRoute(RequestPredicates.GET("/route/post/id/{id}"), handler::findById)
                    .andRoute(RequestPredicates.GET("/route/post/delete/{id}"), handler::deleteById)
                    .andRoute(RequestPredicates.POST("/route/post/create"), handler::create)
                    .andRoute(RequestPredicates.PUT("/route/post/{id}/{content}"), handler::edit);
    }
}

即使网络是rest web service,但我使用WebFlux的WebClient类。

public void functionOnUserDocument() { 
        client.get().uri("/route/user/all").accept(MediaType.APPLICATION_JSON).exchange()
                .flatMapMany(response -> response.bodyToFlux(User.class))
                .subscribe(u -> System.out.println("All Users : " + u.getUsername() + ":" + u.getEmail() + ":" + u.getFullname()));

        client.get().uri("/route/user/id/{id}", "0002").accept(MediaType.APPLICATION_JSON).exchange()
                .flatMap(response -> response.bodyToMono(User.class))
                .subscribe(u -> System.out.println("GET by Id : " + u.getUsername() + ":" + u.getEmail() + ":" + u.getFullname()));

        client.get().uri("/route/user/username/{username}", "jina").accept(MediaType.APPLICATION_JSON).exchange()
                .flatMap(response -> response.bodyToMono(User.class))
                .subscribe(u -> System.out.println("Get by username : " + u.getUsername() + ":" + u.getEmail() + ":" + u.getFullname()));

        client.get().uri("/route/user/email/{email}", "myson@college.ac.kr").accept(MediaType.APPLICATION_JSON).exchange()
                .flatMap(response -> response.bodyToMono(User.class))
                .subscribe(u -> System.out.println("Get By Email : " + u.getUsername() + ":" + u.getEmail() + ":" + u.getFullname()));

        client.get().uri("/route/user/login/{username}/{password}", "julian", "password").exchange()
                .map(ClientResponse::statusCode).subscribe(response -> System.out.println("Login : " + response.getReasonPhrase()));

        User user = new User("0005", 4L, "jane", "password", "aaa@bbb.com", "누나", "USER");

        client.post().uri("/route/user/create").body(Mono.just(user), User.class).exchange() 
                .map(ClientResponse::statusCode).subscribe(response -> System.out.println("User Creation: " + response.getReasonPhrase()));
    }

因为我做了webflux的安全配置,肯定有些webclient不能执行和禁止如下,

Login : Unauthorized
User Creation: Forbidden

我不使用 curl。所以我想知道我的 WebClient 方法是什么,用户名和密码必须在哪里找到并转移到 WebClient 类。任何回复将不胜感激。

【问题讨论】:

  • 您的代码中有几个不好的地方,您从不订阅 webflux 应用程序,因此所有 subscribe 都需要删除。我不知道你的问题是什么。当人们调用你的服务时,或者你的服务调用另一个服务时?
  • 感谢您的回复。你的意思是我的来源的哪一部分有坏事?路由器还是WebClient?请告诉我参考网站以及我的错误。
  • 您的服务是publisher,所有调用它的客户都是subscribers。所以你不应该使用subscribe
  • 你永远不应该/route/user/login/{username}/{password} 这将通过互联网免费发送用户名和密码供所有人查看security.stackexchange.com/questions/142695/…

标签: spring-security spring-webflux


【解决方案1】:

从 spring 5.1 开始,您应该使用HttpHeaders#setBasicAuth 设置基本身份验证,如下所示:

webClient
    .get()
    .uri("https://example.com")
    .headers(headers -> headers.setBasicAuth("username", "password"))
    .exchange()
    ....

以前使用 .filter(basicAuthentication("user", "password") 的方法现在已弃用。

【讨论】:

    【解决方案2】:

    Spring 提供 API 用于通过 ClientFilters 向您的 WebClient 提供基本身份验证参数。

    您可以使用较少的自定义编码来设置 Authorization 标头,从而获得相同的结果。

    请参阅以下 spring 文档中的代码 sn-p:

    import static org.springframework.web.reactive.function.client.ExchangeFilterFunctions.basicAuthentication;
    
        WebClient client = WebClient.builder()
                .filter(basicAuthentication("user", "password"))
                .build();
    

    【讨论】:

      【解决方案3】:

      HTTP 基本身份验证需要在 Authorization 标头中以 Base64 格式编码的用户名和密码。此外,您不需要登录端点,因为此信息应随每个请求一起发送。

      将 Basic Auth 标头添加到客户端中的每个调用中,如下所示:

      String basicAuthHeader = "basic " + Base64Utils.encodeToString((username + ":" + password).getBytes())
      
      client.get().uri("/route/user/all")
            .accept(MediaType.APPLICATION_JSON)
            .header(HttpHeaders.AUTHORIZATION, basicAuthHeader)
            .exchange()
            .flatMapMany(response -> response.bodyToFlux(User.class))
            .subscribe(u -> System.out.println("All Users : " + u.getUsername() + ":" + u.getEmail() + ":" + u.getFullname()));
      

      【讨论】:

        猜你喜欢
        • 2014-02-22
        • 2018-05-09
        • 1970-01-01
        • 1970-01-01
        • 2012-12-31
        • 2012-08-14
        • 2016-08-31
        • 1970-01-01
        • 2017-08-25
        相关资源
        最近更新 更多