繁体   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