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.