読者です 読者をやめる 読者になる 読者になる

the industrial

都内で働くITエンジニアの日記

Playframework/ScalaとTwitter4jでOAuthログインするサンプル

program

というのを作ってみたんだ。

ソースはこちらに置いてます

Twitter4j.jarの取得

build.sbt
libraryDependencies ++= Seq(
   cache
  ,"org.twitter4j" % "twitter4j-core" % "4.0.2"
)

まずはTwitter4j.jarを取得するべく、build.sbtのlibraryDependenciesをこのように修正。

cacheはログイン後のTwitterのユーザー情報を保持するオブジェクトをもちまわすだけの為に使う想定。

twitter4j.propertiesにコンシューマーキーを設定

conf/twitter4j.properties
oauth.consumerKey={あなたのTwitterAppのコンシューマーキー}
oauth.consumerSecret={あなたのTwitterAppのコンシューマーシークレット}

コンシューマーキーは、ここで事前に取得する必要がある(あたりまえだけど)

TwitterController

今回独自にこの様なControllerを作成。

app/controller/TwitterController.scala
package controllers

import play.api._
import play.api.mvc._
import play.api.Play.current

import play.api.cache._

import twitter4j._
import twitter4j.auth._

/**
 * ツイッターログインコントローラ
 */
object TwitterController extends Controller {

  /**
   * Twitterへログインする
   */
  def twitterLogin = Action { implicit request =>

    // Twitterオブジェクトの初期化
    val twitter: Twitter = (new TwitterFactory()).getInstance()

    // RequestTokenの取得
    val requestToken: RequestToken = twitter.getOAuthRequestToken("http://" + request.host + "/twitterOAuthCallback")

    // TwitterとRequestTokenのオブジェクトをCacheに格納(2分有効)
    Cache.set("twitter", twitter, 120)
    Cache.set("requestToken", requestToken, 120)

    // Twitterのログイン画面にリダイレクト
    Redirect(requestToken.getAuthorizationURL())
  }

  /**
   * TwitterからのCallBack処理
   */
  def twitterOAuthCallback = Action { implicit request =>
    // 承認可否を精査(deniedがあったら承認キャンセル)
    request.queryString.get("denied") match {

      // Twitterのアプリケーション承認キャンセル時
      case Some(denied) => Redirect(routes.TwitterController.twitterLogout)

      // Twitterのアプリケーション承認時
      case _ => {

        // TwitterのオブジェクトをCacheから取得
        val getTwitter     : Option[Twitter] = Cache.getAs[Twitter]("twitter")

        // 取得できない場合はトップ画面へ
        getTwitter match {
          case Some(twitter) => {

            // RequestTokenのオブジェクトをCacheから取得
            val getRequestToken: Option[RequestToken] = Cache.getAs[RequestToken]("requestToken")

            // 取得できない場合はトップ画面へ
            getRequestToken match {
              case Some(requestToken) => {

                // AuthTokenを取得する
                var authToken   : String = request.queryString.get("oauth_token").get.head
                var authVerifier: String = request.queryString.get("oauth_verifier").get.head

                // AccessTokenを取得する
                // val accessToken: AccessToken = twitter.getOAuthAccessToken(requestToken, authVerifier)
                twitter.getOAuthAccessToken(requestToken, authVerifier)

                // AccessTokenを取得する場合
                // val accessToken: AccessToken = twitter.getOAuthAccessToken(requestToken, authVerifier)
                // val accessTokenSt: String = accessToken.getToken
                // val accessTokenSecretSt: String = accessToken.getTokenSecret

                // Twitterオブジェクトの認証
                twitter.verifyCredentials()

                // TwitterのUserオブジェクトを取得
                var user: User = twitter.showUser(twitter.getId())

                // Cacheに設定(3日間有効)
                Cache.set("twitter_user", user, 4320)

                // Cacheから削除
                Cache.remove("twitter")
                Cache.remove("requestToken")

              }
              case _ =>
            }
          }
          case _ =>
        }

        // リターン
        Redirect(routes.Application.index)
      }
    }
  }

  /** 
   * ログアウト処理
   */
  def twitterLogout = Action { implicit request =>

    // Cacheから削除
    Cache.remove("twitter_user")
    
    // リターン
    Redirect(routes.Application.index)
  }
}

最後は取得したtwitter4j.UserをCacheに入れて、Application.scalaで使う感じ。

まあDB永続化とかしてもいいのかな?

conf/routes
# Home page
GET     /                           controllers.Application.index

# Twitter
GET     /twitterLogin                                 controllers.TwitterController.twitterLogin
GET     /twitterOAuthCallback                         controllers.TwitterController.twitterOAuthCallback
GET     /twitterLogout                                controllers.TwitterController.twitterLogout

そしてRoutesの設定はこんな感じ。

Application Controllerの設定

app/controllers/Application.scala
  /** index画面起動 */
  def index = Action {
    // CacheからTwitter4j.Userオブジェクトを取得し、index画面を機動
    Ok(views.html.index(Cache.getAs[User]("twitter_user")))
  }

Cacheからtwitter4j.Userオブジェクトを取得している以外特別な事はなし。

index.scala.html

app/views/index.scala.html
  @twitterUser match {
    case Some(user) => {
        &#64;@user.getScreenName<br/>
        <img src="@user.getProfileImageURL"/><br/>
        <a href="/twitterLogout">Logout</a>
    }
    case _ => {
      <a href="/twitterLogin">Login</a>
    }
  }

ページでは引数で受け取った@twitterUserが存在する場合、@twitterUserからScreenNameの表示と、アイコン画像URLからアイコンを表示するという処理。

ログイン前→ログイン後

f:id:omiend:20141030145651p:plainf:id:omiend:20141030145648p:plain

ご指摘の点などあったらよろしくです

AccessTokenは呟く時に使うんだろうけど、アプリ上ではログインとかに使えばいいのかな