簡體   English   中英

Kotlin Android oauth2 令牌請求僅返回錯誤

[英]Kotlin Android oauth2 token request only returning errors

我正在為當地慈善組織開發用戶應用程序,需要訪問他們的 API。 API來自野杏,這是進行令牌請求的文檔:

身份驗證令牌是從 Wild Apricot 的身份驗證服務獲得的,該服務位於https://oauth.wildapricot.org 此服務遵循 oAuth 2.0。

這是我需要實現的訪問選項:

-----------------為了使用 API 密鑰獲取訪問令牌,您必須發出以下請求:

POST /auth/token HTTP/1.1

主持人:oauth.wildapricot.org

授權:基本 BASE64_ENCODED("APIKEY:YOUR_API_KEY")

內容類型:application/x-www-form-urlencoded

grant_type=client_credentials&scope=auto

- - - - - - - - - - - - - - - -所以。 最后,您的請求將如下所示:

POST /auth/token HTTP/1.1

主持人:oauth.wildapricot.org

授權:基本 QVBJS0VZOm85c2U4N3Jnb2l5c29lcjk4MDcwOS0=

內容類型: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 端點調用中,我想我只是錯過了一些東西在該過程中最重要的步驟中至關重要(獲得實際令牌,我想這是一個簡單的、拍打額頭的誤會?)。 Wild apricot API 位於 swagger hub 上,我可以使用我的 API 密鑰通過該 UI 訪問並查看響應,因此我知道它是有效的。

您的客戶端憑據請求看起來大部分都很好。 我能看到的唯一錯誤是 AUTH 標頭中“基本”和編碼憑據之間沒有空格字符。

如果這不起作用,您能否跟蹤 HTTP 請求並驗證您正在發送您認為的消息。

謝謝你的觀察,它讓我弄清楚了我最初的嘗試最終出了什么問題。 添加該空間后,我跟蹤請求,發現它實際上發送了兩個內容類型的標頭。

解決方法是在接口的改造調用中設置標頭:

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 正文類型而不是原始字符串,如下所示:

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>{

通過這些更改,呼叫成功了,我長期的頭痛也結束了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM