adding decorator and demo code

This commit is contained in:
Sick Yoon 2016-05-13 10:40:57 +09:00
parent c951e3486f
commit ffa1c08189
12 changed files with 145 additions and 24 deletions

View File

@ -1,5 +1,5 @@
from .abc import AbstractIdentityPolicy, AbstractAuthorizationPolicy from .abc import AbstractIdentityPolicy, AbstractAuthorizationPolicy
from .api import remember, forget, setup, authorize, permits from .api import remember, forget, setup, authorize, permits, get_user_identity
from .cookies_identity import CookiesIdentityPolicy from .cookies_identity import CookiesIdentityPolicy
from .session_identity import SessionIdentityPolicy from .session_identity import SessionIdentityPolicy
@ -9,4 +9,5 @@ __version__ = '0.1.0'
__all__ = ('AbstractIdentityPolicy', 'AbstractAuthorizationPolicy', __all__ = ('AbstractIdentityPolicy', 'AbstractAuthorizationPolicy',
'CookiesIdentityPolicy', 'SessionIdentityPolicy', 'CookiesIdentityPolicy', 'SessionIdentityPolicy',
'remember', 'forget', 'authorize', 'permits', 'setup') 'remember', 'forget', 'authorize', 'permits',
'get_user_identity', 'setup')

View File

@ -1,6 +1,8 @@
import asyncio import asyncio
import functools import functools
from aiohttp import web from aiohttp import web
from aiohttp_security.abc import (AbstractIdentityPolicy, from aiohttp_security.abc import (AbstractIdentityPolicy,
AbstractAuthorizationPolicy) AbstractAuthorizationPolicy)
@ -16,18 +18,34 @@ def authorize(required=True, redirect_url=None, permission=None):
# assuming first argument is request # assuming first argument is request
assert isinstance(args[0], web.Request) assert isinstance(args[0], web.Request)
request = args[0] request = args[0]
# check if coroutine
if asyncio.iscoroutinefunction(f): if asyncio.iscoroutinefunction(f):
coro = f coro = f
else: else:
coro = asyncio.coroutine(f) coro = asyncio.coroutine(f)
identity = yield from get_user_identity(request)
if not identity and required:
raise web.HTTPForbidden()
kwargs['identity'] = identity
return (yield from coro(*args, **kwargs))
return wrapped
return wrapper
# get identity
identity = yield from get_user_identity(request)
kwargs['identity'] = identity
if required:
# check identity
if not identity:
return web.HTTPFound(redirect_url) if redirect_url \
else web.HTTPForbidden(reason='not authenticated')
# check permission
allowed = yield from permits(request, permission)
if permission and not allowed:
return web.HTTPForbidden(reason='unauthorized')
return (yield from coro(*args, **kwargs))
return wrapped
return wrapper
@asyncio.coroutine @asyncio.coroutine
@ -78,6 +96,7 @@ def get_user_identity(request):
identity = yield from identity_policy.identify(request) identity = yield from identity_policy.identify(request)
return identity return identity
''' '''
@asyncio.coroutine @asyncio.coroutine
def authorized_userid(request): def authorized_userid(request):
@ -98,6 +117,8 @@ def permits(request, permission, context=None):
assert isinstance(permission, str), permission assert isinstance(permission, str), permission
assert permission assert permission
autz_policy = request.app.get(AUTZ_KEY) autz_policy = request.app.get(AUTZ_KEY)
if autz_policy is None:
return True
identity = yield from get_user_identity(request) identity = yield from get_user_identity(request)
access = yield from autz_policy.permits(identity, permission, context) access = yield from autz_policy.permits(identity, permission, context)
return access return access

View File

@ -0,0 +1,11 @@
import asyncio
from aiohttp_security.abc import AbstractAuthorizationPolicy
class StubAuthorizationPolicy(AbstractAuthorizationPolicy):
@asyncio.coroutine
def permits(self, identity, permission, context=None):
if identity == permission:
return True
return False

View File

@ -0,0 +1,34 @@
from aiohttp import web
from aiohttp_jinja2 import render_template
from aiohttp_security import authorize, get_user_identity, remember, forget
@authorize(required=True, redirect_url='/login', permission='Steve')
async def index(request, identity=None):
context = {'name': identity}
response = render_template('index.html', request, context)
return response
async def login(request):
identity = await get_user_identity(request)
if identity:
return web.HTTPFound('/')
response = render_template('login.html', request, {})
return response
async def login_post(request):
post_data = await request.post()
user_id = post_data['username']
password = post_data['password']
response = web.Response(body=b'OK')
await remember(request, response, user_id)
return response
async def logout(request):
response = web.Response(body=b'OK')
await forget(request, response)
return response

27
demo/session_auth/main.py Normal file
View File

