気楽なソフト工房

プログラミングについていろいろな記事を書いています。



mykonos2008

Author:mykonos2008
システムエンジニアとして働いている30代の会社員です。
仕事や趣味でプログラムを書いている方の役に立つ記事を書いていきたいと思っています。
ご意見、ご感想はこちらまで
If you are an english speaker,Please visit my english blog.

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
Google Data APIなどユーザ認証が必要なWeb APIを利用してマッシュアップサイトを作成する場合、
ユーザの認証情報をどのように扱うのかはとても気がかりな問題になります。

Google Data APIの場合、Googleアカウントを扱うことになりますが、GoogleアカウントはGmailなどいろいろな
種類のサービスを利用することが出来るため、その認証情報(ユーザID、パスワード)は非常に厳重に扱われるべき情報になります。

このようなケースにおいて、マッシュアップサイトの運営者が直接、認証情報を扱わずにその先のサービス(Google Data APIなど)
を利用できるようにする標準プロトコルとしてOAUTH(オース)というものが開発されました。

今回、このOAUTHプロトコルを使用してGoogle Calendar APIにアクセスし、カレンダー情報を取得するコードを書いてみました。
開発環境には前回に引き続き、Google App EngineのJava版を使用しました。

ドメインの登録
GoogleのOAUTHを使用するためには、サービスを利用するマッシュアップサイトのドメインをあらかじめ登録して
おく必要があります。

ドメインの登録

画面の指示に従って、ドメインを登録すると、最後のページに「OAuth Consumer Key」と「OAuth Consumer Secret」と
いう項目が表示されます。この2つの項目の値は認証処理を行う際に使用しますので、メモをしておいてください。

ライブラリのダウンロード
Google Data API(Google Calendar APIはGoogle Data APIの一部)はAPIを扱うためのクライアントライブラリを
提供しています。以下のURLから、Java版のクライアントライブラリをダウンロードできます。

Java版クライアントライブラリ

ダウンロードしてファイルを解凍して、以下のjarファイルをプロジェクトにインポートします。

gdata-base-1.0.jar
gdata-calendar-2.0.jar
gdata-calendar-meta-2.0.jar
gdata-client-1.0.jar
gdata-client-meta-1.0.jar
gdata-core-1.0.jar

認証処理
コードは認証処理を行うAuthServletとカレンダー取得を行うCalendarServletに分けました。

以下のコードはローカルの開発環境では正常に動作をしています。
しかし、Google App Engineにインストールすると、カレンダーの取得時に
「com.google.gdata.util.ServiceException: Invalid redirected-to URL - null」というエラーが
発生します。

Google App EngineやGoogle Data APIに関してはWeb上のリソースも少なく、
原因解決に苦戦しています。同じような現象に直面している方がいたら
情報をいただけるとうれしいです。

認証部分についてもこれが確実にあっていると確信できていないので、間違いがあれば指摘してください。

以下のURLにある図をみながら以下のソースを見ていただくと分かりやすいかもしれません。

Account Authentication API

public class AuthServlet extends HttpServlet {

  public void doGet(HttpServletRequest req, HttpServletResponse resp)
  throws IOException {
    
    String pathInfo = req.getPathInfo();
    
    if(pathInfo.equals("/login"))
    {
      login(req,resp);
    }
    else if(pathInfo.equals("/authsub"))
    {
      saveAccessToken(req,resp);
    }
  }

  private void login(HttpServletRequest req, HttpServletResponse resp)
  {
    try
    {
      //パラメータを設定する
      GoogleOAuthParameters params = new GoogleOAuthParameters();
      params.setOAuthConsumerKey(ドメイン登録時に取得したOAuth Consumer Key);
      params.setOAuthSignatureMethod("HMAC-SHA1");
      params.setScope("http://www.google.com/calendar/feeds/");
      params.setOAuthConsumerSecret(ドメイン登録時に取得したOAuth Consumer Secret);
      
      //Step1~2:リクエストトークンを取得する
      GoogleOAuthHelper helper = new GoogleOAuthHelper(new OAuthHmacSha1Signer());
      helper.getUnauthorizedRequestToken(params);
      
      //以下、Step3~6
      
      //TokenSecretを取得する
      String tokenSecret = params.getOAuthTokenSecret();
      
      //開発環境の場合
      if(req.getServerName().equals("localhost"))
      {
        params.setOAuthCallback(String.format("http://localhost:8080/auth/authsub?secret=%s",
            URLEncoder.encode(tokenSecret, "UTF-8")));
      }
      //App Engineの場合
      else
      {
        params.setOAuthCallback(String.format("http://riamediator.appspot.com/auth/authsub?secret=%s",
            URLEncoder.encode(tokenSecret, "UTF-8")));
      }      
    
      //認証用URLを作成する
      String authUrl = helper.createUserAuthorizationUrl(params);
      
      //認証ページにリダイレクトする
      resp.sendRedirect(authUrl);
    }
    catch(Exception ex)
    {
      resp.setContentType("text/html;charset=UTF-8");
      
      try
      {
        resp.getWriter().println(String.format("<html><body>%s</body></html>",ex.toString()));
      }
      catch(Exception e){}
    }  
  }

