用 Python social-oauth 的 facebook 連結


比較和測試了一下找到的社交登入模組.
覺得 social-oauth 是比較可控和靈巧.
不過他本身是一個專注於中國內地社交的模組.
所以就沒自帶 Facebook, Twitter 的支持.
那只好自幹一個 Provider 來測試.筆記一下.

結構大約是

  • social/providers/facebook.py
  • social/routes/index.py

當中 index.py 大約是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
from socialoauth import socialsites
from socialoauth.utils import import_oauth_class
from socialoauth.exception import SocialAPIError

app_name = __name__.split('.')[0]

socialsites.config({
'facebook': ('{0}.providers.facebook.Facebook'.format(app_name), 1, 'Facebook', {
'redirect_uri': 'http://sub.domain.com/login/oauth/facebook',
'client_id': 'SOME ID',
'client_secret': 'SOME KEY',
'scope': ['email']
})
})

@app.route('/')
def index():
user = session.get('user')
return render_template('index.html', user=user)

@app.route('/login')
def login():
connections = dict()
for socialsite in socialsites.list_sites():
provider = import_oauth_class(socialsite)()
connections[provider.site_name] = provider

return render_template('login.html', connections=connections)

@app.route('/login/oauth/<provider>')
def login_oauth(provider):
code = request.args.get('code')
if not code:
redirect(url_for('index.index'))

socialsite = import_oauth_class(socialsites[provider])()

try:
socialsite.get_access_token(code)
except SocialAPIError as e:
print e.site_name
print e.url
print e.error_msg
raise

session['user'] = socialsite

return redirect(url_for('index.index'))

而 facebook.py 就是這樣
當中 parse_token_response 的內容可以再按需求增加
裡面的資料目前設定成和其他內置的 providers/sites 是一樣的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from socialoauth.sites.base import OAuth2

class Facebook(OAuth2):
GRAPH_URL = 'https://graph.facebook.com'
AUTHORIZE_URL = 'https://www.facebook.com/dialog/oauth'
ACCESS_TOKEN_URL = '{0}/oauth/access_token'.format(GRAPH_URL)

SMALL_IMAGE = '{0}/{1}/picture'
LARGE_IMAGE = '{0}/{1}/picture?type=large'

def build_api_url(self, url):
return url

def build_api_data(self, **kwargs):
data = {
'access_token': self.access_token
}
data.update(kwargs)
return data

def parse_token_response(self, res):
res = res.split('&')
res = [_r.split('=') for _r in res]
res = dict(res)

self.access_token = res['access_token']
self.expires_in = int(res['expires'])
self.refresh_token = None

res = self.http_get('https://graph.facebook.com/me', {
'access_token': self.access_token
})

self.uid = res['id']
self.name = res['username']
self.avatar = self.SMALL_IMAGE.format(self.GRAPH_URL, res['username'])
self.avatar_large = self.LARGE_IMAGE.format(self.GRAPH_URL, res['username'])

def get_access_token(self, code):
super(Facebook, self).get_access_token(code, method='GET', parse=False)