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>{
通过这些更改,调用成功,我长期 运行 的头痛就结束了。
我正在为本地慈善组织开发用户应用程序,需要访问他们的 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>{
通过这些更改,调用成功,我长期 运行 的头痛就结束了。