Как добавить базовую аутентификацию HTTP для HTTP.POST и HTTP.PUT на веб-клиенте безопасности webflux? - PullRequest
0 голосов
/ 08 июля 2019

Я пытаюсь создать несколько кодов безопасности webflux, как показано ниже,

@Configuration
@EnableWebFluxSecurity
public class BlogWebFluxSecurityConfig {

    @Bean
    public MapReactiveUserDetailsService userDetailsService() {

        UserDetails userWebFlux = User.withUsername("joseph").password(passwordEncoder().encode("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();
    } 

    @Bean 
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

, а также создать клиентские коды webflux с классом WebClient.Я использую http базовую аутентификацию.В методе HTTP GET базовая аутентификация http работает успешно.Это коды веб-клиентов, которые хорошо работают.

client.get().uri("/route/post/id/{id}", 10).accept(MediaType.APPLICATION_JSON)
                .header(HttpHeaders.AUTHORIZATION, basicAuthHeader).exchange()
                .flatMap(response -> response.bodyToMono(Post.class))
                .subscribe(p -> System.out.println("GET by Id : " + p.getUser().getUsername() + ":" + p.getTitle()));

Но при использовании методов HTTP.POST и HTTP.PUT базовая аутентификация http не работает, даже выдает исключение.

public class WebFluxBlogClient {

    private WebClient client = WebClient.create("http://localhost:8080");  

    String basicAuthHeader = "basic " + Base64Utils.encodeToString(("joseph" + ":" + "password").getBytes());

    public void functionOnSecurityDocument() {

        Map<String, String> mapUser = new HashMap<String, String>();
        mapUser.put("username", "joseph");
        mapUser.put("password", "password");

        client.post().uri("/route/user/login").accept(MediaType.APPLICATION_JSON).body(Mono.just(mapUser), Map.class)
                .header(HttpHeaders.AUTHORIZATION, basicAuthHeader).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").accept(MediaType.APPLICATION_JSON).body(Mono.just(user), User.class)
                .header(HttpHeaders.AUTHORIZATION, basicAuthHeader).exchange() 
                .map(ClientResponse::statusCode).subscribe(response -> System.out.println("User Creation: " + response.getReasonPhrase()));


        client.put().uri("/route/post/{id}/{content}", 7, "test sentences....")
                .accept(MediaType.APPLICATION_JSON).header(HttpHeaders.AUTHORIZATION, basicAuthHeader).exchange().flatMap(response -> response.bodyToMono(Post.class))
                .subscribe(p -> System.out.println("EDIT by Id : " + p.getUser().getUsername() + ":" + p.getBody()));
    }
}

Значения ответа

Login : Forbidden
User Creation: Forbidden
2019-07-08 12:46:16.443  WARN 4800 --- [ctor-http-nio-3] io.netty.util.ReferenceCountUtil         : Failed to release a message: DefaultLastHttpContent(data: PooledSlicedByteBuf(freed), decoderResult: success)

io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1
    at io.netty.util.internal.ReferenceCountUpdater.toLiveRealRefCnt(ReferenceCountUpdater.java:74) ~[netty-common-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.util.internal.ReferenceCountUpdater.release(ReferenceCountUpdater.java:138) ~[netty-common-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.buffer.AbstractReferenceCountedByteBuf.release(AbstractReferenceCountedByteBuf.java:100) ~[netty-buffer-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.handler.codec.http.DefaultHttpContent.release(DefaultHttpContent.java:94) ~[netty-codec-http-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.util.ReferenceCountUtil.release(ReferenceCountUtil.java:88) ~[netty-common-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.util.ReferenceCountUtil.safeRelease(ReferenceCountUtil.java:113) ~[netty-common-4.1.36.Final.jar:4.1.36.Final]
    at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:120) ~[reactor-netty-0.8.9.RELEASE.jar:0.8.9.RELEASE]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) ~[netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) ~[netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) ~[netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102) ~[netty-codec-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) ~[netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) ~[netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) ~[netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:438) ~[netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:323) ~[netty-codec-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:297) ~[netty-codec-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:253) ~[netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) ~[netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) ~[netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) ~[netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1408) ~[netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) ~[netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) ~[netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:930) ~[netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163) ~[netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:682) ~[netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:617) ~[netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:534) ~[netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:496) ~[netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:906) ~[netty-common-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.36.Final.jar:4.1.36.Final]
    at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]

2019-07-08 12:46:16.443  WARN 4800 --- [ctor-http-nio-3] reactor.netty.channel.FluxReceive        : [id: 0xdfda1db5, L:0.0.0.0/0.0.0.0:54009] An exception has been observed post termination, use DEBUG level to see the full stack: reactor.core.Exceptions$ErrorCallbackNotImplemented: org.springframework.web.reactive.function.UnsupportedMediaTypeException: Content type 'text/plain' not supported for bodyType=com.aaa.blog.wf.model.Post

Я понятия не имею, что означает исключение.Я хочу знать, как применить базовую аутентификацию http для HTTP.POST и HTTP.PUT методом webflux webclient.Любой ответ будет оценен.Спасибо

== Обновленные детали ==

Я изменяю конфигурацию безопасности, как показано ниже, но она не срабатывает.

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

        return http.build();
    }

Для вашей информации яприсоедините класс маршрутизатора.

@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.POST("/route/user/login"), handler::authenticate);
    }

Но выдают те же сообщения об ошибках, как показано ниже,

Login : Forbidden
User Creation: Forbidden

В моей конфигурации SecurityWebFilterChain есть некоторые проблемы?Пожалуйста, пришлите мне свой ответ.

Ответы [ 2 ]

2 голосов
/ 08 июля 2019

Вы явно ограничиваете аутентификацию только запросами GET.Если вы замените эту строку в конфигурации SecurityWebFilterChain:

.pathMatchers(HttpMethod.GET, "/route/user/**", "/route/post/**").hasRole("USER")

более общим методом, исключая метод HTTP, аутентификация должна применяться ко всем методам HTTP.

.pathMatchers("/route/user/**", "/route/post/**").hasRole("USER")
0 голосов
/ 08 июля 2019

Приложение, вероятно, дает вам 403, потому что ожидает токен CSRF в запросах, которые имеют побочные эффекты, такие как POST.Spring Security по умолчанию включает защиту CSRF.

Вам нужно настроить свой внешний интерфейс для отправки токена CSRF по вашему запросу POST или вам нужно отключить CSRFвообще .

...