2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【備忘録】pyramidでtwitter OAuth

Last updated at Posted at 2016-05-01

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を利用した

setup.py
@@ -17,6 +17,7 @@ requires = [                                                                                                                                                                                                                
     'transaction',                                                                                                                                                                                                                           
     'zope.sqlalchemy',                                                                                                                                                                                                                       
     'waitress',                                                                                                                                                                                                                              
+    'authomatic',                                                                                                                                                                                                                            
     ]                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                              
 tests_require = [
$ $VENV/bin/python setup.py develop

メンバー用ページ作成

/for_member作成。後でログインログインした場合のみ見られるようにする。

oauthtut/routes.py
@@ -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')
oauthtut/routes.py
@@ -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は出てこず変更内容はチュートリアルのそれに近い

oauthtut/models/__init__.py
@@ -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のパーミッションを与えている。

oauth/models/security.py
GROUPS = {'member':['group:member']}

def groupfinder(userid, request):
    if userid:
        return ['group:member']
    return []

/for_memberをのパーミッションを設定する

oauthtut/views/default.py
@@ -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が走るようになる。

oauthtut/routes.py
@@ -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',
    },
}
```
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?