adding decorator and demo code
This commit is contained in:
parent
c951e3486f
commit
ffa1c08189
|
@ -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')
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
|
@ -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>
|
|
@ -0,0 +1,6 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block content %}
|
||||||
|
<div>
|
||||||
|
<h1>Hello {{name}}!</h1>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -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 %}
|
|
@ -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):
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
@ -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):
|
||||||
|
|
Loading…
Reference in New Issue