質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
87.20%
OAuth

OAuth(Open Authorization)は、APIを通して保護されたリソース(サードパーティのアプリケーション)へアクセスする為のオープンプロトコルです。

OAuth 2.0

OAuth 2.0(Open Authorization 2.0)は、APIを通して保護されたリソース(サードパーティのアプリケーション)へアクセスする為のオープンプロトコルです。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

解決済

JavaからのZAIM APIの呼び出し(oauth)でリクエストトークンが取得できない

tamechop
tamechop

総合スコア6

OAuth

OAuth(Open Authorization)は、APIを通して保護されたリソース(サードパーティのアプリケーション)へアクセスする為のオープンプロトコルです。

OAuth 2.0

OAuth 2.0(Open Authorization 2.0)は、APIを通して保護されたリソース(サードパーティのアプリケーション)へアクセスする為のオープンプロトコルです。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

1回答

1評価

2クリップ

2903閲覧

投稿2018/03/10 09:57

編集2018/03/11 11:25

前提・実現したいこと

Javaで家計簿サイトZAIMのAPIをコールして、家計簿情報を取得・登録するアプリを開発したいとトライしているのですが、
リクエストトークンを取得する際にエラーになっている(?)と思われるところで詰まっています。
初歩的な問題かもしれませんが、助言宜しくお願い致します。

発生している問題・エラーメッセージ

Exception in thread "main" java.io.IOException: Server returned HTTP response code: 400 for URL: https://api.zaim.net/v2/auth/request at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1838) at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1439) at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254) at myapp.main(TestZaim.java:87)

該当のソースコード

Java

//ネット上で有識者が公開して下さっていたソースコードを流用しております。 import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.util.Map.Entry; import java.util.SortedMap; import java.util.TreeMap; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import sun.misc.BASE64Encoder; public class TestZaim { public static void main(String[] args) throws Exception { // OAuthにおいて利用する変数宣言 String consumerkey = "略"; String consumerSecret = "略"; String oauthToken = ""; // リクエストトークン取得時は利用しない String oauthTokenSecret = ""; // リクエストトークン取得時は利用しない String method = "POST"; String urlStr = "https://api.zaim.net/v2/auth/request"; // OAuthにおいて利用する共通パラメーター // パラメーターはソートする必要があるためSortedMapを利用 SortedMap<String, String> params = new TreeMap<String, String>(); params.put("oauth_consumer_key", consumerkey); params.put("oauth_signature_method", "HMAC-SHA1"); params.put("oauth_timestamp", String.valueOf(getUnixTime())); params.put("oauth_nonce", String.valueOf(Math.random())); params.put("oauth_version", "1.0"); // params.put("oauth_token", oauthToken); // リクエストトークン取得時は利用しない { /* * 署名(oauth_signature)の生成 */ // パラメーターを連結する String paramStr = ""; for (Entry<String, String> param : params.entrySet()) { paramStr += "&" + param.getKey() + "=" + param.getValue(); } paramStr = paramStr.substring(1); // 署名対象テキスト(signature base string)の作成 String text = method + "&" + urlEncode(urlStr) + "&" + urlEncode(paramStr); // 署名キーの作成 String key = urlEncode(consumerSecret) + "&" + urlEncode(oauthTokenSecret); // HMAC-SHA1で署名を生成 SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), "HmacSHA1"); Mac mac = Mac.getInstance(signingKey.getAlgorithm()); mac.init(signingKey); byte[] rawHmac = mac.doFinal(text.getBytes()); String signature = new BASE64Encoder().encode(rawHmac); // 署名をパラメータに追加 params.put("oauth_signature", signature); } // Authorizationヘッダの作成 String paramStr = ""; for (Entry<String, String> param : params.entrySet()) { paramStr += ", " + param.getKey() + "=\"" + urlEncode(param.getValue()) + "\""; } paramStr = paramStr.substring(2); String authorizationHeader = "OAuth " + paramStr; // APIにアクセス URL url = new URL(urlStr); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod(method); connection.setRequestProperty("Authorization", authorizationHeader); connection.connect(); BufferedReader reader = new BufferedReader(new InputStreamReader( connection.getInputStream())); String response; while ((response = reader.readLine()) != null) { System.out.println(response); } } private static int getUnixTime() { return (int) (System.currentTimeMillis() / 1000L); } private static String urlEncode(String string) { try { return URLEncoder.encode(string, "UTF-8"); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } }

試したこと

