views:

121

answers:

1

I'm trying to write a simple decorator to check the authentication of a user, and to redirect to the login page if s/he is not authenticated:

def authenticate(f):
    try:
        if user['authenticated'] is True:
            return f
    except:
        redirect_to(controller='login', action='index')

class IndexController(BaseController):
    @authenticate
    def index(self):
        return render('/index.mako' )

But this approach doesn't work. When a user is authenticated, everything is fine. But when the user is not authenticated, redirect_to() doesn't work and I am given this error:

HTTPFound: 302 Found Content-Type: text/html; charset=UTF-8 Content-Length: 0 location: /login

Thank for your help!

+3  A: 

i don't know pylons, but it seems the way you wrote your decorator is not good.

a decorator is a callable which must return a callable. the decorator is called at the moment the function is defined, and it should return a callable (generally a function) which will be called in place of the function being decorated.

in your sample, your decorator returns a callable only if the user is authenticated at the moment the index() function is defined.

try rewriting it this way:

def authenticate(func):
    def call(*args, **kwargs):
        if user['authenticated'] is True:
            return func(*args,**kwargs)
        else:
            return redirect_to(controller='login', action='index')
    return call

here, authenticate() defines an inner function, which is returned in place of the function it decorates. now when you decorate a function using this decorator:

@authenticate
def index(self):
    return render('/index.mako' )

this means that each time you call index(), you are in fact calling the inner function declared in your decorator.

you should note that: due to the way functions are defined in python, the function object returned by the decorator still remembers the value of arguments of the function in which it was defined. call() still knows about the argument func which was passed when the decorator was called. (this is called a closure)

decorators are difficult to understand although they are not complicated. you should search google for a tutorial on decorators: there are plenty of them which gives a very nice understanding of the concept, far much clearer than the python documentation.

Adrien Plisson
This was so helpful. Thank you very much!
ensnare