This a continuation of the original post about authentication in web2py, I decided to roll out my own authentication schema for web2py, it works pretty well actually and support several decorators to make your life a little easier, for example:
@auth_user.requires_login()
def index():
# Do your stuff here
Now anyone that accesses the index controller will be "redirected" (or any action that you want to provide) if the use is not "logged in".
# Custom Authentication Class
# Implementation similar to gluon.tools
##db=SQLDB("mysql://dbuser:dbpasswd@serverloc:port/db")
from gluon.html import URL
from gluon.http import redirect
import sha
class CustomAuthentication(object):
""" Role-Based authentication module """
def __init__(self, request, response, session, cache, T, db):
self.request = request
self.response = response
self.session = session
self.cache = cache
self.T = T
self.db = db
self._anonymous_user = 'Anonymous User'
def __call__(self):
""" Returns the username """
_auth_name = self.session.auth_alias
if _auth_name is None:
_auth_name = self._anonymous_user
return _auth_name
def authenticate(self, auth_alias, auth_passwd):
""" sets authentication for the user """
auth = False
self.logout() # Clear up previous session if any
hash_pwd = sha.new(auth_passwd).hexdigest()
rows = self.db((self.db.auth_users.auth_alias==auth_alias) & (self.db.auth_users.auth_passwd==hash_pwd) & (self.db.auth_users.is_enabled==True)).select()
if rows:
self.session.auth_alias = auth_alias
auth = True
return auth
def logout(self):
""" Clear the session """
self.session.auth_alias = None
def has_role(self, roles):
""" Receives a comma-separated string containing the roles to check and will return True if the user contains any of the passed roles """
hasrole = False
roles_to_check = roles.split(',')
roles_found = []
if self.is_auth():
auth_alias = self.session.auth_alias
# select
# ar.auth_role_name
# from
# auth_roles as ar,
# auth_user_role as aur,
# auth_users as au
# where
# au.auth_alias = %(auth_alias)s
# and au.id = aur.auth_user_id
# and aur.auth_role_id = ar.id
user_roles = self.db((self.db.auth_users.auth_alias == auth_alias) &\
(self.db.auth_users.id == self.db.auth_user_role.auth_user_id) &\
(self.db.auth_user_role.auth_role_id == self.db.auth_roles.id)).select(self.db.auth_roles.auth_role_name)
if user_roles:
roles_found = [each_role for each_role in user_roles if each_role.auth_role_name in roles_to_check]
if roles_found:
hasrole = True
return hasrole
def get_roles(self):
""" Returns a list of roles the user belongs to """
roles = []
if self.is_auth():
auth_alias = self.get_user_name()
user_roles = self.db((self.db.auth_users.auth_alias==auth_alias) &\
(self.db.auth_users.id==self.db.auth_user_role.auth_user_id) &\
(self.db.auth_user_role.auth_role_id==self.db.auth_roles.id)).select(self.db.auth_roles.auth_role_name)
if user_roles:
roles = [each_role.auth_role_name for each_role in user_roles]
return roles
def get_user_name(self):
""" same as __call__ - returns the username (alias) """
_auth_name = self.session.auth_alias
if _auth_name is None:
_auth_name = self._anonymous_user
return _auth_name
def get_user_email(self):
""" If auth, gets the user alias from the database """
if self.is_auth():
user_email = self.db(self.db.auth_users.auth_alias==self.get_user_name()).select(self.db.auth_users.auth_email)[0].auth_email
else:
user_email = None
return user_email
def is_auth(self):
""" True if the user has been authenticated in the system, false otherwise """
return self.session.auth_alias is not None
def is_admin(self):
""" This is a hack-y method (or shortcut) that can become useful in the future if the
developer decides that "zAdministrator" should not be the only "admin" in the system """
return self.has_role('zAdministrator') # Add "more" as needed
def requires_login(self):
""" Decorator Helper to aid in determine whether a controller needs specific access """
def wrapper(func):
def f(*args, **kwargs):
if not self.is_auth():
return redirect(URL(r=self.request, c='default', f='login'))
return func(*args, **kwargs)
return f
return wrapper
def requires_role(self, roles):
""" Decorator Helper to aid in determine whether a controller needs specific access """
def wrapper(func):
def f(*args, **kwargs):
if not self.has_role(roles):
return redirect(URL(r=self.request, c='default', f='login'))
return func(*args, **kwargs)
return f
return wrapper
# Instantiate our authentication object, visible throughout all applications (If this is put in the Models section, that is).
# auth_user = CustomAuthentication(request, response, session, cache, T, db)

