web2py

web2pyTM Tools

Since version 1.56 web2py includes tools for authentication, authorization, CRUD, and more. They are implemented so that they do not require JOINs and work on Google App Engine as well.

Authentication

The basic authentication tool is the Auth class. It provides methods that can be used as controller actions to register users (with optional Recaptcha support), log them in and out, allow email verification, password change, password reset and retrieval, editing user profile.

These functionalities can then be used as the basis for authorization.

The Auth calls can be extended, personalized, and replaced by other authentication mechanisms which expose a similar interface.

To use authentication, write something like this in a model file:

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
from gluon.tools import Mail, Auth, Recaptcha

mail=Mail()
## specify your SMTP server
mail.settings.server = 'smtp.yourdomain.com:25'
## specify your email address
mail.settings.sender = 'you@yourdomain.com'
## optional: specify the username and password for SMTP
mail.settings.login = 'username@password'

## instantiate the Auth class (or your derived class)
auth = Auth(globals(), db)
## ask it to create all necessary tables
auth.define_tables()
## optional: require email verification for registration
# auth.settings.mailer = mail
## optional: if you require captcha verification for registration
# auth.settings.captcha = Recaptcha(request,public_key='RECAPTCHA_PUBLIC_KEY',private_key='RECAPTCHA_PRIVATE_KEY')

In your controller (for example in default.py) expose the auth object (for example via a user action):

1.
2.
def user():
return dict(form = auth())

The above action will expose the following URLs

  • http://locahost:8000/application/default/user/register
  • http://locahost:8000/application/default/user/login
  • http://locahost:8000/application/default/user/logout
  • http://locahost:8000/application/default/user/verify_email
  • http://locahost:8000/application/default/user/profile
  • http://locahost:8000/application/default/user/change_password
  • http://locahost:8000/application/default/user/retrieve_password
  • http://locahost:8000/application/default/user/groups

The groups page shows a list of roles and description for the groups the logged-in user is a member of (see authorization).

You can check if a user is logged in via auth.is_logged_in(). If a user is logged in its record information can be found in auth.user. By default a user is stored in a table called "auth_user" and has the following columns: first_name, last_name, email, password. Password is stored encrypted (md5 hashed or stronger). You can change the table name, define your own table with more fields, require additional validators.

All authentication events are logged in a table called "auth_event".

Custom Authentication

You can customize the Auth class by extending it. Here is an example of code you can put in your model to include internationalization for authentication messages:

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
from gluon.tools import Auth
class MyAuth(Auth):
def __init__(self, environment, T, db = None):
"Initialise parent class & make any necessary modifications"
Auth.__init__(self,environment,db)
self.messages.logged_in = T("Logged in")
self.messages.email_sent = T("Email sent")
self.messages.email_verified = T("Email verified")
self.messages.logged_out = T("Logged out")
self.messages.registration_successful = T("Registration successful")
self.messages.invalid_email = T("Invalid email")
self.messages.invalid_login = T("Invalid login")
self.messages.verify_email_subject = T("Password verify")
self.messages.username_sent = T("Your username was emailed to you")
self.messages.new_password_sent = T("A new password was emailed to you")
self.messages.password_changed = T("Password changed")
self.messages.retrieve_username=str(T("Your username is"))+": %(username)s"
self.messages.retrieve_username_subject="Username retrieve"
self.messages.retrieve_password=str(T("Your password is"))+": %(password)s"
self.messages.retrieve_password_subject = T("Password retrieve")
self.messages.profile_updated = T("Profile updated")

auth = MyAuth(globals(), T, db)

Views are handled the usual web2py way.

Authorization

Once you have a user identified by user.id, you can create a group (for example "Manager")


group_id = auth.add_group(role = "Manager", description = "example of a group")

make the user a member:


auth.add_membership(group_id,user_id)

and assign permissions to all members of the group:


auth.add_permission(group_id,'create','tablename',record_id)

Now you can enforce permissions using the following decorators:

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
auth.settings.on_failed_authorization=URL(r=request,f='error')

@auth.requires_login():
def some_function1():
return dict()

@auth.requires_membership('Manager'):
def some_function2():
return dict()

@auth.requires_permission('create','tablename',1):
def some_function3():
return dict()

def error():
return dict(message = T("not authorized"))

Group roles are conventional. Permission names are also conventional. If one group has a certain permission on record_id==0 (default), it means the user has the permission on any record.

Some permission names ("tables", "select", "create", "update", "delete", "read") have a special meaning because they can be automatically enforced by the CRUD tool described below.

Create/Read/Update/Delete and more

To use CRUD, in your model insert the following code:

1.
2.
from gluon.tools import Crud
crud = Crud(globals(),db)

and in a controller (for example in default.py) expose it via an action (for example data):

1.
2.
3.
4.
5.
def data():
return dict(form = crud())

def download():
return response.download(request, db)

This will expose the following URLs:

  • http://locahost:8000/application/default/data/tables
  • http://locahost:8000/application/default/data/select/tablename
  • http://locahost:8000/application/default/data/create/tablename
  • http://locahost:8000/application/default/data/read/tablename/record_id
  • http://locahost:8000/application/default/data/update/tablename/record_id
  • http://locahost:8000/application/default/data/delete/tablename/record_id
  • http://locahost:8000/application/default/download/filename

"tables" list of current database tables.

"download" only allows to download uploaded files (whether they are in the uploads folder or in the database).

To enforce authorization on these CRUD URLs simply set

1.
crud.settings.auth=auth

and the logged in user will only be able to "create" a record in table "tablename" if the user is a member of a group that has "create" permission on table "tablename". The same mechanism works for tables, select, read, update, and delete URLs.

Fetch a URL

The Python module urllib does not work well on the Google App Engine. For this reason we created a portable function for fetching url that works everywhere, including GAE:

1.
2.
from gluon.tools import fetch
html = fetch("http://www.web2py.com")

Geocoding

Another very common need of modern web applications is that of converting an address into latitude and longitude. We also provide a portable function to do it that uses the Google Geocoding API:

1.
2.
from gluon.tools import geocode
(latitude, longitude) = geocode("243 S Wabash Ave, Chicago IL 60604, USA")

It returns 0,0 on failure.