我正在为本地慈善组织开发用户应用程序,并且需要访问其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获得访问权限,并查看响应,因此我知道它是有效的。
答案 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>{
有了这些更改,呼叫成功了,我长期的头痛也结束了。