Twitter botが作りたい。
Twitter4jを使ったTwitterアプリケーションで、ログイン処理を作ってみたいと思います。フレームワークに使ったのはWicketですが、URLとクエリ文字列が分かるのであれば応用ができると思います。
とりあえずこのメモの前提となったバージョンは以下の通りです。
前提となるライブラリ
| ライブラリ名 | バージョン | ||
|---|---|---|---|
| Twitter4j | 2.1.12(SNAP SHOT VERSION) | ||
| Wicket | 1.3.4 (もうかなり古いですが) |
Twitterアプリ側の設定
ユーザーにTwitterログイン処理を行わせるには、登録したツイッターアプリケーションの画面で「アプリケーションの種類」を「ブラウザアプリケーション」にして、コールバックURL欄に、ログインが成功した場合に呼び出されるURLを登録します。このURLが呼び出されたらログインが成功した後の処理を記述するんですね。このコールバックURL欄ですが、自宅の開発マシンなどで開発中とかでもhttp://127.0.0.1:8080/hogehage/verifyなどのプライベートなURLでもコールバックしてくれます。すごいですねぇ。
ユーザーにログインを促す
まずは、ユーザーのログインを促す処理です。OpenIDのようにID欄もコンシューマーを選択または入力するフィールドも必要ありません。リンクで十分です。押された処理として、Twitterアプリケーションのコンシューマーキーとコンシューマーキー・シークレットを使ってTwitterのログインページにリダイレクトします。
MainPage.java (例外処理は省いています)
public class MainPage extends WebPage{
private Link _loginasuser = new Link("loginasuser", new Model("")){
public void onClick() {
String consumerkey = ... // DBとかに保存したコンシューマキーを取得
String consumersecret = ... // DBとかに保存したコンシューマシークレットを取得
Twitter twitter = new twitter4j.TwitterFactory().getInstance();
twitter.setOAuthConsumer(consumerkey, consumersecret);
RequestToken reqtoken = twitter.getOAuthRequestToken();
// Twitterのログインページにリダイレクト
setResponsePage(new RedirectPage(reqtoken.getAuthorizationURL()));
}
};
}
コールバックURL側の処理
Twitter側でのログインが成功するとコールバックURL欄に記入したURLが呼び出されるため、WicketのナイスURLを使って検証用のページをマウントします。
MyApp.java
public class MyApp extends WebApplication {
protected void init() {
... 省略
// http://hogehate.com/veryfytwitter?oauth_token=XXXX&oauth_verifier=YYYY
mountBookmarkablePage("veryfytwitter", VerifyAsUserPage.class);
}
}
つぎにログインが成功した場合の処理です。コールバックURL欄に記載したURLにクエリ文字列としてoauth_token=xxx&oauth_verifier=yyyと言った情報が付加されてきます。この情報を使ってログインしたユーザーのアクセストークンを取得します。取得したアクセストークンの情報はDBやセッションなどに保存して、次からはコンシューマーキーとこのアクセストークンを使ってユーザーに成り代わってTwitterにアクセス可能です。
VerifyAsUserPage.java (例外処理は省いています)
public class VerifyAsUserPage extends AbstractPage{
public VerifyAsUserPage(PageParameters params){
// request parameters
//oauth_token = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
//oauth_verifier = YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
String oauthtoken = params.getString("oauth_token");
String oauthverifier = params.getString("oauth_verifier");
if(oauthtoken == null || oauthverifier == null){
// エラーだ、エラーいこっちゃ、エラーページにリダイレクト
setResponsePage(new RedirectPage("..."));
return;
}
String consumerkey = ... // DBとかに保存したTwitterアプリのコンシューマキーを取得
String consumersecret = ... // DBとかに保存したTwitterアプリのコンシューマシークレットを取得
Twitter twitter = new twitter4j.TwitterFactory().getInstance();
twitter.setOAuthConsumer(consumerkey, consumersecret);
AccessToken atoken = twitter.getOAuthAccessToken(oauthtoken, oauthverifier);
~~~~~~~~~~~~~~~~~~~~~~~~~~~
↑ ↑
String screenname = atoken.getScreenName();
String acctoken = atoken.getToken();
String accsecret = atoken.getTokenSecret();
String sql = "INSERT INTO USER VALUES(SCREENNAME='" + screenname
+ "', ACC_TOKEN='" + acctoken
+ ", ACC_SECRET='" + accsecret + ")";
// 変数sqlを使ってユーザーの情報を保存する処理とか...
// ログイン後のページに*リダイレクト*する。
setResponsePage(new RedirectPage("..."));
}
}
処理をした後は、成功しても失敗しても結果ページに必ずリダイレクトします。しないとうっかりユーザーが認証後にF5キーなどを押した場合にこのコールバック処理が再リクエストされてしまいます。その場合、既にoauth_tokenとoauth_verifierは無効になっていますので、Twitter#getOAuthAccessToken(oauthtoken, oauthverifier);の処理でエラーになってしまいます。「あれ?さっきログイン成功したのに何で?」ってなってしまいます。
また再リクエストされる構造にしておくということは、Twitterとの接続が再度行われるので、悪意の第3者が例えばF5キーを連打するようなDos攻撃をしたとき、アプリ側の負荷は対応できたとしても、Twitterとの認証が多数発生してしまい、TwitterAPI制限に引っかかってしまいます。なので、リダイレクトが必要です。
ユーザーとしてつぶやく
あとは、「つぶやく」ボタンを作ったりして、コールバックURL処理の中で保存したアクセストークンを使って、ユーザーに成り代わりTwitterにアクセスします。
TwitterPage.java (例外処理は省いています)
public class TwitterPage extends WebPage{
private Button _tweet = new Button("tweet"){
public void onSubmit() {
String consumerkey = ... // DBとかに保存したTwitterアプリのコンシューマキーを取得
String consumersecret = ... // DBとかに保存したTwitterアプリのコンシューマシークレットを取得
String acctoken = ... // DBとかに保存したユーザーのアクセストークンを取得
String accsecret = ... // DBとかに保存したユーザーのアクセストークン・シークレットを取得
// Twitterインスタンスを取得する。
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setOAuthConsumerKey(consumerkey)
.setOAuthConsumerSecret(consumersecret)
.setOAuthAccessToken(acctoken)
.setOAuthAccessTokenSecret(accsecret);
TwitterFactory tf = new TwitterFactory(cb.build());
Twitter tw = tf.getInstance();
// ユーザーになりかわり呟く
tw.updateStatus("はろー!");
}
}
}