  //アクセス用トークンを取得する(Step7~8に該当)
 //ユーザが認証情報を入力後、リダイレクトされてコールされる
  private void saveAccessToken(HttpServletRequest req, HttpServletResponse resp)
  {
    try
    {    
      //パラメータを設定する
      GoogleOAuthParameters params = new GoogleOAuthParameters();
      params.setOAuthConsumerKey(ドメイン登録時に取得したOAuth Consumer Key);
      params.setOAuthSignatureMethod("HMAC-SHA1");
      params.setOAuthConsumerSecret(ドメイン登録時に取得したOAuth Consumer Secret);
      params.setOAuthTokenSecret(req.getParameter("secret"));
      
      //アクセス用トークンを取得する
      GoogleOAuthHelper helper = new GoogleOAuthHelper(new OAuthHmacSha1Signer());
      helper.getAccessToken(req.getQueryString(),params);
      
      //トークンをクッキーに設定する
      Cookie cookie = new Cookie("access_token",params.getOAuthToken());
      cookie.setPath("/");
      cookie.setMaxAge(60 * 60 * 24 * 14);  //有効期限を2週間に設定      
      resp.addCookie(cookie);
      
      cookie = new Cookie("token_secret",params.getOAuthTokenSecret());
      cookie.setPath("/");
      cookie.setMaxAge(60 * 60 * 24 * 14);  //有効期限を2週間に設定      
      resp.addCookie(cookie);      
      
      resp.getWriter().println("<html><head>");
      
      //開発環境の場合
      if(req.getServerName().equals("localhost"))
      {
        resp.getWriter().println("<meta HTTP-EQUIV='Refresh' CONTENT='0; URL=http://localhost:8080/cal/list'>");        
      }
      //App Engineの場合
      else
      {
        resp.getWriter().println("<meta HTTP-EQUIV='Refresh' CONTENT='0; URL=http://riamediator.appspot.com/cal/list'>");  
      }      
      

      resp.getWriter().println("</head><body></body></html>");
      
    }
    catch(Exception ex)
    {
      resp.setContentType("text/html;charset=UTF-8");
      
      try
      {
        resp.getWriter().println(String.format("<html><body>%s</body></html>",ex.toString()));
      }
      catch(Exception e){}
    }
  }

public class CalendarServlet extends HttpServlet {

  private static final Logger _log = Logger.getLogger(CalendarServlet.class.getName());
  
  public void doGet(HttpServletRequest req, HttpServletResponse resp)
  throws IOException {
    
    try
    {
      resp.setContentType("text/html;charset=UTF-8");
      resp.getWriter().println("<html><body>");
      
      //クッキーからトークンを取得する
      Cookie[] cookies = req.getCookies();
      
      String accessToken = null;
      String tokenSecret = null;
      
      if(cookies != null)
      {
        for(Cookie cookie : cookies)
        {
          if(cookie.getName().equals("access_token"))
          {
            accessToken = cookie.getValue();
          }
          else if(cookie.getName().equals("token_secret"))
          {
            tokenSecret = cookie.getValue();
          }            
        }
      }
      
      GoogleOAuthParameters params = new GoogleOAuthParameters();
      params.setOAuthConsumerKey(ドメイン登録時に取得したOAuth Consumer Key);
      params.setOAuthConsumerSecret(ドメイン登録時に取得したOAuth Consumer Secret);
      params.setOAuthSignatureMethod("HMAC-SHA1");
      params.setOAuthToken(accessToken);
      params.setOAuthTokenSecret(tokenSecret);
      params.addCustomBaseParameter("oauth_version","1.0");
      
      CalendarService service = new CalendarService("riamediator-riamediator-1");
      service.setOAuthCredentials(params, new OAuthHmacSha1Signer());
      
      URL feedUrl = new URL("http://www.google.com/calendar/feeds/default/allcalendars/full");
      CalendarFeed resultFeed = service.getFeed(feedUrl, CalendarFeed.class);
      
      for (int i = 0; i < resultFeed.getEntries().size(); i++) {
        CalendarEntry entry = resultFeed.getEntries().get(i);
        resp.getWriter().println(entry.getTitle().getPlainText() + "<br>");
      }
      
      resp.getWriter().println("</body></html>");
  
    }
    catch(Exception ex)
    {      
      try
      {
        resp.getWriter().println(String.format("<html><body>%s</body></html>",ex.toString()));
      }
      catch(Exception e){}
    }
  }

コメント

Google Contact APIを使うためにOAuthの接続部分を作っているのですが大変参考になりました!OAuth時にanonymouseを送信していたのですが、「ドメインの登録」が必要だったんですね。ありがとうございました。

Re: タイトルなし

> Google Contact APIを使うためにOAuthの接続部分を作っているのですが大変参考になりました!OAuth時にanonymouseを送信していたのですが、「ドメインの登録」が必要だったんですね。ありがとうございました。

Hisaさん、役にたってよかったです。

コメントの投稿

管理者にだけ表示を許可する

トラックバック

http://csfun.blog49.fc2.com/tb.php/46-bd500b06

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。