Closed ghost closed 6 years ago
My solution to this is a bit clumsy.. cos it means a second trip to the database... but it works..
@jwt.jwt_data_loader
def add_claims_to_access_token(identity):
thisUser = session.query(User).filter_by(user=identity).first()
now = datetime.utcnow()
return {
'exp': now + current_app.config['JWT_EXPIRES'],
'iat': now,
'nbf': now,
'sub': identity,
'roles': thisUser.roles
}
So, now at least when the client (say and Angular app) sends a request, the server doesn't have to go to the database to find out if the user has the required role...
There should not a limitation on what you can pass in as the create_jwt identity. You could pass in the full sqlalchemy user object to the ‘create_jwt’ function, and that would be the object you received in the jwt_data_loader callback, thus preventing the need to hit the database twice.
Hope that helps!
ooh.. ok.. I'm a newbie at python .. am trying this but passing the sqlalchemy user object to create_jwt is giving me errors.. Think its not json serializable so have to figure out how to do that ...
But thanks ! PJ
ps: apologies for python newbieness...
I have it workin like this now..
data = {}
data['user'] = theUser.user
data['roles'] = theUser.roles
json_data = json.dumps(data)
ret = {'jwt': create_jwt(identity=json_data)}
return jsonify(ret), 200
and my protected route can now differentiate ...
app.route('/protected', methods=['GET'])
@jwt_required
def protected():
print '------ protected route accessed ----'
theUser = json.loads(get_jwt()['sub'])
if (theUser['roles'] == 'admin'):
print 'this is an admin'
return jsonify({'hello_from': get_jwt_identity()}), 200
Probably a bit newbie and clumsy.. but it'll do for today..
Another way you could do it would be like this:
@jwt.jwt_data_loader
def add_claims_to_access_token(user): # user is the sqlalchemy user object
now = datetime.utcnow()
return {
'exp': now + current_app.config['JWT_EXPIRES'],
'iat': now,
'nbf': now,
'sub': user.user,
'roles': user.roles
}
@app.route('/login', methods=['POST'])
def login():
username = request.json.get('username', None)
password = request.get('password', None)
user = session.query(User).filter_by(user=identity).first()
# you would need to implement this with however your system is setup
if not validate_password(user, password):
return jsonify({"msg": "Bad username or password"}), 401
ret = {'jwt': create_jwt(identity=user)}
return jsonify(ret), 200
Oh yeah.. thats a lot neater isn't it? Thanks very much for this!
No problem :+1:
Hi, I was hoping to add roles to the token based on what was coming out of my database. I've looked at your example where you use the jwt_data_loader to hardwire a single admin user based on just the identity...
I would need to have more users that may be admins or more roles... and the User object I take from the database contains the list of Roles each user has.
I can't work this way with just the identity and jwt_data_loader.. (I think?)..
Is there some other way to do this? I can't pass the User object to the create...
Can I make a jwt and then add to it?
Thanks