python - español - flask>-< restful
Autorización de la API de Frask-restful. Accede a current_identity dentro del decorador. (3)
Aquí está la combinación de Flask-Restful
de Flask-JWT
y Flask-Restful
.
from flask import Flask
from flask_restful import Resource, Api, abort
from functools import wraps
app = Flask(__name__)
api = Api(app)
from flask_jwt import JWT, jwt_required, current_identity
from werkzeug.security import safe_str_cmp
class User(object):
def __init__(self, id, username, password):
self.id = id
self.username = username
self.password = password
def __str__(self):
return "User(id=''%s'')" % self.id
users = [
User(1, ''user1'', ''abcxyz''),
User(2, ''user2'', ''abcxyz''),
]
username_table = {u.username: u for u in users}
userid_table = {u.id: u for u in users}
def authenticate(username, password):
user = username_table.get(username, None)
if user and safe_str_cmp(user.password.encode(''utf-8''), password.encode(''utf-8'')):
return user
def identity(payload):
user_id = payload[''identity'']
return userid_table.get(user_id, None)
app.config[''SECRET_KEY''] = ''super-secret''
jwt = JWT(app, authenticate, identity)
def checkuser(func):
@wraps(func)
def wrapper(*args, **kwargs):
if current_identity.username == ''user1'':
return func(*args, **kwargs)
return abort(401)
return wrapper
class HelloWorld(Resource):
decorators = [checkuser, jwt_required()]
def get(self):
return {''hello'': current_identity.username}
api.add_resource(HelloWorld, ''/'')
if __name__ == ''__main__'':
app.run(debug=True)
ENVIAR
{
"username": "user1",
"password": "abcxyz"
}
Para localhost:5000/auth
y obtener el access_token
en respuesta.
Entonces GET localhost:5000/
con encabezado
Authorization: JWT `the access_token value above`
Obtendrías
{
"hello": "user1"
}
si intenta acceder a localhost:5000/
con el token JWT de user2, obtendría 401
.
Los decoradores se envuelven de esta manera:
for decorator in self.decorators:
resource_func = decorator(resource_func)
https://github.com/flask-restful/flask-restful/blob/master/flask_restful/init.py#L445
Así que el último en la serie de decoradores se ejecuta antes.
Para más referencia:
https://github.com/rchampa/timetable/blob/master/restful/users.py
Utilizo matraz-restful para crear mis APIs. He utilizado flask-jwt
para habilitar la autenticación basada en JWT
. Ahora necesito hacer la autorización.
He intentado poner mi decorador de autorizaciones.
test.py (/ test api)
from flask_restful import Resource
from flask_jwt import jwt_required
from authorization_helper import authorized_api_user_type
class Test(Resource):
decorators = [jwt_required(), authorized_api_user_type()]
def get(self):
return ''GET OK''
def post(self):
return ''POST OK''
Básicamente para manejar la autorización básica, necesito acceder a current_identity
y verificar su tipo. Luego, en función de su tipo, voy a decidir si el usuario está autorizado para acceder a la api / resources.
Pero current_identity
parece estar empty
en ese decorador. Así que para adquirirlo indirectamente, tuve que ver el código de jwt_handler
y hacer lo que se hace allí.
autorizacion_helper.py
from functools import wraps
from flask_jwt import _jwt, JWTError
import jwt
from models import Teacher, Student
def authorized_api_user_type(realm=None, user_type=''teacher''):
def wrapper(fn):
@wraps(fn)
def decorator(*args, **kwargs):
token = _jwt.request_callback()
if token is None:
raise JWTError(''Authorization Required'', ''Request does not contain an access token'',
headers={''WWW-Authenticate'': ''JWT realm="%s"'' % realm})
try:
payload = _jwt.jwt_decode_callback(token)
except jwt.InvalidTokenError as e:
raise JWTError(''Invalid token'', str(e))
identity = _jwt.identity_callback(payload)
if user_type == ''student'' and isinstance(identity, Student):
return fn(*args, **kwargs)
elif user_type == ''teacher'' and isinstance(identity, Teacher):
return fn(*args, **kwargs)
# NOTE - By default JWTError throws 401. We needed 404. Hence status_code=404
raise JWTError(''Unauthorized'',
''You are unauthorized to request the api or access the resource'',
status_code=404)
return decorator
return wrapper
¿Por qué no puedo acceder a current_identity
en authorized_api_user_type
decorator? ¿Cuál es la forma CORRECTA de hacer la autorización en un matraz reparador?
Mi solución actual se ve como:
@app.before_request
def detect_something():
header = request.headers.get(''Authorization'')
if header:
_, token = header.split()
request.identity = identity(jwt.decode(token,
app.config[''SECRET_KEY'']))
Después de esto podemos acceder a la identidad en el decorador a través de la request.identity
. Identidad. Y quité current_identity
todas partes del código. Todavía es un camino desordenado.
Utilizar esta:
from flask_jwt import current_identity
@jwt_required()
def get(self):
return {''current_identity'': current_identity.json()}