Anybody know of a good tutorial about flask-principal? I'm trying to do authentication and authorization (needRole and needIdentity) and I haven't gotten anywhere.
I am almost sure there's no really comprehensive tutorial -- maybe some of you has some time on their hands and would like to post a tutorial-as-answer? I'm REALLY determined to use flask instead of django but need to fix this.
I know this question is kind of old, but a couple of days ago I was looking for the same thing so hopefully this will help someone in the future . . .
A good place to start is on the github repo for Flask-Principal.
I've had some trouble with Flask-Principal (FP) too. If you're new to decorators, context-managers, and signals you'll probably want to research them a little before using FP.
Flask registers signals based on a package called Blinker. If you don't have Blinker, Flask will still allow you to declare signals however they won't do anything. To see what I mean, have a look in the source for Flask's signals.py.
So why does this matter for FP? Well, it turns out that FP uses signals to register and update identities. Specifically:
identity_loaded
: When this signal is called, we know to create an identity object for the user. (It's called via Principal._set_thread_identity()
)
identity_changed
: When this signal is called, we know to update the user's identity. (When it's called it executes Principal._on_identity_changed()
)
So what do I mean by called? First, we need to know how signals are set up. Blinker works by allowing functions to "subscribe" to signals. So, for example, Principal._on_identity_changed()
is set up as a subscriber for the signal identity_changed
. Whenever the signal identity_changed
is sent, _on_identity_changed() is executed. The code looks like this:
from blinker import signal
test = signal('test')
test.connect(func_we_want_to_execute_when_signal_is_called)
Back to the question of how signals are called. In Blinker, signals handlers are executed when we call send()
on the signal object. So for our test
signal, the syntax is just:
test.send()
When test.send()
is called func_we_want_to_execute_when_signal_is_called
will execute. Hopefully this example in the FP documentation makes a bit more sense now:
def login_view(req):
username = req.form.get('username')
# Your authentication here.
# Notice our signal (identity_changed) is being called (identity_changed.send())
# What function is being called? Principal._on_identity_changed()
identity_changed.send(app, identity=Identity(username))
However we can simplify setting up signals if we use a decorator to do it for us. Pretend again that I've set up my test signal but haven't connected it. We can do:
@test.connect
def func_we_want_to_execute_when_signal_is_called():
return stuff
What the above code does is essentially sets up the function we want to execute when our test signal is sent. Hopefully now the following code from the FP documentation makes sense:
# We're setting up our signal (identity_loaded)
# to execute the function below (on_identity_loaded)
# when we call our signal (identity_loaded.send())
# which is called in Principal._set_thread_identity()
@identity_loaded.connect
def on_identity_loaded(sender, identity):
# Get the user information from the db
user = db.get(identity.name)
# Update the roles that a user can provide
for role in user.roles:
identity.provides.add(RoleNeed(role.name))
# Save the user somewhere so we only look it up once
identity.user = user
So you can see that signals really drive the identity process. Roles and permissions are really an (easier) afterthought if you're looking for a way to do authorization of any kind.
For me, wrapping my head around signals was the hardest part; I hope this was helpful for someone else, too. But I'd really encourage you to read through the source code I've linked above for Flask-Principal; it is probably going to be the best way to understand what is going on.