ZAIMへアプリ申請し、consumerKey,consumerSecretを取得。
リクエストトークン取得URL:https://api.zaim.net/v2/auth/request

ローカル環境よりeclispe上でJunitテストを実施し、上記エラーが発生。

補足情報(FW/ツールのバージョンなど)

Java1.6 + Junit
eclipse4.4

★20180311追記
ありがとうございます。Hurl.itにてPOST/oauth1.0aで試行してみましたので、その結果を記述します。

POST https://api.zaim.net/v2/auth/request?oauth_consumer_key=略&oauth_signature=EWWa2vRVJPnAKqXpbS5ZG7l5a0Y=&oauth_timestamp=1520742972&oauth_nonce=14367107062858923431520742972&oauth_version=1.0&oauth_signature_method=HMAC-SHA1

HEADERS
Connection: keep-alive
Content-Type: application/json; charset=utf-8
Date: Sun, 11 Mar 2018 04:36:13 GMT
Server: nginx
Transfer-Encoding: chunked
X-Powered-By: PHP/7.1.13-1+ubuntu16.04.1+deb.sury.org+1

BODY view raw
{
"error": true,
"message": "400 OAuth parameter(s) does not exist: oauth_callback"
}

TestZaim.java 87行目 connectionを実行する箇所です。
BufferedReader reader = new BufferedReader(new InputStreamReader(
connection.getInputStream()));

★20180311追記

