当前位置: 首页 > 知识库问答 >
问题:

SpringWebClient发布登录。微软在线。com给出了404错误

马煌
2023-03-14

我在Kotlin中使用Spring Responsive WebClient(org.springframework.web.Reactive.function.client.WebClient)在Azure AD中实现Oauth2时遇到问题,请遵循以下文档:https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow#first-case-access-token-request-with-a-shared-secret

我的组织有自己的租户,但是这个问题也适用于使用https://login.microsoftonline.com/common/oauth2/v2.0/token.

如果执行以下CURL,我将得到预期的400个错误,我需要参数grant\u type

curl-d''https://login.microsoftonline.com/common/oauth2/v2.0/token

这很好,这意味着我从服务中得到了一个正确的错误,我可以处理包括缺少的参数。然而,对同一个uri使用WebClient时,我得到了一个404错误。

这是我的实现:

import com.fasterxml.jackson.annotation.JsonProperty
import org.springframework.stereotype.Component
import org.springframework.web.reactive.function.client.WebClient


@Component
class AzureADClient {

    fun oidcToken(): String {
        var received = WebClient.create("https://login.microsoftonline.com/common/oauth2/v2.0/token").post()
            .retrieve()
            .bodyToMono(OidcToken::class.java)
            .block()

        return received.token
    }

    data class OidcToken(
        @JsonProperty(value = "access_token", required = true)
        val token: String,
        @JsonProperty(value = "token_type", required = true)
        val type: String,
        @JsonProperty(value = "expires_in", required = true)
        val expiresIn: Int
    )
}

这是我得到的堆栈跟踪:

org.springframework.web.reactive.function.client.WebClientResponseException$NotFound: 404 Not Found from POST https://login.microsoftonline.com/common/oauth2/v2.0/token
    at org.springframework.web.reactive.function.client.WebClientResponseException.create(WebClientResponseException.java:185)
    Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
    |_ checkpoint ⇢ 404 from POST https://login.microsoftonline.com/common/oauth2/v2.0/token [DefaultWebClient]
Stack trace:
        at org.springframework.web.reactive.function.client.WebClientResponseException.create(WebClientResponseException.java:185)
        at org.springframework.web.reactive.function.client.DefaultClientResponse.lambda$createException$1(DefaultClientResponse.java:209)
        at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:100)
        at org.springframework.cloud.sleuth.instrument.reactor.ScopePassingSpanSubscriber.onNext(ScopePassingSpanSubscriber.java:90)
        at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1712)
        at reactor.core.publisher.FluxDefaultIfEmpty$DefaultIfEmptySubscriber.onComplete(FluxDefaultIfEmpty.java:100)
        at org.springframework.cloud.sleuth.instrument.reactor.ScopePassingSpanSubscriber.onComplete(ScopePassingSpanSubscriber.java:104)
        at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onComplete(FluxMapFuseable.java:144)
        at reactor.core.publisher.FluxContextStart$ContextStartSubscriber.onComplete(FluxContextStart.java:122)
        at org.springframework.cloud.sleuth.instrument.reactor.ScopePassingSpanSubscriber.onComplete(ScopePassingSpanSubscriber.java:104)
        at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onComplete(FluxMapFuseable.java:144)
        at org.springframework.cloud.sleuth.instrument.reactor.ScopePassingSpanSubscriber.onComplete(ScopePassingSpanSubscriber.java:104)
        at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onComplete(FluxFilterFuseable.java:165)
        at org.springframework.cloud.sleuth.instrument.reactor.ScopePassingSpanSubscriber.onComplete(ScopePassingSpanSubscriber.java:104)
        at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1713)
        at reactor.core.publisher.MonoCollect$CollectSubscriber.onComplete(MonoCollect.java:160)
        at org.springframework.cloud.sleuth.instrument.reactor.ScopePassingSpanSubscriber.onComplete(ScopePassingSpanSubscriber.java:104)
        at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:136)
        at org.springframework.cloud.sleuth.instrument.reactor.ScopePassingSpanSubscriber.onComplete(ScopePassingSpanSubscriber.java:104)
        at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:252)
        at org.springframework.cloud.sleuth.instrument.reactor.ScopePassingSpanSubscriber.onComplete(ScopePassingSpanSubscriber.java:104)
        at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:252)
        at org.springframework.cloud.sleuth.instrument.reactor.ScopePassingSpanSubscriber.onComplete(ScopePassingSpanSubscriber.java:104)
        at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:136)
        at reactor.netty.channel.FluxReceive.terminateReceiver(FluxReceive.java:421)
        at reactor.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:211)
        at reactor.netty.channel.FluxReceive.onInboundComplete(FluxReceive.java:369)
        at reactor.netty.channel.ChannelOperations.onInboundComplete(ChannelOperations.java:367)
        at reactor.netty.channel.ChannelOperations.terminate(ChannelOperations.java:416)
        at reactor.netty.http.client.HttpClientOperations.onInboundNext(HttpClientOperations.java:612)
        at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:90)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
        at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
        at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
        at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:321)
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:295)
        at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
        at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1486)
        at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1235)
        at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1282)
        at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:498)
        at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:437)
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
        at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:834)

