pyramidでのtwitter OAuthに手探りで挑戦した記録
参考: http://peterhudec.github.io/authomatic/examples/pyramid-simple.html
準備
twitterにアプリ登録
https://apps.twitter.com/
ここでアプリを登録し、Consumer Key, Consumer Secretを取得
(電話番号をtwitterに登録していない人は登録を要求されるので注意)
pyramidインストール
今回のバージョンは1.7a1
プロジェクト作成
$ $VENV/bin/pcreate oauthtut
OAuthにはAuthomaticを利用した
@@ -17,6 +17,7 @@ requires = [
'transaction',
'zope.sqlalchemy',
'waitress',
+ 'authomatic',
]
tests_require = [
$ $VENV/bin/python setup.py develop
メンバー用ページ作成
/for_member
作成。後でログインログインした場合のみ見られるようにする。
@@ -1,3 +1,4 @@
def includeme(config):
config.add_static_view('static', 'static', cache_max_age=3600)
config.add_route('home', '/')
+ config.add_route('for_member', '/for_member')
@@ -31,3 +31,10 @@ might be caused by one of the following things:
After you fix the problem, please restart the Pyramid application to
try it again.
"""
+
+@view_config(route_name='for_member')
+def for_member(request):
+ response = Response()
+ response.write(u'<h1>Hi {0}</h1>'.format(request.authenticated_userid))
+
+ return response
サーバ起動
$ $VENV/bin/pserve development --reload
この時点でhttp://localhost:6543
にアクセスすると
Hi None
と表示される
認証の設定
pyramidに対して認証周りの設定を行うがこの時点ではAuthomaticは出てこず変更内容はチュートリアルのそれに近い
@@ -3,15 +3,31 @@ from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm import configure_mappers
import zope.sqlalchemy
+from pyramid.authentication import AuthTktAuthenticationPolicy
+from pyramid.authorization import ACLAuthorizationPolicy
+
# import or define all models here to ensure they are attached to the
# Base.metadata prior to any initialization routines
from .mymodel import MyModel # flake8: noqa
+from .security import groupfinder
+
# run configure_mappers after defining all of the models to ensure
# all relationships can be setup
configure_mappers()
+from pyramid.security import (
+ Allow,
+ Everyone,
+)
+
+class RootFactory(object):
+ __acl__ = [ (Allow, Everyone, 'guest'),
+ (Allow, 'group:member', 'member')]
+ def __init__(self,request):
+ pass
+
def get_engine(settings, prefix='sqlalchemy.'):
return engine_from_config(settings, prefix)
@@ -58,6 +74,15 @@ def includeme(config):
"""
settings = config.get_settings()
+ config.set_root_factory('oauthtut.models.RootFactory')
+
+ authn_policy = AuthTktAuthenticationPolicy(
+ 'sosecret', callback=groupfinder, hashalg='sha512')
+ authz_policy = ACLAuthorizationPolicy()
+
+ config.set_authentication_policy(authn_policy)
+ config.set_authorization_policy(authz_policy)
+
# use pyramid_tm to hook the transaction lifecycle to the request
config.include('pyramid_tm')
AuthTktAuthenticationPolicy
生成時に指定されているgroupfinder
ではユーザーとパーミッションを紐付ける。今回はログインさえできていれば、group:member
のパーミッションを与えている。
GROUPS = {'member':['group:member']}
def groupfinder(userid, request):
if userid:
return ['group:member']
return []
/for_member
をのパーミッションを設定する
@@ -32,7 +32,7 @@ After you fix the problem, please restart the Pyramid application to
try it again.
"""
-@view_config(route_name='for_member')
+@view_config(route_name='for_member', permission='member')
def for_member(request):
response = Response()
response.write(u'<h1>Hi {0}</h1>'.format(request.authenticated_userid))
これでログインしないで/for_member
にアクセスすると403となる
ログイン/ログアウト処理追加
以下の変更で/for_member
アクセス時にOAuthが走るようになる。
@@ -2,3 +2,5 @@ def includeme(config):
config.add_static_view('static', 'static', cache_max_age=3600)
config.add_route('home', '/')
config.add_route('for_member', '/for_member')
+ config.add_route('login', '/login')
+ config.add_route('logout', '/logout')
```
```py3:oauthtut/views/login.py
from pyramid.response import Response
from authomatic import Authomatic
from authomatic.adapters import WebObAdapter
from pyramid.httpexceptions import (
HTTPFound,
HTTPForbidden,
HTTPBadGateway,
)
from pyramid.view import (
view_config,
forbidden_view_config,
)
from pyramid.security import (
remember,
forget,
)
from ..config import CONFIG
authomatic = Authomatic(config=CONFIG, secret='some random secret string')
@view_config(route_name='login')
@forbidden_view_config()
def login(request):
response = Response()
login_url = request.route_url('login')
referrer = request.url
came_from = request.params.get('came_from', referrer)
result = authomatic.login(WebObAdapter(request, response), 'tw')
if result:
if result.error:
return HTTPBadGateway()
elif result.user:
if not (result.user.name and result.user.id):
result.user.update()
headers = remember(request, result.user.id)
return HTTPFound(location=came_from,
headers=headers)
return response
@view_config(route_name='logout')
def logout(request):
headers = forget(request)
return HTTPFound(location = request.route_url('home'),
headers = headers)
```
```py3:oauthtut/config.py
from authomatic.providers import oauth1
CONFIG = {
'tw': {
'class_': oauth1.Twitter,
'consumer_key': 'XXXXXXXXXXXXXXXXXXXXXX',
'consumer_secret': 'XXXXXXXXXXXXXXXXXXXXXX',
},
}
```