前人未踏の領域へ Androidアプリ開発編

Androidアプリ開発に関する調査メモ置き場。古い記事にはアプリ以外も含まれます。

サーバーサイドJAVAでFacebookにログイン

自分のWebサイトからFacebookでログイン出来るようにしたい、サーバーからFacebookに対していろいろやりたい。そんな人の為に。

参考 https://developers.facebook.com/docs/authentication/server-side/

ステップ

  1. ユーザーをOAuthダイアログにリダイレクト
  2. ユーザーによるアプリケーション認証
  3. ユーザーがリダイレクトによりアプリに戻ってくる
  4. コードからアクセストークンに変換
  5. アクセストークンを使ってグラフAPIにリクエストを送信

0.アプリケーションの登録

自分のサイトのURLをFacebookに登録する。まずはここから。必須作業です。

1.ユーザーをOAuthダイアログにリダイレクト

ログイン画面を作成し、そこから以下のURL、パラメータでアクセスさせる。またはいったん自身のサーブレットなどにリクエストを飛ばし、そこからリダイレクトさせる。

https://www.facebook.com/dialog/oauth?
    client_id=YOUR_APP_ID
   &redirect_uri=YOUR_REDIRECT_URI
   &scope=COMMA_SEPARATED_LIST_OF_PERMISSION_NAMES
   &state=SOME_ARBITRARY_BUT_UNIQUE_STRING

scopeはオプション。ただしアプリケーションに特定の追加権限を必要とする場合は記述が必要。

セキュリティ観点から、リダイレクトURIはアプリケーション設定で設定したドメインと同じである必要がある。

stateパラメータはリクエストを認証するためにサーバー側で作成する任意の文字列。この値はFacebookから自身のドメインにリダイレクト際にそのままパラメータとし戻ってくる。認証開始時に渡した値と一致しているかを確認することでログインリクエストが正しいものであることを確認する、CSRF対策として使用するべきである。Javaでランダムな文字列を生成したければRandomStringUtilsを使えば良い。

private String getRandomString(){
   return RandomStringUtils.randomAlphanumerics(15);
}

これで15文字のアルファベットか数値を返却してくれるようになるので、セッションにでも入れて戻りをチェックすれば良いだろう。

2.ユーザーによるアプリケーション認証

ここではFacebookからユーザーに対してアプリケーションを認証するかどうかの確認画面が表示されている。ここでユーザーがFacebookでログインすることを承認すると1で設定したredirect_uriに対してパラメータが付与された状態でリダイレクトされてくる。

3. ユーザーがリダイレクトによりアプリに戻ってくる

Facebookよりリダイレクトされたリクエストは以下のようになっている。

YOUR_REDIRECT_URI?
    state=YOUR_STATE_VALUE
   &code={FACEBOOKにより生成されたコード}

エラーがあればこんな感じになる。一応リダイレクト先に戻ってはくるが、codeパラメータがない。

YOUR_REDIRECT_URI?
    error_reason=user_denied
   &error=access_denied
   &error_description=The+user+denied+your+request.
   &state=YOUR_STATE_VALUE

4.codeからアクセストークンに変換

ユーザーに承認されcodeが取得できたらそのコードを元にしてFacebookからアクセストークンを取得するためのリクエストを送信する。

https://graph.facebook.com/oauth/access_token?
    client_id=YOUR_APP_ID
   &redirect_uri=YOUR_REDIRECT_URI
   &client_secret=YOUR_APP_SECRET
   &code=CODE_GENERATED_BY_FACEBOOK

client_idとcodeは前述の通り。client_secretはアプリケーションを登録した際に発行される秘密のコードだ。このリクエストを送信すると以下の戻りが得られる。またここでのredirect_uriFacebookからリダイレクトしてもらうためのものではなく一連のやり取りを表すものらしく、1で設定したものと同じにしないとエラーとなった。
上記のリクエストを送信すると今度はリダイレクトではなく以下のようなレスポンスが帰ってくる。

access_token=USER_ACESS_TOKEN&expires=NUMBER_OF_SECONDS_UNTIL_TOKEN_EXPIRES

リクエスト送信サンプルは以下の通り

        //アクセストークン取得
	private String getAccessToken(String code) {
		String url = "https://graph.facebook.com/oauth/access_token?"
				+ "client_id=" + {App ID/API Key} + "&redirect_uri="
				+ {1.で指定したのと同じuri}
				+ "&client_secret=" + {アプリの秘訣} + "&code="
				+ {受け取ったcode};
		HttpClient client = new HttpClient();
		HttpMethod method = new GetMethod(url);
		try {
			int status = client.executeMethod(method);
			if (status == 200) {
				String responseBody = method.getResponseBodyAsString();
				String[] data = responseBody.split("&");
				for (String string : data) {
					String[] p = string.split("=");
					if (p.length == 2 && p[0].equals("access_token")) {
						return p[1];
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			method.releaseConnection();
		}
		return null;
	}

5.アクセストークンを使ってグラフAPIにリクエストを送信

あとは取得したAccessTokenを使ってGraphAPIにリクエストを投げて権限に応じて操作を行えばよい。とりあえずサンプルとしてUser情報をリクエストして結果をBeanにつめるサンプルを掲載しておく。

        //Facebookユーザー情報を得る。
	private FacebookUser getFbUser(String accessToken) {
		String url = https://graph.facebook.com/me?access_token="
				+ accessToken;
		HttpClient client = new HttpClient();
		HttpMethod method = new GetMethod(url);
		try {
			int status = client.executeMethod(method);
			if (status == 200) {
				String responseBody = method.getResponseBodyAsString();
				JSONObject jsonObject = JSONObject.fromObject(responseBody);
				FacebookUser user = (FacebookUser)JSONObject.toBean(jsonObject, FacebookUser.class);
				return user;
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			method.releaseConnection();
		}
		return null;
	}

//使用したBean ここでは省略するがSetterは必須。そしてJSONObject.toBeanを使うとアンダーバーはSetterでもそのまま使用しないと値がセットされないようなので注意。つまりはsetFirst_name(String s)のようになる。
public class FacebookUser {
	public int id;
	public String name;
	public String first_name;
	public String last_name;
	public String link;
	public String username;
	public String quotes;
	public String gender;
	public String timezone;
	public String locale;
	public String verified;
	public Date updated_time;
}

結論

今回は全てサーバーサイドで行ったが、要はAccessTokenを取得するのがポイントなので、AccessTokenを得るところまではJavaScriptでやるのも良いと思う。そして世の中の誰かが絶対接続用ライブラリ作ってるからそっち探した方がいいよ、きっと。