在其他交互中,我将WebClient与POST请求一起使用。如果我用restemplate()替换WebClient调用。postForObject()我得到了预期的400错误,但我正试图在我的应用程序中一直使用WebClient。我试着对https://postman-echo.com/post,在那里我得到了一个合理的响应,因此它似乎是特定于登录的。微软在线。comendpoint。

有人遇到过这种情况,并找到了解决办法吗?

共有1个答案

盖向荣
2023-03-14

我找到了解决办法。首先,这篇帖子的回复建议主机不接受分块传输编码:https://social.msdn.microsoft.com/Forums/en-US/8efc2e39-8e9c-4449-8e25-13b97a7acf15/azure-ad-oauth-20-token-endpoint-recently-started-returning-404-with-empty-response-body-but-used?forum=WindowsAzureAD

这是通过curl验证的:

> curl -H "Transfer-Encoding: chunked" -d ''  https://login.microsoftonline.com/common/oauth2/v2.0/token -v
< ...
< HTTP/1.1 404 Not Found
< ...

我首先尝试扩展请求以包含所需的参数,如下所示:

    fun oidcToken(): String {

        val map = LinkedMultiValueMap<String, String>()

        map.add("client_id", "client_id")
        map.add("client_secret", "client_secret")
        map.add("grant_type", "grant_type")
        map.add("scope", "api://scope_id/.default")

        val received = WebClient
            .create("https://login.microsoftonline.com/common/oauth2/v2.0/token")
            .post()
            .body(BodyInserters.fromMultipartData(map))
            .retrieve()
            .bodyToMono(OidcToken::class.java)
            .block()

        return received.token
    }

这产生了与之前相同的404错误,因此传输可能也在这里分块。

解决方案原来是使用. body Value(map)而不是. body(BodyInserters.fromMultipartData(map))

我尝试设置内容长度标题,回答如下:https://stackoverflow.com/a/51049535/9658830.使用此方法,我确实收到了400个错误,因此找到了服务器,但bodyValue()证明是一个更简单的解决方案。

 类似资料:
  • 我使用和以及开发了一个Java web应用程序。我的应用程序在本地pc上运行,没有任何错误。 但是在我托管了我的应用程序之后,我无法访问servlet。它给了我错误。我不习惯在我的应用程序中映射servlet。我使用了。 托管服务器使用和。 可能是什么问题?我该怎么解决这个问题? 新更新 我购买主机的地方给了我上传文件的。tomcat中没有上传文件的地方,也没有上传文件到director的地方。所

  • 错误: HTTP状态404–未找到 类型状态报告 消息/降级任务/ 说明源服务器找不到目标资源的当前表示形式,或不愿意透露存在该表示形式。 Apache Tomcat/7.0.90 代码:

  • 当我构建我的应用程序并尝试它时,没有任何错误,但当我在google play store上发布我的应用程序并尝试登录Facebook时,它会给我一个错误。这个错误是一个错误的散列键,因为散列键发生了变化(我得到了sign应用程序的散列键,通过许多方式给了我相同的has键,工作正常)这是第一个问题。 我的第二个问题是当尝试使用gmail登录(谷歌登录)获取字段错误。 (您有错误的OAuth2相关配置

  • 问题内容: 我正在尝试通过前端发布数据,而烧瓶应用程序抛出了400个错误的请求。但是,如果我使用Curl call做同样的事情,它似乎工作正常。我不知道表格中缺少什么。 以下是我的表单代码 在服务器端: 服务器端对我来说似乎很好。由于我收到卷曲请求的响应 问题答案: 嗯,我想我明白了:您只为元素设置,但未设置。仍用于发送到服务器的表单数据中。这导致在这导致400错误。

  • Microsoft's latest announcement, called Microsoft .NET, while touted by the likes of Fortune Magazine as a huge "revolution", is really nothing but vaporware, and I think it proves that something has

  • 我无法登录到已发布的apk,但调试apk工作正常。谷歌服务。发布的apk缺少json文件,我不知道为什么会这样。请有人帮我解决这个问题。下面我列出了我的应用程序级依赖项。 项目级依赖项 我得到这个错误请任何人帮帮我。