PylonsHQ.

Layout: Fixed-width

Simple Homegrown Authentication

Based on an article by Graham Higgins.

Pylons makes it easy to hook functionality into your application. So it's easy to add authentication to your application. This is just a quick recipe to show you how easy it is.

lib/base.py

Add a class variable (here: requires_auth) to your BaseController class. It is set to false by default to declare all controllers as not requiring authentication. It can be set to true for the controllers that you like to be protected. Like:

1
2
3
4
5
class MyController(BaseController):
    requires_auth = True

    def index(self):
        ...

Add a __before__ method to that class that checks whether requires_auth is set to true. It then checks whether a session variable user is set (that is supposed to contain the username of the logged-in user). If it finds that there is no such variable set then the user is redirected to a login controller. For some extra user-friendliness the current path is saved so that the user can return to the actually requested page after the successful login:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class BaseController(WSGIController):
    requires_auth = False

    def __before__(self):
        # Authentication required?
        if self.requires_auth and 'user' not in session:
            # Remember where we came from so that the user can be sent there
            # after a successful login
            session['path_before_login'] = request.path_info
            session.save()
            return redirect_to(h.url_for(controller='login'))

controllers/login.py

Your LoginController just needs to do the authentication. In basic cases it displays a form to read the username and password and to check it against a user database table. Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class LoginController(BaseController):
   def login(self):
       """
       Show login form. Submits to /login/submit
       """
       return render('login.mako')

   def submit(self):
       """
       Verify username and password
       """
       # Both fields filled?
       form_username = str(request.params.get('username'))
       form_password = str(request.params.get('password'))

       # Get user data from database
       db_user = model.WebUser.query(User).get_by(name=form_username)
       if db_user is None: # User does not exist
           return render('login.mako')

       # Wrong password? (MD5 hashes used here)
       if db_user.passwd != md5.md5(form_password).hexdigest():
           return render('login.mako')

       # Mark user as logged in
       session['user'] = form_username
       session.save()

       # Send user back to the page he originally wanted to get to
       if session.get('path_before_login'):
           redirect_to(session['path_before_login'])
       else: # if previous target is unknown just send the user to a welcome page
           return render('loggedin.mako')

   def logout(self):
       """
       Logout the user and display a confirmation message
       """
       if 'user' in session:
           del session['user']
           session.save()
       return render('logout.mako')

lib/base.py

1
2
3
4
5
6
7
8
9
class BaseController(WSGIController):
   requires_auth = []

   def __before__(self, action):
       if action in self.requires_auth:
           if 'user' not in session:
               session['path_before_login'] = request.path_info
               session.save()
               return redirect_to(h.url_for(controller='login'))

controller/my.py

1
2
3
4
5
class MyController(BaseController):
 requires_auth = ['index']

 def index(self):
     pass

Home-grown authorization

The way of authorizing users (to check whether they have certain permission) can be done similarly.

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.

Powered by Pylons - Contact Administrators