У меня проблема с генерацией подписи для нового API погоды Yahoo.Они обновили свой API и теперь требовали подписи OAuth 1.0.
Я пытался использовать пример кода из этой документации https://developer.yahoo.com/weather/documentation.html?guccounter=1#oauth-java
Я использую Retrofit 2 и OkHttpClient.Мой код:
public interface WeatherApi {
@Headers({
"Content-Type: application/json",
"Yahoo-App-Id: " + YAHOO_APP_ID
})
@GET("forecastrss")
Observable<WeatherInfo> getWeather(@Header("Authorization") String authorization,
@QueryMap Map<String, String> params);
}
public final class WeatherInjection {
public static WeatherApi provideYahooWeatherApi() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient okHttpClient = new OkHttpClient()
.newBuilder()
.addInterceptor(interceptor)
.build();
Gson gson = new GsonBuilder()
.registerTypeAdapter(WeatherInfo.class, new WeatherInfo.WeatherInfoJsonDeserializer())
.create();
GsonConverterFactory gsonConverterFactory = GsonConverterFactory.create(gson);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(WeatherApi.BASE_URL)
.client(okHttpClient)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(gsonConverterFactory)
.build();
return retrofit.create(WeatherApi.class);
}
}
Сгенерированная здесь подпись:
public String buildAuthorization(String location) {
try {
String oauthNonce = UUID.randomUUID().toString();
long timestamp = System.currentTimeMillis() / 1000;
List<String> parameters = new ArrayList<>();
parameters.add("oauth_consumer_key=" + CLIENT_ID);
parameters.add("oauth_nonce=" + oauthNonce);
parameters.add("oauth_signature_method=HMAC-SHA1");
parameters.add("oauth_timestamp=" + timestamp);
parameters.add("oauth_version=1.0");
parameters.add("location=" + location);
parameters.add("format=json");
Collections.sort(parameters);
Log.d("My", "Sorted list: " + parameters);
StringBuilder parametersList = new StringBuilder();
for (int i = 0; i < parameters.size(); i++) {
parametersList.append((i > 0) ? "&" : "").append(parameters.get(i));
}
Log.d("My", "Parameter list: " + parametersList.toString());
String signatureString = "GET&" +
URLEncoder.encode(BASE_URL + "forecastrss", UTF_8) + "&" +
URLEncoder.encode(parametersList.toString(), UTF_8);
Log.d("My", "Signature: " + signatureString);
SecretKeySpec signingKey = new SecretKeySpec((CLIENT_SECRET + "&").getBytes(), "HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(signingKey);
byte[] rawHMAC = mac.doFinal(signatureString.getBytes());
String signature = Base64.encodeToString(rawHMAC, Base64.NO_WRAP);
return "OAuth " +
"oauth_consumer_key=\"" + CLIENT_ID + "\", " +
"oauth_nonce=\"" + oauthNonce + "\", " +
"oauth_timestamp=\"" + timestamp + "\", " +
"oauth_signature_method=\"HMAC-SHA1\", " +
"oauth_signature=\"" + signature + "\", " +
"oauth_version=\"1.0\"";
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
Я обнаружил, что когда я использовал какзначение для параметра "location" одним словом (например, "sunnyvale") работает хорошо.Но когда "location" содержит> 1 слова или содержит "," и "", тогда я получаю ошибку 401.Например, «location = sunnyvale, ca» или «Santa Monica» не будут работать, но «SantaMonica» будет работать нормально.
Обращаюсь к вам за помощью