・呼び出し方事例(公式 https://oauth.net/core/1.0a/#anchor43)
After Jane informs printer.example.com that she would like to print her vacation photo stored at photos.example.net, the printer website tries to access the photo and receives HTTP 401 Unauthorized indicating it is private. The Service Provider includes the following header with the response:

WWW-Authenticate: OAuth realm="http://photos.example.net/"
The Consumer sends the following HTTP POST request to the Service Provider:

https://photos.example.net/request_token?oauth_consumer_key=dpf43f3p2l4k3l03&oauth_signature_method=PLAINTEXT&oauth_signature=kd94hf93k423kf44%26&oauth_timestamp=1191242090&oauth_nonce=hsu94j3884jdopsl&oauth_version=1.0&oauth_callback=http%3A%2F%2Fprinter.example.com%2Frequest_token_ready
The Service Provider checks the signature and replies with an unauthorized Request Token in the body of the HTTP response:

oauth_token=hh5s93j4hdidpola&oauth_token_secret=hdhd0244k9j7ao03&oauth_callback_confirmed=true

・phpコードサンプル(公式 https://dev.zaim.net/home/api/authorize)

<?php require_once('HTTP/OAuth/Consumer.php'); session_start(); // Provider info $provider_base = 'https://api.zaim.net/v2/auth/'; $request_url = $provider_base.'request'; $authorize_url = 'https://auth.zaim.net/users/auth'; $access_url = $provider_base.'access'; $resource_url = 'https://api.zaim.net/v2/home/user/verify'; // Consumer info $consumer_key = YOUR_CONSUMER_KEY; $consumer_secret = YOUR_CONSUMER_SECRET; $callback_url = sprintf('http://%s%s', $_SERVER['HTTP_HOST'], $_SERVER['SCRIPT_NAME']); // Session clear if (isset($_REQUEST['action']) && $_REQUEST['action'] === 'clear') { session_destroy(); $_SESSION = array(); session_start(); } $content = ''; try { // Initialize HTTP_OAuth_Consumer $oauth = new HTTP_OAuth_Consumer($consumer_key, $consumer_secret); // Enable SSL $http_request = new HTTP_Request2(); $http_request->setConfig('ssl_verify_peer', false); $consumer_request = new HTTP_OAuth_Consumer_Request; $consumer_request->accept($http_request); $oauth->accept($consumer_request); if (!isset($_SESSION['type'])) $_SESSION['type'] = null; // 2 Authorize if ($_SESSION['type']=='authorize' && isset($_GET['oauth_token'], $_GET['oauth_verifier'])) { // Exchange the Request Token for an Access Token $oauth->setToken($_SESSION['oauth_token']); $oauth->setTokenSecret($_SESSION['oauth_token_secret']); $oauth->getAccessToken($access_url, $_GET['oauth_verifier']); // Save an Access Token $_SESSION['type'] = 'access'; $_SESSION['oauth_token'] = $oauth->getToken(); $_SESSION['oauth_token_secret'] = $oauth->getTokenSecret(); } // 3 Access if ($_SESSION['type']=='access') { // Accessing Protected Resources $oauth->setToken($_SESSION['oauth_token']); $oauth->setTokenSecret($_SESSION['oauth_token_secret']); $result = $oauth->sendRequest($resource_url, array(), 'GET'); $content = $result->getBody(); // 1 Request } else { // Get a Request Token $oauth->getRequestToken($request_url, $callback_url); // Save a Request Token $_SESSION['type'] = 'authorize'; $_SESSION['oauth_token'] = $oauth->getToken(); $_SESSION['oauth_token_secret'] = $oauth->getTokenSecret(); // Get an Authorize URL $authorize_url = $oauth->getAuthorizeURL($authorize_url); $content = "Click the link.<br />\n"; $content .= sprintf('<a href="%s">%s</a>', $authorize_url, $authorize_url); } } catch (Exception $e) { $content .= $e->getMessage(); } ?> <html> <head> <title>OAuth in PHP</title> </head> <body> <h2>Welcome to a Zaim OAuth PHP example.</h2> <p><a href='?action=clear'>Clear sessions</a></p> <p><pre><?php print_r($content); ?><pre></p> </body> </html>

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

yukapome789

2018/03/10 11:06

TestZaim.java:87がどの行のコードか教えていただけますか。
yukapome789

2018/03/11 02:17

下記のような、GET、POST等でリクエストを送って返却されたレスポンスを見れるツールがあるので、送信を想定しているURLを叩いてみて貰って返却値が何になるか教えてもらえますか?ちなみに単純にGETでhttps://api.zaim.net/v2/auth/requestを叩くと{ "error": true, "message": "400 OAuth parameter(s) does not exist: oauth_consumer_key, oauth_signature, oauth_signature_method, oauth_timestamp, oauth_nonce, oauth_version" }が帰ってきますね。https://www.hurl.it/
tamechop

2018/03/11 04:46

rarara様、ご助言ありがとうございます。補足情報へ記載致しました。ご確認お願い致します。
yukapome789

2018/03/11 06:30

追記ありがとうございます。想定してるURIでステータスコード400返ってきてますので、リクエスト先に問題があるか、リクエスト方法が間違っている可能性があります。公式リファレンスを読めない(なぜかログインできない)状態なので聞きますが、リクエスト時にPOSTでbodyにJSONで必要な情報をセットしてAPI叩くのではなく、追記のようにURIにクエリ文字列を付けてデータを渡すので本当に合っていますか?(前者の方がよくやるので
tamechop

2018/03/11 11:26

ありがとうございます。サイトの通信事例を見てみました。文字列で引き渡しているようにも見えます。
tamechop

2018/03/11 11:27

補足情報へ追記しています。何かヒントになりそうなノウハウがあれば、是非ご助言お願い致します。
yukapome789

2018/03/11 11:44

追記ありがとうございます。読みました。クエリ文字列でデータ送るのは合ってるみたいですね。HurlでAPI叩いた時に帰ってきたメッセージ内の「oauth_callback」が気になってまして、追記いただいた例の中のURLのクエリには付いてるのに、質問者さんは付けてない理由って何かありますか?
tamechop

2018/03/12 14:56

回答遅くなり申し訳ありません。アドバイス頂いたとおり、oauth_callbackへ適当なURLを入力したところ、リクエストトークンが取得できました。
tamechop

2018/03/12 14:59

認証用URLを入れると、ZAIM側でリクエストトークンを保持したまま認証用URLへリダイレクトしてくれる仕組みのように読めました。一歩進むことができましたので、もう一度API文献を理解しようと思います。rarara様、相談に乗って頂き、誠にありがとうございました。
yukapome789

2018/03/12 15:33

おーよかったです。自己解決ってことで、時間がある時に回答部分に投稿しておいていただけると、teratail的に良いと思いますのでよろしくお願いします。
tamechop

2018/03/14 11:57

了解致しました。java上でのコールを試行した上で記述しておきたいと思います。大変お世話になりました。

まだ回答がついていません

会員登録して回答してみよう

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
87.20%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

OAuth

OAuth(Open Authorization)は、APIを通して保護されたリソース(サードパーティのアプリケーション)へアクセスする為のオープンプロトコルです。

OAuth 2.0

OAuth 2.0(Open Authorization 2.0)は、APIを通して保護されたリソース(サードパーティのアプリケーション)へアクセスする為のオープンプロトコルです。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。