diff --git a/demo/simple_example_auth.py b/demo/simple_example_auth.py
new file mode 100644
index 0000000..d1da45f
--- /dev/null
+++ b/demo/simple_example_auth.py
@@ -0,0 +1,93 @@
+from aiohttp import web
+from aiohttp_session import SimpleCookieStorage, session_middleware
+from aiohttp_security import has_permission, \
+ is_anonymous, remember, forget, \
+ setup as setup_security, SessionIdentityPolicy
+from aiohttp_security.abc import AbstractAuthorizationPolicy
+
+
+# Demo authorization policy for only one user.
+# User 'jack' has only 'listen' permission.
+# For more complicated authorization policies see examples
+# in the 'demo' directory.
+class SimpleJack_AuthorizationPolicy(AbstractAuthorizationPolicy):
+ async def authorized_userid(self, identity):
+ """Retrieve authorized user id.
+ Return the user_id of the user identified by the identity
+ or 'None' if no user exists related to the identity.
+ """
+ if identity == 'jack':
+ return identity
+
+ async def permits(self, identity, permission, context=None):
+ """Check user permissions.
+ Return True if the identity is allowed the permission
+ in the current context, else return False.
+ """
+ return identity == 'jack' and permission in ('listen',)
+
+
+async def handler_root(request):
+ is_logged = not await is_anonymous(request)
+ return web.Response(text='''
+ Hello, I'm Jack, I'm {logged} logged in.
+ Log me in
+ Log me out
+ Check my permissions,
+ when i'm logged in and logged out.
+ Can I listen?
+ Can I speak?
+ '''.format(
+ logged='' if is_logged else 'NOT',
+ ), content_type='text/html')
+
+
+async def handler_login_jack(request):
+ redirect_response = web.HTTPFound('/')
+ await remember(request, redirect_response, 'jack')
+ raise redirect_response
+
+
+async def handler_logout(request):
+ redirect_response = web.HTTPFound('/')
+ await forget(request, redirect_response)
+ raise redirect_response
+
+
+@has_permission('listen')
+async def handler_listen(request):
+ return web.Response(body="I can listen!")
+
+
+@has_permission('speak')
+async def handler_speak(request):
+ return web.Response(body="I can speak!")
+
+
+async def make_app():
+ #
+ # WARNING!!!
+ # Never use SimpleCookieStorage on production!!!
+ # It’s highly insecure!!!
+ #
+
+ # make app
+ middleware = session_middleware(SimpleCookieStorage())
+ app = web.Application(middlewares=[middleware])
+
+ # add the routes
+ app.router.add_route('GET', '/', handler_root)
+ app.router.add_route('GET', '/login', handler_login_jack)
+ app.router.add_route('GET', '/logout', handler_logout)
+ app.router.add_route('GET', '/listen', handler_listen)
+ app.router.add_route('GET', '/speak', handler_speak)
+
+ # set up policies
+ policy = SessionIdentityPolicy()
+ setup_security(app, policy, SimpleJack_AuthorizationPolicy())
+
+ return app
+
+
+if __name__ == '__main__':
+ web.run_app(make_app(), port=9000)
diff --git a/docs/example.rst b/docs/example.rst
index b75a8ed..39c839b 100644
--- a/docs/example.rst
+++ b/docs/example.rst
@@ -7,63 +7,96 @@ How to Make a Simple Server With Authorization
Simple example::
- import asyncio
from aiohttp import web
-
- async def root_handler(request):
- text = "Alive and kicking!"
- return web.Response(body=text.encode('utf-8'))
-
- # option 2: auth at a higher level?
- # set user_id and allowed in the wsgi handler
- @protect('view_user')
- async def user_handler(request):
- name = request.match_info.get('name', "Anonymous")
- text = "Hello, " + name
- return web.Response(body=text.encode('utf-8'))
+ from aiohttp_session import SimpleCookieStorage, session_middleware
+ from aiohttp_security import has_permission, \
+ is_anonymous, remember, forget, \
+ setup as setup_security, SessionIdentityPolicy
+ from aiohttp_security.abc import AbstractAuthorizationPolicy
- # option 3: super low
- # wsgi doesn't do anything
- async def user_update_handler(request):
- # identity, asked_permission
- user_id = await identity_policy.identify(request)
- identity = await auth_policy.authorized_userid(user_id)
- allowed = await request.auth_policy.permits(
- identity, asked_permission)
- if not allowed:
- # how is this pluggable as well?
- # ? return NotAllowedStream()
- raise NotAllowedResponse()
+ # Demo authorization policy for only one user.
+ # User 'jack' has only 'listen' permission.
+ # For more complicated authorization policies see examples
+ # in the 'demo' directory.
+ class SimpleJack_AuthorizationPolicy(AbstractAuthorizationPolicy):
+ async def authorized_userid(self, identity):
+ """Retrieve authorized user id.
+ Return the user_id of the user identified by the identity
+ or 'None' if no user exists related to the identity.
+ """
+ if identity == 'jack':
+ return identity
- update_user()
+ async def permits(self, identity, permission, context=None):
+ """Check user permissions.
+ Return True if the identity is allowed the permission
+ in the current context, else return False.
+ """
+ return identity == 'jack' and permission in ('listen',)
- async def init(loop):
- # set up identity and auth
- auth_policy = DictionaryAuthorizationPolicy({'me': ('view_user',),
- 'you': ('view_user',
- 'edit_user',)})
- identity_policy = CookieIdentityPolicy()
- auth = authorization_middleware(auth_policy, identity_policy)
- # wsgi app
- app = web.Application(loop=loop, middlewares=*auth)
+ async def handler_root(request):
+ is_logged = not await is_anonymous(request)
+ return web.Response(text='''
+ Hello, I'm Jack, I'm {logged} logged in.
+ Log me in
+ Log me out
+ Check my permissions,
+ when i'm logged in and logged out.
+ Can I listen?
+ Can I speak?
+ '''.format(
+ logged='' if is_logged else 'NOT',
+ ), content_type='text/html')
+
+
+ async def handler_login_jack(request):
+ redirect_response = web.HTTPFound('/')
+ await remember(request, redirect_response, 'jack')
+ raise redirect_response
+
+
+ async def handler_logout(request):
+ redirect_response = web.HTTPFound('/')
+ await forget(request, redirect_response)
+ raise redirect_response
+
+
+ @has_permission('listen')
+ async def handler_listen(request):
+ return web.Response(body="I can listen!")
+
+
+ @has_permission('speak')
+ async def handler_speak(request):
+ return web.Response(body="I can speak!")
+
+
+ async def make_app():
+ #
+ # WARNING!!!
+ # Never use SimpleCookieStorage on production!!!
+ # It’s highly insecure!!!
+ #
+
+ # make app
+ middleware = session_middleware(SimpleCookieStorage())
+ app = web.Application(middlewares=[middleware])
# add the routes
- app.router.add_route('GET', '/', root_handler)
- app.router.add_route('GET', '/{user}', user_handler)
- app.router.add_route('GET', '/{user}/edit', user_update_handler)
+ app.router.add_route('GET', '/', handler_root)
+ app.router.add_route('GET', '/login', handler_login_jack)
+ app.router.add_route('GET', '/logout', handler_logout)
+ app.router.add_route('GET', '/listen', handler_listen)
+ app.router.add_route('GET', '/speak', handler_speak)
- # get it started
- srv = await loop.create_server(app.make_handler(),
- '127.0.0.1', 8080)
- print("Server started at http://127.0.0.1:8080")
- return srv
+ # set up policies
+ policy = SessionIdentityPolicy()
+ setup_security(app, policy, SimpleJack_AuthorizationPolicy())
+
+ return app
- loop = asyncio.get_event_loop()
- loop.run_until_complete(init(loop))
- try:
- loop.run_forever()
- except KeyboardInterrupt:
- pass # TODO put handler cleanup here
+ if __name__ == '__main__':
+ web.run_app(make_app(), port=9000)