@ -0,0 +1,27 @@
import asyncio
import os
import jinja2
from aiohttp import web
from aiohttp_jinja2 import setup as setup_jinja
from aiohttp_session import setup as setup_session
from aiohttp_session.redis_storage import RedisStorage
from aioredis import create_pool
from aiohttp_security import setup as setup_security, SessionIdentityPolicy
from .auth_policy import StubAuthorizationPolicy
from .handlers import index, login, login_post, logout
loop = asyncio.get_event_loop()
redis_pool = loop.run_until_complete(create_pool(('localhost', 6379)))
app = web.Application(loop=loop)
setup_session(app, RedisStorage(redis_pool))
setup_security(app,
SessionIdentityPolicy(),
StubAuthorizationPolicy())
setup_jinja(app, loader=jinja2.FileSystemLoader(os.path.join(os.path.dirname(__file__), 'templates')))
app.router.add_route('GET', '/', index)
app.router.add_route('GET', '/login', login)
app.router.add_route('POST', '/login', login_post)
app.router.add_route('GET', '/logout', logout)
web.run_app(app)

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>aiohttp_security demo</title>
</head>
<body>
{% block content %}{% endblock %}
{% block script %}{% endblock %}
</body>
</html>

View File

@ -0,0 +1,6 @@
{% extends 'base.html' %}
{% block content %}
<div>
<h1>Hello {{name}}!</h1>
</div>
{% endblock %}

View File

@ -0,0 +1,15 @@
{% extends 'base.html' %}
{% block content %}
<div>
<h3>Login</h3>
<form class="m-t" role="form" action="/login" method="post">
<div class="form-group">
<input name="username" type="text" class="form-control" placeholder="ID" required="">
</div>
<div class="form-group">
<input name="password" type="password" class="form-control" placeholder="Password" required="">
</div>
<button type="submit">Login</button>
</form>
</div>
{% endblock %}

View File

@ -15,10 +15,6 @@ class Autz(AbstractAuthorizationPolicy):
def permits(self, identity, permission, context=None): def permits(self, identity, permission, context=None):
pass pass
@asyncio.coroutine
def authorized_userid(self, identity):
pass
@pytest.mark.run_loop @pytest.mark.run_loop
def test_remember(create_app_and_client): def test_remember(create_app_and_client):

View File

@ -2,8 +2,7 @@ import asyncio
import pytest import pytest
from aiohttp import web from aiohttp import web
from aiohttp_security import (remember, from aiohttp_security import (remember, permits, get_user_identity,
authorized_userid, permits,
AbstractAuthorizationPolicy) AbstractAuthorizationPolicy)
from aiohttp_security import setup as _setup from aiohttp_security import setup as _setup
from aiohttp_security.cookies_identity import CookiesIdentityPolicy from aiohttp_security.cookies_identity import CookiesIdentityPolicy
@ -18,12 +17,14 @@ class Autz(AbstractAuthorizationPolicy):
else: else:
return False return False
'''
@asyncio.coroutine @asyncio.coroutine
def authorized_userid(self, identity): def authorized_userid(self, identity):
if identity == 'UserID': if identity == 'UserID':
return 'Andrew' return 'Andrew'
else: else:
return None return None
'''
@pytest.mark.run_loop @pytest.mark.run_loop
@ -32,12 +33,12 @@ def test_authorized_userid(create_app_and_client):
@asyncio.coroutine @asyncio.coroutine
def login(request): def login(request):
response = web.HTTPFound(location='/') response = web.HTTPFound(location='/')
yield from remember(request, response, 'UserID') yield from remember(request, response, 'Andrew')
return response return response
@asyncio.coroutine @asyncio.coroutine
def check(request): def check(request):
userid = yield from authorized_userid(request) userid = yield from get_user_identity(request)
assert 'Andrew' == userid assert 'Andrew' == userid
return web.Response(text=userid) return web.Response(text=userid)
@ -58,7 +59,7 @@ def test_authorized_userid_not_authorized(create_app_and_client):
@asyncio.coroutine @asyncio.coroutine
def check(request): def check(request):
userid = yield from authorized_userid(request) userid = yield from get_user_identity(request)
assert userid is None assert userid is None
return web.Response() return web.Response()

View File

@ -2,7 +2,7 @@ import asyncio
import pytest import pytest
from aiohttp import web from aiohttp import web
from aiohttp_security import authorized_userid, permits from aiohttp_security import permits, get_user_identity
@pytest.mark.run_loop @pytest.mark.run_loop
@ -10,7 +10,7 @@ def test_authorized_userid(create_app_and_client):
@asyncio.coroutine @asyncio.coroutine
def check(request): def check(request):
userid = yield from authorized_userid(request) userid = yield from get_user_identity(request)
assert userid is None assert userid is None
return web.Response() return web.Response()

View File

@ -17,10 +17,6 @@ class Autz(AbstractAuthorizationPolicy):
def permits(self, identity, permission, context=None): def permits(self, identity, permission, context=None):
pass pass
@asyncio.coroutine
def authorized_userid(self, identity):
pass
@pytest.fixture @pytest.fixture
def create_app_and_client2(create_app_and_client): def create_app_and_client2(create_app_and_client):