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

时间:2020-08-26 00:44:24

标签: android api kotlin oauth-2.0 retrofit2

我正在为本地慈善组织开发用户应用程序,并且需要访问其API。该API来自野生杏,这是发出令牌请求的文档:

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

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

-----------------要获取具有API密钥的访问令牌,您必须发出以下请求:

POST / auth /令牌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 /令牌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”作为端点)。如果有人可以告诉我我到底在哪里搞砸了,那会非常感谢,我尝试过的代码如下。

enter code here

接口:

界面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)

}

主要活动中的用来拨打电话的功能

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获得访问权限,并查看响应,因此我知道它是有效的。

2 个答案:

答案 0 :(得分:1)

您的客户凭据请求看起来大部分都很好。我唯一看到的看起来不对的地方是“基本”和编码凭据之间的AUTH标头中没有空格字符。

如果这不起作用,您可以trace the HTTP request并确认您发送的是您想发送的消息吗?

答案 1 :(得分:1)

感谢您的观察,它使我得以弄清楚在我最初的尝试中最终出了什么问题。添加该空间后,我跟踪了请求,发现该请求实际上是为内容类型发送两个标头。解决方法是在接口的改造调用中设置标头:

    interface WAApiCall {
@POST("auth/token")

乐趣callPost(@Body正文:okhttp3.RequestBody,@Header(“ Content-type”)类型:String):调用 }

如您所见,主体也略有不同,该呼叫正在接通但返回“ 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>{

有了这些更改,呼叫成功了,我长期的头痛也结束了。