Python で作る Facebook ページの「いいね!」ファン限定コンテンツ (ファンゲート)

最近ようやく Facebook を使い始めていろいろ遊んでいます。
今回は企業の Facebook ページなんかでよく見かける「いいね!」会員限定コンテンツを Python で実装してみます。

環境

今回は Dotcloud を使ってみますが、サーバーの設定が面倒だという理由からです。WSGI を利用できるサーバーがすでにあるならそちらで動かしても問題ないと思います。

コード

環境作成
$ mkdir fangate
$ cd fangate
$ touch wsgi.py
$ touch dotcloud.yml
wsgi.py

signed_request を POST してくるので送られてきたデータを parse する。

# coding: utf-8
# Ref: http://developers.facebook.com/docs/authentication/signed_request/
import json
import urlparse
import hmac
import hashlib
import base64


SECRET = 'アプリの秘訣を入れる'


def base64_url_decode(s):
    padding = 4 - len(s) % 4
    s += '=' * padding
    return base64.urlsafe_b64decode(s)


def parse_signed_request(signed_request, secret):
    encoded_sig, payload = signed_request.split('.', 2)
    sig = base64_url_decode(encoded_sig)
    data = json.loads(base64_url_decode(payload))

    if data['algorithm'].upper() != 'HMAC-SHA256':
        return None
    
    expected_sig = hmac.new(secret, payload, hashlib.sha256).digest()
    if sig != expected_sig:
        return None

    return data


def application(environ, start_response):
    status = '200 OK'
    response_headers = [('Content-Type', 'text/html')]
    start_response(status, response_headers)
    if environ['REQUEST_METHOD'] == 'POST':
        post_data = urlparse.parse_qs(environ['wsgi.input'].read())
        if 'signed_request' in post_data:
            # post_data['signed_request'] の中身はリストになっている
            signed_request = parse_signed_request(post_data['signed_request'][0], SECRET)
            if signed_request['page']['liked']:
                # 限定コンテンツ!
                return ['Special Content!']
    # 通常コンテンツ
    return ['Hello']
dotcloud.yml
www:
  type: python
Dotcloud にデプロイ
$ dotcloud create fangate
$ dotcloud push fangate
...

Deployment finished. Your application is available at the following URLs
www: http://fangate-XXXXXXXX.dotcloud.com/

おしまい

これでファンゲートの完成です。あとは Facebook アプリの設定を済ませて、いいねを押してみたり取り消したりしてみましょう。
動かないときは dotcloud logs fangate.www としてみてログを確認してください。