【Java】Play framework 2.7でTwitter APIを使ってOAuth認証をしてみよう!【Twitter4J】

今回はこのような質問をいただきました。

OAuth認証について教えて!
OAuth認証って慣れるまで結構難しいんですよね。
そこで今回はこちらの質問について解説していきます!
- Play Framework:2.7.3
- OS : macOS Catalina バージョン 10.15
- Java : 1.8.0_131
- sbt : 0.13.16
- IDE : IntelliJ IDEA Ultimate 2019.2
OAuth認証を行ってユーザ情報を取得してみよう!
今回はOAuth認証を行ってログインし、ユーザ情報を取得したいと思います。
Consumer Key, Consumer Secretの取得
Twitter Developer Platformに登録して取得します。
私は以前、取得したものを使用します。
取得方法も大きく変わって、今では簡単に取得はできなくなってしまったみたい。
解説しているページはいろいろあると思うので、今回は省略します。
Twitter4Jのインポート
build.sbtに1行追加してTwitter4Jをインポートします。
libraryDependencies += "org.twitter4j" % "twitter4j-core" % "4.0.7"
Consumer Key, Consumer Secretの設定
先ほど取得してもらったConsumer KeyとConsumer SecretをPlay側に設定します。
confディレクトリの中にtwitter4j.propertiesというファイルを作成して、以下のように設定します。
XXXXは自分のConsumer KeyとConsumer Secretに置き換えてください。
oauth.consumerKey=XXXXXXXXXXXXXXXXXXXX
oauth.consumerSecret=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
TwitterServiceを定義
Twitter4Jのメソッドはすべてthrowsが定義されているので(たぶん)ラップしておきます。
とりあえず使いそうなメソッドをラップしておきました。
package services;
import exceptions.ForbiddenException;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.User;
import twitter4j.auth.AccessToken;
import twitter4j.auth.RequestToken;
import javax.inject.Singleton;
import java.util.Optional;
/**
* TwitterService
*/
@Singleton
public class TwitterService {
private static Twitter twitter = TwitterFactory.getSingleton();
/**
* リクエストトークンを取得する
* @return RequestToken
*/
public static RequestToken getOAuthRequestToken() {
try {
return twitter.getOAuthRequestToken();
} catch (TwitterException e) {
throw new ForbiddenException();
}
}
/**
* アクセストークンを取得する
* @param requestToken リクエストトークン
* @param oauthVerifier 認証コード
* @return AccessToken
*/
public static AccessToken getOAuthAccessToken(RequestToken requestToken, String oauthVerifier) {
try {
return twitter.getOAuthAccessToken(requestToken, oauthVerifier);
} catch (TwitterException e) {
throw new ForbiddenException();
}
}
/**
* アクセストークンを登録する
* @param accessToken アクセストークン
*/
public static void setOAuthAccessToken(AccessToken accessToken) {
twitter.setOAuthAccessToken(accessToken);
}
/**
* ユーザー情報を取得する
* @return User
*/
public static User getUser() {
try {
return twitter.verifyCredentials();
} catch (TwitterException e) {
throw new ForbiddenException();
}
}
/**
* ユーザー名を取得する
* @return Optional<String>
*/
public static Optional<String> getUserNameOptional() {
String name = null;
try {
name = getUser().getName();
} catch (Exception e) {
// none
}
return Optional.ofNullable(name);
}
/**
* ログイン済みかどうか
* @return boolean
*/
public static boolean isLogin() {
return getUserNameOptional().isPresent();
}
}
Controllerの実装
TwitterServiceを使ってログイン部分のControllerを実装します。
login()にアクセスするとTwitterの認証画面にリダイレクトし、認証後にauth()にリダイレクトされます。
ログイン時に発行するリクエストトークンは、リクエストごとにインスタンスを生成して発行する必要がありました。
生成しなかった場合、認証に失敗したりキャンセルしたりした場合に再認証が行えなくなってしまいました。
そのため、リクエストごとにインスタンスを生成し、そのインスタンスをキャッシュに入れて認証後に使用しています。
少し複雑になってしまいましたが、他の方法が思いつきませんでした。
一度認証してアクセストークンを発行してしまえば、リクエストトークンは不要なので、アクセストークンはTwitterServiceのインスタンスにセットします。
これによりTwitterServiceからTwitter APIを使用できるようになります。

