Historically AuthKit has been the typical solution
for authentication and authorization needs in Pylons applications. Unfortunately
the version 0.3 has a few bugs like problems with Unicode strings. Version 0.4
is in the making but not yet finished. Most of the documentation that is floating
around doesn't match either version properly. At the moment (August 2007) AuthKit
should probably be avoided. It is definitely worth a look in the future because it
include different ways of authentication (like OpenID) and works as a proper
WSGI middleware layer.
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.
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'))
|
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')
|
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'))
|
1
2
3
4
5 | class MyController(BaseController):
requires_auth = ['index']
def index(self):
pass
|
The way of authorizing users (to check whether they have certain permission)
can be done similarly.
Could someone clarify what "session" is?
I often see SqlAlchemy 'Session', beaker 'session', and random 'session' items. This is a bit unclear.