Flask-Principal

0.4.0 · deprecated · verified Thu Apr 16

Flask-Principal is an extension for Flask that provides identity management for users, enabling flexible authorization based on 'Needs' and 'Permissions'. The latest stable version is 0.4.0, released in 2012, and the library is largely unmaintained. It uses a signal-based approach to load user identities and their associated permissions.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates how to set up Flask-Principal with an example Flask application. It includes routes for logging in/out, a profile page, and an admin dashboard protected by a 'RoleNeed'. The `identity_changed` signal is used to update the current identity, and `identity_loaded` is used to assign `Needs` (like 'admin' role) to the identity. Ensure `FLASK_SECRET_KEY` is set for production.

import os
from flask import Flask, session, g, redirect, url_for
from flask_principal import Principal, Identity, AnonymousIdentity, \
                            identity_changed, identity_loaded, \
                            current_identity, \
                            Need, UserNeed, RoleNeed, Permission

# Initialize Flask app
app = Flask(__name__)
app.secret_key = os.environ.get('FLASK_SECRET_KEY', 'default_secret_key')

# Initialize Flask-Principal
principals = Principal(app)

# Define a permission for 'admin' role
admin_permission = Permission(RoleNeed('admin'))

@app.before_request
def load_identity_from_session():
    # Load identity from session or create an anonymous one
    if 'identity_id' in session:
        g.identity = Identity(session['identity_id'])
        # Signal that the identity has loaded
        identity_changed.send(app, identity=g.identity)
    else:
        g.identity = AnonymousIdentity()

@identity_loaded.connect_via(app)
def on_identity_loaded(sender, identity):
    # This signal is fired when an identity is loaded (or changed)
    # Use this to add Needs to the identity based on your application logic
    if identity.id:
        # Example: user_id 1 is an admin, others are regular users
        if identity.id == 1:
            identity.provides.add(RoleNeed('admin'))
        identity.provides.add(UserNeed(identity.id)) # All logged-in users get their UserNeed
    # For anonymous users, no specific Needs are added here by default

@app.route('/login/<int:user_id>')
def login(user_id):
    # Simulate a login: set identity in session and emit signal
    session['identity_id'] = user_id
    identity_changed.send(app, identity=Identity(user_id))
    return f'Logged in as User {user_id}. <a href="{url_for("profile")}">Go to profile</a> <a href="{url_for("admin_dashboard")}">Go to admin dashboard</a>'

@app.route('/logout')
def logout():
    # Simulate a logout: clear session and emit anonymous identity signal
    if 'identity_id' in session:
        del session['identity_id']
    identity_changed.send(app, identity=AnonymousIdentity())
    return 'Logged out. <a href="{url_for("profile")}">Go to profile</a>'

@app.route('/')
@app.route('/profile')
def profile():
    if current_identity.is_authenticated():
        return f'Hello, User {current_identity.id}! You are authenticated.' \
               f' Role: {"Admin" if admin_permission.can() else "User"}.'
    return 'Hello, Anonymous User! You are not logged in.'

@app.route('/admin')
@admin_permission.require() # This decorator enforces the 'admin' permission
def admin_dashboard():
    return f'Welcome to the Admin Dashboard, User {current_identity.id}!'

if __name__ == '__main__':
    # For local testing, ensure a secret key is set
    if 'FLASK_SECRET_KEY' not in os.environ:
        print("WARNING: FLASK_SECRET_KEY environment variable not set. Using a default for demonstration.")
    app.run(debug=True)

view raw JSON →