package controllers;
import org.apache.commons.lang3.StringUtils;
import play.mvc.Controller;
import play.mvc.Http;
import play.mvc.Result;
import services.TwitterService;
import twitter4j.Twitter;
import twitter4j.TwitterFactory;
import twitter4j.auth.AccessToken;
import twitter4j.auth.RequestToken;
import utils.CacheUtils;
import java.util.Optional;
/**
* ツイッター連携
*/
public class TwitterController extends Controller {
/**
* ログイン画面
*/
public Result login(Http.Request request) {
// ログイン済みの場合
if (TwitterService.isLogin()) {
return redirect(routes.HomeController.index());
}
try {
// 同じインスタンスではリクエストトークンをリフレッシュできないため、認証用のインスタンスを取得
Twitter twitter = new TwitterFactory().getInstance();
RequestToken requestToken = twitter.getOAuthRequestToken();
String token = requestToken.getToken();
String tokenSecret = requestToken.getTokenSecret();
// キャッシュにTwitterインスタンスをセット(キーはリクエストトークン)
CacheUtils.set(token, twitter, "60s");
return redirect(requestToken.getAuthorizationURL())
.addingToSession(request, "requestToken", token)
.addingToSession(request, "requestTokenSecret", tokenSecret);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 認証画面
*/
public Result auth(Http.Request request) {
// ログイン済みの場合
if (TwitterService.isLogin()) {
return redirect(routes.HomeController.index());
}
// 認証失敗時のパラメータ
String denied = request.getQueryString("denied");
// 認証成功時のパラメータ
Optional<String> requestTokenOpt = request.session().getOptional("requestToken");
Optional<String> requestTokenSecretOpt = request.session().getOptional("requestTokenSecret");
// 認証成功
if (StringUtils.isBlank(denied) && requestTokenOpt.isPresent() && requestTokenSecretOpt.isPresent()) {
try {
String token = requestTokenOpt.get();
String tokenSecret = requestTokenSecretOpt.get();
// ログイン画面でキャッシュにセットしたTwitterインスタンスを取得
Optional<Twitter> twitterOptional = CacheUtils.getOptional(token);
if (!twitterOptional.isPresent()) {
return redirect(routes.TwitterController.login());
}
Twitter twitter = twitterOptional.get();
// リクエストトークンの発行
RequestToken requestToken = new RequestToken(token, tokenSecret);
String verifier = request.getQueryString("oauth_verifier");
// アクセストークンの発行
AccessToken accessToken = twitter.getOAuthAccessToken(requestToken, verifier);
// TwitterServiceのインスタンスにアクセストークンをセットする
TwitterService.setOAuthAccessToken(accessToken);
return redirect(routes.HomeController.index());
} catch (Exception e) {
e.printStackTrace();
return redirect(routes.TwitterController.login());
}
} else {
return redirect(routes.TwitterController.login());
}
}
}
ユーザ情報の取得
あとはユーザ情報を取得するだけです。
取得してviewで表示します。
package controllers;
import filters.UserAuth;
import play.mvc.Controller;
import play.mvc.Http;
import play.mvc.Result;
import play.mvc.Security;
import services.TwitterService;
import views.html.index;
/**
* ホーム
*/
@Security.Authenticated(UserAuth.class)
public class HomeController extends Controller {
/**
* トップ
* @return
*/
public Result index(Http.Request request) {
return ok(index.render(TwitterService.getUser()));
}
}
@import twitter4j.User
@(user: User)
<h3>@user.getName</h3>
<h3>@user.getScreenName</h3>
<h3>@user.getFriendsCount</h3>
<h3>@user.getFollowersCount</h3>
あとがき
以前、個人的に触ったときはライブラリを使わなかったのですが、今回はTwitter4Jというライブラリを使ってみました。
やっぱりライブラリを使うと楽ですね!
シンプルな作りになっているのでわかりやすかったです。
普段Twitterを使っているのでTwitter APIを使うのは楽しいですね!