tipfy.ext.auth ¶
This extension provides utilities to support a variety of authentication methods in tipfy using a standard API. Currently supported methods are:
See our examples of multi-auth (source) and gae auth (source).
Overview¶
To implement authentication, a handler must extend one of the two mixins
provided by this extension: AppEngineAuthMixin, to use App Engine's
built in auth system, or MultiAuthMixin, for own authentication or one
of the supported third party authentication services.
The handler will then have access to the current logged in user as a property, as well as several authentication related methods.
Configuration¶
These are the configuration options available for this extension. All configuration values are optional.
- user_model: A
db.Modelclass used for authenticated users, as a string. Define this to provide a custom user model. Default istipfy.ext.auth.model.User. - cookie_name: Name of the autentication cookie. Default is
tipfy.auth. - session_max_age: Interval in seconds before a user session id is renewed. Default is 1 week.
For own and third party auth, you also need to configure the session extension, which requires a secret key to be defined.
Authentication endpoints¶
You need to define URL rules used for login, logout and sign up using the following endpoints:
auth/login: displays and processes a login form.auth/logout: invalidates the user session.auth/signup: display and process a registration form.
For built in App Engine auth, only auth/signup is required. The others
are ignored since these URLs are generated by App Engine. For own and third
party auth, all endpoints must be implemented.
Here's an example of defining the three endpoints:
urls.py
from tipfy import Rule
def get_rules(app):
rules = [
Rule('/login', endpoint='auth/login', handler='handlers.LoginHandler'),
Rule('/logout', endpoint='auth/logout', handler='handlers.LogoutHandler'),
Rule('/register', endpoint='auth/signup', handler='handlers.SignupHandler'),
]
return rules
AppEngineAuthMixin¶
This mixin is used exclusively for authentication with App Engine's Users API.
Because of its uniqueness, we have no option but to declare that it as a authentication system that doesn't mix with others: if you use App Engine's built in authentication, you don't use any other. On the other hand, it is the simplest to setup and the preferred one to use for single sign-on (SSO) on Google Marketplace apps.
Why have a mixin for App Engine's built-in authentication if the API is simple to use? Here are the main reasons:
- You can use the decorator
@user_requiredto require a user record stored in datastore after a user signs in. - It also adds a convenient access to current logged in user directly inside the handler, as well as the functions to generate auth-related URLs.
- It standardizes how you create login, logout and signup URLs, and how you
check for a logged in user and load an
Userentity. If you change to a different auth method later, these don't need to be changed in your code.
That said, you are free to ignore this extension and use the API directly if you prefer. We think that it is worth at least as a convenience to a common need: to load users from datastore based on the authentication id from the built in auth system.
Using AppEngineAuthMixin¶
You simply need to make your handler extend AppEngineAuthMixin to use it:
from tipfy import RequestHandler, Response
from tipfy.ext.auth import AppEngineAuthMixin, user_required
class MyHandler(RequestHandler, AppEngineAuthMixin):
@user_required
def get(self, **kwargs):
return Response('Only logged in users can see this page.')
That's all. Once you extend the mixin, you have access to the following properties or methods from the handler:
auth_session: the current user from App Engine's Users API, if any, orNoneif no user is logged in.auth_current_user: the loadedUserentity, if the user is logged in and has a record saved in datastore, orNone.auth_is_admin:Trueif the current user is admin,Falseotherwise.auth_login_url(redirect=None): generates a login URL using the URL passed asredirectto redirect to after logging in. Ifredirectis not defined, uses the current URL.auth_logout_url(redirect=None): generates a logout URL using the URL passed asredirectto redirect to after logging in. Ifredirectis not defined, uses the current URL.auth_signup_url(redirect=None): generates a sign up URL using the URL passed asredirectto redirect to after logging in. Ifredirectis not defined, uses the current URL.auth_user_model: it is the configuredUsermodel, as a property.auth_create_user(username, auth_id, **kwargs): saves a newUserentity with the given arguments. You can pass as kwargs any model property. It returns the created entity if it was successful, orNoneif not (most likely because the username is taken).auth_get_user_entity(username=None, auth_id=None): fetches and returns aUserentity using the providedusernameorauth_id. This is used internally during the auth process but you can override it to provide an alternativce loading method and checkings.
MultiAuthMixin¶
This mixin is used to provide access to the user logged in using own authentication or third party services. It also provides functions to validate username and password submitted through a form, set the auth session and logout the user.
Using MultiAuthMixin¶
Your handler must extend MultiAuthMixin and implement
sessions to use own or third party authentication.
Here's an example:
from tipfy import RequestHandler, Response
from tipfy.ext.auth import MultiAuthMixin, user_required
from tipfy.ext.session import SessionMiddleware, SessionMixin
class MyHandler(RequestHandler, SessionMixin, MultiAuthMixin):
middleware = [SessionMiddleware]
@user_required
def get(self, **kwargs):
return Response('Only logged in users can see this page.')
That's all. Once you extend the mixin, you have access to the following properties or methods from the handler:
auth_session: the current auth session data, a dictionary like object. Logged in users have at least three values defined in the session. Different auth providers may add additional values to the session, such as tokens for api requests. The required values are:id: the authentication id.session_id: a unique session token, also stored with the user record.remember: '1' if the session should persist after the user closes the browser, or '0' if not.
auth_current_user: the loadedUserentity, if the user is logged in and has a record saved in datastore, orNone.auth_is_admin:Trueif the current user is admin,Falseotherwise.auth_login_url(redirect=None): generates a login URL using the URL passed asredirectto redirect to after logging in. Ifredirectis not defined, uses the current URL.auth_logout_url(redirect=None): generates a logout URL using the URL passed asredirectto redirect to after logging in. Ifredirectis not defined, uses the current URL.auth_signup_url(redirect=None): generates a sign up URL using the URL passed asredirectto redirect to after logging in. Ifredirectis not defined, uses the current URL.auth_user_model: it is the configuredUsermodel, as a property.auth_create_user(username, auth_id, **kwargs): saves a newUserentity with the given arguments. You can pass as kwargs any model property. It returns the created entity if it was successful, orNoneif not (most likely because the username is taken).auth_get_user_entity(username=None, auth_id=None): fetches and returns aUserentity using the providedusernameorauth_id. This is used internally during the auth process but you can override it to provide an alternativce loading method and checkings.auth_login_with_form(username, password, remember=False): Authenticates the current user using data from a form. ReturnsTrueif authetication is successful,Falseotherwise.auth_login_with_third_party(auth_id, remember=False, **kwargs): Called to authenticate the user after a third party confirmed authentication. This always authenticate a user.auth_set_session(auth_id, session_id=None, remember=False, **kwargs): Sets or renews the auth session.auth_logout(): Logs out the current user. This cleans and deletes the authentication session.
The User model¶
tipfy.ext.auth.model containes a User model that you can use as
it is, extend to add additional properties or use as reference to create your
own user model. An entity from this model is loaded when a user logs in and
is the primary reference for users of your application. The model contains
some basic properties that allows multiple authentication systems to be used.
Restricting access using decorators¶
To restrict access to RequestHandler methods, tipfy.ext.auth provides
three decorators:
@login_required: the method is executed only if the current user is logged in. Otherwise, the user is redirected to the login URL.@user_required: the method is executed only if the current user is logged in and has a record stored in datastore. If not logged in, the user is redirected to the login URL. If logged in but there's no record stored in datastore, the user is redirected to the signup URL.@admin_required: the method is executed only if the current user is logged in and is an admin (theadminproperty must beTruein the user entity). If not logged in, the user is redirected to the login URL. If logged in but there's no record stored in datastore or the user is not admin, aForbiddenexception is raised.
You must apply one of these decorators to every method that you want to restrict access. For example:
from tipfy import RequestHandler, Response
from tipfy.ext.auth import (AppEngineAuthMixin, login_required, user_required,
admin_required)
class MyHandler(RequestHandler, AppEngineAuthMixin):
@login_required
def get(self, **kwargs):
return Response('Only logged in users can see this page.')
@login_required
def post(self, **kwargs):
return Response('Only logged in users can post to this page.')
class MyHandler2(RequestHandler, AppEngineAuthMixin):
@user_required
def get(self, **kwargs):
return Response('Only users with a record stored in datastore can see '
'this page.')
class MyHandler3(RequestHandler, AppEngineAuthMixin):
@admin_required
def get(self, **kwargs):
return Response('Only admins can see this page.')
Restricting access using middleware¶
If you have several handlers that require a logged in user or admin rights, adding a decorator to every method to restrict access will look repetitive and unnecessary. For these cases (think about an admin panel that requires a logged in user for all requests), using a middleware is a better option.
tipfy.ext.auth provides three middleware classes which are equivalent
to the decorators described above, but they apply the restrictions to all
methods in a handler. They are:
LoginRequiredMiddleware: the handler methods are executed only if the current user is logged in. Otherwise, the user is redirected to the login URL.UserRequiredMiddleware: the handler methods are executed only if the current user is logged in and has a record stored in datastore. If not logged in, the user is redirected to the login URL. If logged in but there's no record stored in datastore, the user is redirected to the signup URL.AdminRequiredMiddleware: the handler methods are executed only if the current user is logged in and is an admin (theadminproperty must beTruein the user entity. If not logged in, the user is redirected to the login URL. If logged in but there's no record stored in datastore or the user is not admin, aForbiddenexception is raised.
They are specially useful in base classes: all extended classes will have the restrictions applied. See an example:
from tipfy import RequestHandler, Response
from tipfy.ext.auth import (AppEngineAuthMixin, UserRequiredMiddleware,
admin_required)
class BaseAdminHandler(RequestHandler, AppEngineAuthMixin):
"""Base class for all admin panel handlers."""
middleware = [UserRequiredMiddleware]
class DashboardHandler(BaseAdminHandler):
def get(self, **kwargs):
return Response('Only users with a record can see this page.')
class CalendarHandler(BaseAdminHandler):
def get(self, **kwargs):
return Response('Only users with a record can see this page.')
class ManageUsersHandler(BaseAdminHandler):
@admin_required
def get(self, **kwargs):
return Response('Only admins can see this page.')
In the example above, we set a base handler class that all others extend. All
handlers can only be accessed by logged in users with a record stored in
datastore. You can still apply decorators like @admin_required to special
methods, as we did in the last class.
Extension Reference¶
- Name: tipfy.ext.auth
- Author: Rodrigo Moraes
- License: BSD
- Tags: authentication, users
- URL: http://www.tipfy.org/wiki/extensions/auth/
- PyPi page: http://pypi.python.org/pypi/tipfy.ext.auth/
- Source code: http://code.google.com/p/tipfy-ext-auth/
- Issue tracker: http://code.google.com/p/tipfy-ext-auth/issues/list
- Version: latest
- Edited by voodoonofx on 8/25/10 12:02 AM
- Save on Delicious | Submit to Reddit
- History
- Edit
