Challenge Engineer Life !

エンジニア人生を楽しみたい!仕事や趣味で学んだ技術的なことを書いていくブログです。

JSFにてTwitterでログイン機能を試してみる

最近遊びでJava EEを使ったアプリを作ろうとしているのですが、世間のWeb系サービスでよく目にするTwitterでログインする機能みたいなの欲しいなぁと。

Twitter4JはOAuth周りもサポートされてるので、仕組みを把握することを兼ねてちょっとお試しで作ってみることに。

とりあえずOAuthの1.0から理解せんと(^^;ということで、以下サイト辺りが図解が丁寧でわかりやすかったです。

OAuthプロトコルの中身をざっくり解説してみるよ ( ꒪⌓꒪) ゆるよろ日記
OAuth 2.0でWebサービスの利用方法はどう変わるか @IT

また、JSPとTwitter4Jでの例は既にあって、そもそもTwitter4Jの公式サイトにあるコード例ページからリンクがあるように、@yusukeさんのGitHubにシンプルな例があったりします。

Twitterアカウントによるサインインのサンプル Twitter4JのGitHub
JavaでTwitterをOAuth認証して使えるTwitter4Jとは @IT

ということで、自分はJSFで試してみることにしました。

できたサンプルはこんな感じ。

とりあえずTwitterでログインボタンを設けたログインページ表示して
f:id:kikutaro777:20140225234532j:plain

ボタンを押すとアプリから認証を求められて
f:id:kikutaro777:20140225234611j:plain

とりあえず自分の普段利用してるアカウントで認証すると…

認証されて、取得されたユーザ名でメッセージ出せてる!
f:id:kikutaro777:20140225234959j:plain

あらかじめログインした状態だと、認証の画面は以下のような感じで、ID/Passの入力が省かれます
f:id:kikutaro777:20140225235041j:plain

世間的には大したことじゃないんだろうけど…なんか嬉し楽し(^^)!

サンプルはJDK8とGlassFish4.0.1b4で作りました。

以下、サンプルで作ったコードです。

ログインページ(twitterLogin.xhtml)

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html">
    <h:head>
        <title>Twitterでログインするお試し</title>
    </h:head>
    <h:body>
        <h:form>
            <h:commandButton value="Twitterでログイン" actionListener="#{twitterLoginBean.twitterLogin()}" />
        </h:form>
    </h:body>
</html>

管理Bean

package com.kikutaro.twitterlogin;

import java.io.IOException;
import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import twitter4j.TwitterException;
import twitter4j.auth.RequestToken;

@Named
@RequestScoped
public class TwitterLoginBean{
    
    @Inject
    private TwitterSession twitterSession;
    
    @PostConstruct
    public void init(){
        if(twitterSession != null){
            twitterSession.getTwitter().setOAuthConsumer("hogehoge", "foofoo");
        }
    }
    
    public void twitterLogin() throws TwitterException, IOException{
        RequestToken requestToken = twitterSession.getTwitter().getOAuthRequestToken("http://localhost:8080/TwitterLogin/faces/callback.xhtml");
        twitterSession.setRequestToken(requestToken);
        ExternalContext externalContet = FacesContext.getCurrentInstance().getExternalContext();
        externalContet.redirect(requestToken.getAuthenticationURL());
    }
}

Session保持用

package com.kikutaro.twitterlogin;

import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
import lombok.Getter;
import lombok.Setter;
import twitter4j.Twitter;
import twitter4j.TwitterFactory;
import twitter4j.auth.RequestToken;

@Named
@SessionScoped
public class TwitterSession implements Serializable{

    @Getter
    private Twitter twitter;
    
    @Getter @Setter
    private RequestToken requestToken;
    
    @PostConstruct
    public void init(){
        twitter = new TwitterFactory().getInstance();
    }
}

Callbackでリダイレクトされるページ

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core">
    <h:head>
        <title>Twitterからリダイレクトされてくる</title>
    </h:head>
    <h:body>
        <f:metadata>
            <f:viewParam name="oauth_token" value="#{callBackBean.oauthToken}" />
            <f:viewParam name="oauth_verifier" value="#{callBackBean.oauthVerifier}" />
            <f:viewAction action="#{callBackBean.preRender()}" />
        </f:metadata>
        
        <h:outputLabel value="#{callBackBean.loginUserName}" />さん、ログインに成功しました。
    </h:body>
</html>

上記ページの管理Bean

package com.kikutaro.twitterlogin;

import java.util.logging.Level;
import java.util.logging.Logger;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
import lombok.Getter;
import lombok.Setter;
import twitter4j.TwitterException;
import twitter4j.User;
import twitter4j.auth.AccessToken;

@Named
@RequestScoped
public class CallBackBean {
    
    @Inject
    private TwitterSession twitterBean;
    
    @Getter @Setter
    private String oauthToken;
    
    @Getter @Setter
    private String oauthVerifier;
    
    @Getter
    private String loginUserName;
    
    public void preRender(){
        try {
            AccessToken accessToken = twitterBean.getTwitter().getOAuthAccessToken(twitterBean.getRequestToken(), oauthVerifier);
            twitterBean.getTwitter().setOAuthAccessToken(accessToken);
            User user = twitterBean.getTwitter().showUser(accessToken.getUserId());
            loginUserName = user.getName();
        } catch (TwitterException ex) {
            Logger.getLogger(CallBackBean.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

パラメータの受け取りは「JSF 2.0のGETパラメータの受け取り」「JSF 2.2ではf:eventのpreRenderViewではなくf:viewActionを使う?」を参考にViewActionを利用してみました。

NameSpaceは「http://xmlns.jcp.org/jsf/core」で動いたので、改修されてるっぽいですね。

作っていて1つハマったのは以下サイトにもあるCallbackでリダイレクトできない現象でした。

TwitterのOAuthでCallbackさせるときの注意点

アプリケーションを登録する際の以下画面でCallback URLを指定する必要があるんですね。
上記ブログにもあるように、適当な値でも大丈夫なので何らか入れることで、ちゃんと情報が取得できるようになりました。

f:id:kikutaro777:20140226001526j:plain

本気で実装するなら、もっと色々工夫しないとダメだなー。と思いつつ、とりあえず、動いたので地味に感動(^^;

にほんブログ村 IT技術ブログへ
にほんブログ村 にほんブログ村 IT技術ブログ Javaへ
にほんブログ村