FacebookにGroovyでログイン(その4)

2019-05-12Facebook,Groovy

以下のエントリのさらに続きです。

結局、昨日の方式を採用しました。
リダイレクト後の http://localhost:9999/#access_token=...# 以降をサーバーで取得できないため、画面描画後にJavaScriptで ? に置き換え再リクエストするようにしてみました。

結果、アクセストークンが取得できました。

#!/usr/bin/env groovy
@Grab("org.mortbay.jetty:jetty-embedded:6.1.26")
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Method
import javax.servlet.http.*
import javax.servlet.ServletException
import org.mortbay.jetty.Connector
import org.mortbay.jetty.Handler
import org.mortbay.jetty.handler.AbstractHandler
import org.mortbay.jetty.Request
import org.mortbay.jetty.Server

def appId = "XXXXXXXXXXXXXXX"
def localHost = "localhost"
def localPort = 9999
def urlText = "https://www.facebook.com/dialog/oauth?" + [
        "client_id=${appId}",
        "redirect_uri=" + URLEncoder.encode("http://${localHost}:${localPort}/login_success.html", "utf-8"),
        "scope=" + URLEncoder.encode("email,read_stream,friends_about_me,user_about_me", "utf-8"),
        "response_type=token",
].join("&")

browser = browse(urlText)

server = new Server(localPort).with {
    connectors.each {
        it.host = "${localHost}"
    }
    handler = [
            handle: { String target, HttpServletRequest request, HttpServletResponse response, int dispatch ->
                switch (target) {
                    case "/login_success.html":
                        response.with {
                            status = HttpServletResponse.SC_OK
                            contentType = "text/html"
                            writer.withWriter {
                                it.println("<html>")
                                it.println("<head>")
                                it.println("<script type='text/javascript'>")
                                it.println("function init() {")
                                it.println("    window.location = 'http://localhost:9999/access_token.html?' + window.location.toString().split('#')[1];");
                                it.println("}")
                                it.println("</script>")
                                it.println("</head>")
                                it.println("<body onload=\"init();\">")
                                it.println("</body>")
                                it.println("</html>")
                            }
                            handled = true
                        }
                        break
                    case "/access_token.html":
                        println request.getParameter("access_token")
                        println request.getParameter("expires_in")
                        request.handled = true
                        browser.destroy()
                        server.stop()
                        server.join()
                        break
                    default:
                        response.status = HttpServletResponse.SC_NOT_FOUND
                        break
                }
            }
    ] as AbstractHandler
    start()
}

def browse(String url) throws ClassNotFoundException, IllegalAccessException,
        IllegalArgumentException, InterruptedException, InvocationTargetException, IOException,
        NoSuchMethodException {
    def osName = System.getProperty("os.name", "")
    if (osName.startsWith("Mac OS")) {
        Class fileMgr = Class.forName("com.apple.eio.FileManager")
        Method openURL = fileMgr.getDeclaredMethod("openURL", [String.class] as Class[])
        openURL.invoke(null, [url] as Object[])
    } else if (osName.startsWith("Windows")) {
        return Runtime.runtime.exec("rundll32 url.dll,FileProtocolHandler " + url)
    } else {
        def browser = ["firefox", "opera", "konqueror", "epiphany", "mozilla", "netscape"].find {
            Runtime.runtime.exec(["which", it] as String[]).waitFor() == 0
        }
        if (!browser)
            throw new NoSuchMethodException("Could not find web browser")
        return Runtime.runtime.exec(browser + " ${url}")
    }
}

Facebookのアプリケーション設定画面の サイトURL 入力欄には、昨日の設定から以下の入力に変更しました。

  • http://localhost:9999/login_success.html

Facebook認証後リダイレクトにより、ローカルサーバーのコンテンツが表示されるが、onloadにてすぐに以下のURLにサブミット。

  • http://localhost:9999/access_token.html

後はトークン取得後のjettyサーバーの停止を組み込みたい。

一応 server.stop() メソッドは呼び出しているが停止してくれない。
なぜか一分後とかにひょっこり止まってしまいます。

2019-05-12Facebook,Groovy