在Android上使用Retrofit进行多部分“发布”时的签名问题

huangapple go评论51阅读模式
英文:

Signature issue while multipart "posting" with Retrofit on Android

问题

I am having a problem trying to send data to my server using multipart/form-data

If I send only 2 parts (file included) I get an error 400 (saying I am missing the 2 others parts)

but if I send 3 or 4 parts I get an error 401 because my server respond with a signature issue.

here is my code.
My Interface:

@POST("api/{id}/edit")
@Multipart
fun postMultipart(
    @Path("id") id: Int,
    @Part commissioner: MultipartBody.Part,
    @Part commissioning: MultipartBody.Part,
    @Part file: MultipartBody.Part?,
    @Part commissioningDate: MultipartBody.Part
): Call<ResponseBody>

So If I only send file and for example commissioner my server is responding 400 but if I send file and commissioner and commissioning my server is responding 401

I also tried MultipartBody.Part or RequestBody for other parts than the file (same result)

My AsyncTask making the call:

val interface = RetrofitSignedClient().getClient().create(Interface::class.java)

val f = getFile(context, fileUri)
val requestFile: RequestBody = f.asRequestBody()
val fileBody: MultipartBody.Part = MultipartBody.Part.createFormData("file", f.name, requestFile)

val commissionerIdPart =
    MultipartBody.Part.createFormData("commissioner", commissioner)

val commissioningPart =
    MultipartBody.Part.createFormData("commissioning", commissioning)

val datePart =
    MultipartBody.Part.createFormData("commissioningDate", date)

val response =
    interface.postMultipart(
        id = id,
        commissioner = commissionerIdPart,
        commissioning = commissioningPart,
        file = fileBody,
        commissioningDate = datePart
    ).execute()

The retrofit client:

val consumer = OkHttpOAuthConsumer(consumerKey, consumerSecret)
consumer.setTokenWithSecret(token, secret)

val client = OkHttpClient.Builder()
    .addInterceptor(SigningInterceptor(consumer)).build()

return Retrofit.Builder().baseUrl(WS_HOSTNAME_PROJECT)
    .addConverterFactory(GsonConverterFactory.create(GsonBuilder().setLenient().create()))
    .client(client)
    .build()

For the 401 error, on phone logs I have 401 Unauthorized {"message":"An authentication exception occurred."}

and on server side:

Verification of signature failed (signature base string was "POST&http%3A%2F%2Fmy.server.address%2Fapi%2FID%2Fedit&commissioner%3D110000000292%26commissioning%3D0%26oauth_consumer_key%3DXXXX%26oauth_nonce%3DXXXX%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3DXXX%26oauth_token%3DXXXX%26oauth_version%3D1.0"). with Array ( [0] => 7992a0f54cc2104fec647c75a9aa8317 [1] => 1b1fea099c727b89d9c0cb9d9a618608 [2] => access ) -- Signature verification failed (HMAC-SHA1)

Am I missing something?

英文:

I am having a problem trying to send data to my server using multipart/form-data

If I send only 2 parts (file included) I get an error 400 (saying I am missing the 2 others parts)

but if I send 3 or 4 parts I get an error 401 because my server respond with a signature issue.

here is my code.
My Interface:

@POST(&quot;api/{id}/edit&quot;)
@Multipart
fun postMultipart(
    @Path(&quot;id&quot;) id: Int,
    @Part commissioner: MultipartBody.Part,
    @Part commissioning: MultipartBody.Part,
    @Part file: MultipartBody.Part?,
    @Part commissioningDate: MultipartBody.Part
): Call&lt;ResponseBody&gt;

So If I only send file and for example commissioner my server is responding 400 but if I send file and commissioner and commissioning my server is responding 401

I also tried MultipartBody.Part or RequestBody for other parts than the file (same result)

My AsyncTask making the call:

val interface = RetrofitSignedClient().getClient().create(Interface::class.java)

val f = getFile(context, fileUri)
val requestFile: RequestBody = f.asRequestBody()
val fileBody: MultipartBody.Part = MultipartBody.Part.createFormData(&quot;file&quot;, f.name, requestFile)

val commissionerIdPart =
    MultipartBody.Part.createFormData(&quot;commissioner&quot;, commissioner)

val commissioningPart =
    MultipartBody.Part.createFormData(&quot;commissioning&quot;, commissioning)

val datePart =
    MultipartBody.Part.createFormData(&quot;commissioningDate&quot;, date)

val response =
    interface.postMultipart(
        id = id,
        commissioner = commissionerIdPart,
        commissioning = commissioningPart,
        file = fileBody,
        commissioningDate = datePart
    ).execute()

The retrofit client:

val consumer = OkHttpOAuthConsumer(consumerKey, consumerSecret)
consumer.setTokenWithSecret(token, secret)

val client = OkHttpClient.Builder()
    .addInterceptor(SigningInterceptor(consumer)).build()

return Retrofit.Builder().baseUrl(WS_HOSTNAME_PROJECT)
    .addConverterFactory(GsonConverterFactory.create(GsonBuilder().setLenient().create()))
    .client(client)
    .build()

For the 401 error, on phone logs I have 401 Unauthorized {&quot;message&quot;:&quot;An authentication exception occurred.&quot;}

and on server side:

Verification of signature failed (signature base string was &quot;POST&amp;http%3A%2F%2Fmy.server.address%2Fapi%2FID%2Fedit&amp;commissioner%3D110000000292%26commissioning%3D0%26oauth_consumer_key%3DXXXX%26oauth_nonce%3DXXXX%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3DXXX%26oauth_token%3DXXXX%26oauth_version%3D1.0&quot;). with Array ( [0] =&gt; 7992a0f54cc2104fec647c75a9aa8317 [1] =&gt; 1b1fea099c727b89d9c0cb9d9a618608 [2] =&gt; access ) -- Signature verification failed (HMAC-SHA1)

Am I missing something?

答案1

得分: 0

问题实际上出现在服务器端。

如果只有一个参数存在,使用的库会对请求进行签名,而如果存在两个或更多参数,则会带上参数一起签名。

英文:

In fact the issue was on server side.

The lib used signed the request without params if only one is present and with params if 2 or more are present.

huangapple
  • 本文由 发表于 2023年6月1日 00:25:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/76375574.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定