Kotlin Android oauth2 令牌请求仅返回错误

Kotlin Android oauth2 token request only returning errors

我正在为本地慈善组织开发用户应用程序,需要访问他们的 API。 API来自野杏,这是申请token的文档:

身份验证令牌是从位于 https://oauth.wildapricot.org 的 Wild Apricot 的身份验证服务获取的。此服务遵守 oAuth 2.0。

这是我需要实现的访问选项:

----------------为了使用 API 密钥获取访问令牌,您必须提出以下请求:

POST /auth/token HTTP/1.1

Host: oauth.wildapricot.org

Authorization: Basic BASE64_ENCODED("APIKEY:YOUR_API_KEY")

Content-type: application/x-www-form-urlencoded

grant_type=client_credentials&scope=auto

--------------------------------所以。最后您的请求将如下所示:

POST /auth/token HTTP/1.1

Host: oauth.wildapricot.org

Authorization: Basic QVBJS0VZOm85c2U4N3Jnb2l5c29lcjk4MDcwOS0=

Content-type: application/x-www-form-urlencoded

grant_type=client_credentials&scope=auto

我正在尝试使用 retrofit2 和 okhttp3 拦截器进行此调用,并收到错误的请求响应(我是新手和学习者,除了 400 错误请求外,无法获得任何其他响应(当我使用“/auth/token”作为端点时),或找不到 404(当我使用“/auth/token HTTP/1.1”作为端点时)。如果有人能告诉我在哪里正是我搞砸了非常感谢,我试过的代码如下。

接口:

interface WAApiCall {
@POST("auth/token")
fun callPost(@Body body:String ): Call<AuthToken>
}

呼叫服务:

object WAApiCallService {

private const val API_KEY = "xxxxxxxxIxHavexAxValidxKeyxxxx"
private const val BASE_URL = "https://oauth.wildapricot.org/"
private val AUTH = "Basic" + Base64.encodeToString(API_KEY.toByteArray(), Base64.NO_WRAP) 
private const val CONTENT_TYPE = "application/x-www-form-urlencoded"
private var api:WAApiCall? = null

private fun getWAApi(context: Context) : WAApiCall {

    if(api==null){
        val OkHttpClient = OkHttpClient.Builder()
        val logging = HttpLoggingInterceptor()
        logging.level = HttpLoggingInterceptor.Level.BASIC

        OkHttpClient.addInterceptor{chain ->
           
            val request = chain.request()
            Log.d("CALL", request.body.toString())
            
            val newRequest = request.newBuilder()
                .addHeader("Host", "oauth.wildapricot.org")
                .addHeader("Authorization", AUTH ) 
                .addHeader("Content-type", CONTENT_TYPE)
                .method(request.method, request.body)
                .build()
            chain.proceed(newRequest)
        }

        api = Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .client(OkHttpClient.build())
            .build()
            .create(WAApiCall::class.java)
    }

    return api!!

}


fun call(context: Context) =
    getWAApi(context)
}

Main 中的函数 Activity 进行调用:

fun testRequest(){
val call = WAApiCallService.call(this)
call.callPost("grant_type=client_credentials&scope=auto")
    .enqueue(object: Callback<AuthToken>{
        override fun onFailure(call: Call<AuthToken>, t: Throwable) {
            Log.i("FAILURE", t.localizedMessage)
        }

        override fun onResponse(call: Call<AuthToken>, response: Response<AuthToken>) {
            Log.i("SUCCESS", "TOKEN = ${response.body().toString()}")
            Log.i("SUCCESS", "${response}")
            val token = response.body()?.accessToken
            Log.i("SUCCESS", "TOKEN = $token")
        }
    })
}

错误信息:

I/SUCCESS: TOKEN = null
I/SUCCESS: Response{protocol=http/1.1, code=400, message=Bad Request,   url=https://oauth.wildapricot.org/auth/token}

我认为我只是不明白如何以某种基本方式实现这种类型的请求,我也无法让它在 Postman 中工作。我知道我需要将凭据发送到身份验证服务器,并接收一个访问令牌,该令牌将过期并需要刷新,并且它将包含在每个实际的 API 端点调用中,我想我'我只是在该过程的最重要步骤中遗漏了一些关键的东西(获得实际令牌,我想这是我的一个简单的,前额拍打式的误解?)。野杏 API 在 swagger hub 上,我可以使用我的 API 密钥通过那个 UI 获得访问权限,并看到响应,所以我知道它是有效的。

您的客户端凭据请求看起来基本没问题。我唯一能看到的错误是 'Basic' 和编码凭据之间的 AUTH header 中没有 space 字符。

如果这不起作用,您可以 trace the HTTP request 并验证您发送的消息是否如您所愿。

感谢您的观察,它让我弄清楚了我最初尝试的最终错误所在。添加 space 后,我跟踪请求,发现它实际上发送了两个 header 内容类型。

解决方法是在界面的改造调用中设置 header:

interface WAApiCall {
@POST("auth/token")
fun callPost(@Body Body: okhttp3.RequestBody, @Header("Content-type") type: String): Call<AuthToken>
}

如您所见,body 也略有不同,呼叫接通但返回:

"unsupported_grant_type".

我将原始字符串作为 body 参数传递,该参数在请求中包含引号。那里的解决方案是传递 okhttp3.Request body 类型而不是原始字符串,在进行实际调用的函数中它看起来像这样:

val body: "grant_type=client_credentials&scope=auto&obtain_refresh_token=true"
val requestBody = RequestBody.create("text/plain".toMediaTypeOrNull(),body)
val call = WAApiCallService.call(this)
call.callPost(requestBody,"application/x-www-form-urlencoded")
    .enqueue(object: Callback<AuthToken>{

通过这些更改,调用成功,我长期 运行 的头痛就结束了。