I’ve been creating a python-flask web app based on miguel grinbergs excellent tutorial. It’s not a blog, more of an online ordering system, but needs user and admin access, i.e. different options available for different users, which is not included in that tutorial. I’d been researching Flask-Principal which does fine-grained permissions, but it looked a bit complex, since all I wanted was to put and @decorator in front of certain functions to prevent these pages from showing.
A bit more googling and I discovered this excellent snippet. I’ll explain exactly how I implemented it in my code.
1. In my models.py I have a user class, which has a “role” field.
2. In my views.py which contains all the routes / views into the web app, I have the following:
– Import the wraps class:
from functools import wraps
– A function defintion which will work as a decorator for each view – we can call this with @required_roles. If the required role is not correct, it simply sends a ‘flash’ message which I already have setup and returns the user to the index page. I’m using g.user to handle my current user session.
def required_roles(*roles): def wrapper(f): @wraps(f) def wrapped(*args, **kwargs): if get_current_user_role() not in roles: flash('Authentication error, please check your details and try again','error') return redirect(url_for('index')) return f(*args, **kwargs) return wrapped return wrapper def get_current_user_role(): return g.user.role
3. Finally, for each view, I can add the decorator, for example, I’m only letting users with role=admin access the register new user page:
@app.route('/register' , methods=['GET','POST']) @required_roles('admin') def register():
4. It’s worth noting that although this will restrict the views that can be accessed, there are other considerations for a complete multi-role web app – i.e. you may have a single view / template with different options – in my case the index page can be access by both standard and admin users, but I want the admin users to be able to see a link to register a new user. If I didn’t do this, ALL users would have a link to the register new user page, but only role=admin users would be able to access it. This is pretty easy to acheive in python-flask with the jinja templating engine. I simply include the link inside an if block as follows:
{% if g.user.role == 'admin' %} <!--menu link here --> {% endif %}