Apitore blog

Apitoreを運営していた元起業家のブログ

Facebook4JでFacebookとOpenID Connectする

はじめに

Facebook APIを使ってSpring Frameworkを利用したウェブサイトの認証をやろうという企画の「番外編」です。Facebook4Jを使って認証することはできましたので、その情報を残しておきます。Spring Securityとの連携については次回の記事で紹介します。 amarec(20160716-110115)

関連記事

手順

基本的に公式サイトが非常にわかりやすいので、そちらを参照すればOKです。Facebook APIを使ったOpenID Connectもサンプルプログラムがあります。 amarec(20160716-110131) バージョンは投稿時点で最新の2.4.6を使います。

    <dependency>
      <groupId>org.facebook4j</groupId>
      <artifactId>facebook4j-core</artifactId>
      <version>2.4.6</version>
    </dependency>

(結局別のやり方をしたので、Facebook4JではSpring Securityとの連携は実現できていないですが)Spring MVCなどのサービスから利用できるFacebook4Jを使ったOpenID Connectについて解説します。まずはウェブサービス上に「FacebookでSignIn」みたいなリンクを作ります。バックエンドの処理は以下のようにします。

  @RequestMapping(value="/signin", method=RequestMethod.GET)
  public ModelAndView signin(
      Principal principal,
      HttpServletRequest request,
      Map<String, Object> model)
  {
    Authentication auth = (Authentication) principal;
    if (auth != null) {
      return new ModelAndView("redirect:/index.html",model);
    }
    Facebook facebook = new FacebookFactory().getInstance();
    facebook.setOAuthAppId(APP_ID, APP_SECRET);
    facebook.setOAuthPermissions(PERMISSIONS);
    String redirect = facebook.getOAuthAuthorizationURL(CALLBACK);
    return new ModelAndView("redirect:"+redirect,new HashMap<String, Object>());
  }

「APP_ID」と「APP_SECRET」は前回の記事でメモしたものを使います。「PERMISSIONS」はFacebook APIを使ってやりたいことを書きます。今回の場合はOpenID Connectで認証できれば良いので、『"public_profile,email"』で良いでしょう。Facebookから他にも情報を引っ張りたい or Facebookで投稿などを操作したいという場合は、こちらに利用できるものが載っています。「CALLBACK」はFacebookで認証を終えた後に戻ってくるところで、前回の記事で『Facebook APIを利用予定のURL』を記入しましたがそれと同じものを入力する必要があります。前回の記事に倣い、ローカルでデバッグするので「http://localhost:xxxx/callback」にしておきます。次にコールバックで受ける部分を書きます。

  @RequestMapping(value="/callback", method=RequestMethod.GET)
  public ModelAndView callback(
      Principal principal,
      HttpServletRequest request,
      Map<String, Object> model,
      @RequestParam(value="code", required=false)
      String code,
      @RequestParam(value="error_reason", required=false)
      String error_reason,
      @RequestParam(value="error", required=false)
      String error,
      @RequestParam(value="error_description", required=false)
      String error_description)
  {
    ApitoreLogFormatter.accessLog(LOG,request);
    if (error != null) {
      String txt = String.format("%s, %s, %s", error, error_reason, error_description);
      model.put("error", error_reason);
      return new ModelAndView("redirect:/login?error",model);
    }
    try {
      Facebook facebook = new FacebookFactory().getInstance();
      facebook.setOAuthAppId(APP_ID, APP_SECRET);
      facebook.setOAuthPermissions(PERMISSIONS);
      facebook.setOAuthCallbackURL(CALLBACK);
      AccessToken token = facebook.getOAuthAccessToken(code);
      facebook.setOAuthAccessToken(token);
      User me = facebook.getMe(new Reading().fields("email","name","first_name","last_name","picture"));
      String username = me.getEmail();
      /* お好きな処理を */
    } catch (FacebookException e) {
      LOG.error("FacebookException",e);
      model.put("error", "error: Facebook Exception");
      return new ModelAndView("redirect:/login?error",model);
    }
    return new ModelAndView("redirect:/index.html",model);
  }

コールバックには「code」「error_reason」「error」「error_description」が返ってくる可能性があります。途中でユーザーが認証をやめた場合は「error~」が返ってきます。認証が完了した場合は「code」が返ってきます。「code」を受け取ったら「code」を使ってFacebook APIのAccessTokenを取得します。実はこのAccessTokenはFacebookでやりたいことによっていくつか種類があります。今回はOpenID Connectが目的なのでこれでOKですが、たとえば「ページ」にアクセスしたい場合は「ページ用のAccessToken」を取得する必要があります。Tokenには寿命も設定されており、場合によっては自分で寿命をのばすリクエストをする必要があります。OpenID Connect以外にやりたいことがある人は、詳しくはFacebook4Jを見てください。 取得したTokenで試しにemailを取得してみましょう。FacebookオブジェクトにTokenをセットして、「getMe()」を呼びます。ここで注意事項ですが、「getMe()」の引数に「Reading」オブジェクトを加えてください。ほしい情報を指定しないと取得できない仕組みになっています。emailを取得する場合は以下のようになります。

User me = facebook.getMe(new Reading().fields("email"));

おわりに

以上でFacebook4Jを使ったOpenID Connectの説明は終了です。Spring Securityと連動する場合は次回に説明する別のやり方をする方がスマートです。