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

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

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

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

OAuth 2.0

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

Java

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

Q&A

解決済

1回答

4199閲覧

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

tamechop

総合スコア6

OAuth

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

OAuth 2.0

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

Java

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

1グッド

2クリップ

投稿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

1//ネット上で有識者が公開して下さっていたソースコードを流用しております。 2import java.io.BufferedReader; 3import java.io.InputStreamReader; 4import java.io.UnsupportedEncodingException; 5import java.net.HttpURLConnection; 6import java.net.URL; 7import java.net.URLEncoder; 8import java.util.Map.Entry; 9import java.util.SortedMap; 10import java.util.TreeMap; 11import javax.crypto.Mac; 12import javax.crypto.spec.SecretKeySpec; 13import sun.misc.BASE64Encoder; 14 15public class TestZaim { 16 17 public static void main(String[] args) throws Exception { 18 // OAuthにおいて利用する変数宣言 19 String consumerkey = "略"; 20 String consumerSecret = "略"; 21 String oauthToken = ""; // リクエストトークン取得時は利用しない 22 String oauthTokenSecret = ""; // リクエストトークン取得時は利用しない 23 String method = "POST"; 24 String urlStr = "https://api.zaim.net/v2/auth/request"; 25 26 // OAuthにおいて利用する共通パラメーター 27 // パラメーターはソートする必要があるためSortedMapを利用 28 SortedMap<String, String> params = new TreeMap<String, String>(); 29 params.put("oauth_consumer_key", consumerkey); 30 params.put("oauth_signature_method", "HMAC-SHA1"); 31 params.put("oauth_timestamp", String.valueOf(getUnixTime())); 32 params.put("oauth_nonce", String.valueOf(Math.random())); 33 params.put("oauth_version", "1.0"); 34 // params.put("oauth_token", oauthToken); // リクエストトークン取得時は利用しない 35 36 { 37 /* 38 * 署名(oauth_signature)の生成 39 */ 40 // パラメーターを連結する 41 String paramStr = ""; 42 for (Entry<String, String> param : params.entrySet()) { 43 paramStr += "&" + param.getKey() + "=" + param.getValue(); 44 } 45 paramStr = paramStr.substring(1); 46 47 // 署名対象テキスト(signature base string)の作成 48 String text = method + "&" + urlEncode(urlStr) + "&" 49 + urlEncode(paramStr); 50 51 // 署名キーの作成 52 String key = urlEncode(consumerSecret) + "&" 53 + urlEncode(oauthTokenSecret); 54 55 // HMAC-SHA1で署名を生成 56 SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), 57 "HmacSHA1"); 58 Mac mac = Mac.getInstance(signingKey.getAlgorithm()); 59 mac.init(signingKey); 60 byte[] rawHmac = mac.doFinal(text.getBytes()); 61 String signature = new BASE64Encoder().encode(rawHmac); 62 63 // 署名をパラメータに追加 64 params.put("oauth_signature", signature); 65 } 66 67 // Authorizationヘッダの作成 68 String paramStr = ""; 69 for (Entry<String, String> param : params.entrySet()) { 70 paramStr += ", " + param.getKey() + "=\"" 71 + urlEncode(param.getValue()) + "\""; 72 } 73 paramStr = paramStr.substring(2); 74 String authorizationHeader = "OAuth " + paramStr; 75 76 // APIにアクセス 77 URL url = new URL(urlStr); 78 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 79 connection.setRequestMethod(method); 80 connection.setRequestProperty("Authorization", authorizationHeader); 81 connection.connect(); 82 BufferedReader reader = new BufferedReader(new InputStreamReader( 83 connection.getInputStream())); 84 String response; 85 while ((response = reader.readLine()) != null) { 86 System.out.println(response); 87 } 88 } 89 90 private static int getUnixTime() { 91 return (int) (System.currentTimeMillis() / 1000L); 92 } 93 94 private static String urlEncode(String string) { 95 try { 96 return URLEncoder.encode(string, "UTF-8"); 97 } catch (UnsupportedEncodingException e) { 98 throw new RuntimeException(e); 99 } 100 }

試したこと

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>
A-pZ👍を押しています

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

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上でのコールを試行した上で記述しておきたいと思います。大変お世話になりました。
guest

回答1

0

自己解決

【課題】 javaでRequestTokenを取得できない。
【対応】 oauth_callbackが設定されていなかったため、ボディへ追加し、
RequestToken取得URL(API)をコールした。
https://www.hurl.it/ ※上記要因であることを左記ページ様にて確認
【結果】 oauth_token, oauth_token_secret, oauth_callback_confirmedを取得できた。
oauth_token=xxxx&oauth_token_secret=xxxx&oauth_callback_confirmed=true
【成果物】
最終的には以下内容で、JavaからAccessToken認証URLを開くまで、確認できました。
★scribejavaを利用

--Java
OAuthConsumer mConsumer = new CommonsHttpOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);
OAuthProvider mProvider = new CommonsHttpOAuthProvider(REQUEST_TOKEN_URL, ACCESS_TOKEN_URL, AUTHORIZE_URL);
String authUrl = mProvider.retrieveRequestToken(mConsumer, CALLBACK);
// ブラウザに認証ページを開かせる
Desktop desktop = Desktop.getDesktop();
String uriString = authUrl;
try {
URI uri = new URI(uriString);
desktop.browse(uri);
} catch (URISyntaxException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

--POM
<dependency>
<groupId>com.github.scribejava</groupId>
<artifactId>scribejava-apis</artifactId>
<version>5.3.0</version>
</dependency>
<dependency>
<groupId>com.github.scribejava</groupId>
<artifactId>scribejava-core</artifactId>
<version>5.3.0</version>
</dependency>

投稿2018/03/17 10:10

tamechop

総合スコア6

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問