Python 使用restful API授权。访问装饰器内的当前_标识

Python 使用restful API授权。访问装饰器内的当前_标识,python,flask,flask-restful,flask-jwt,Python,Flask,Flask Restful,Flask Jwt,我使用flask restful创建API。我使用了jwt来启用基于jwt的身份验证。现在我需要做授权 我试着把我的授权放在装饰器上 test.py(/test-api) 基本上,为了处理基本授权,我需要访问当前\u标识,并检查其类型。然后根据它的类型,我将决定用户是否有权访问api/资源 但是当前\u标识在该装饰器中似乎是空的。因此,为了间接获得它,我必须查看jwt_handler的代码,并在那里做一些事情 授权\u helper.py from functools import wraps

我使用flask restful创建API。我使用了
jwt
来启用基于
jwt
的身份验证。现在我需要做授权

我试着把我的授权放在装饰器上

test.py(/test-api)


基本上,为了处理基本授权,我需要访问
当前\u标识
,并检查其类型。然后根据它的类型,我将决定用户是否有权访问api/资源


但是
当前\u标识
在该装饰器中似乎是
空的
。因此,为了间接获得它,我必须查看
jwt_handler
的代码,并在那里做一些事情

授权\u 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

为什么我不能在我的
authorized\u api\u user\u type
decorator中访问
current\u identity
?在flask restful中进行授权的正确方法是什么?

我当前的解决方案如下所示:

@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']))

之后,我们可以通过
request.identity
访问decorator中的标识。我从代码中删除了
current_identity
。这条路还是很乱

这里是
Flask JWT
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)
职位

localhost:5000/auth
并获取
access\u令牌作为响应

然后获取带有标题的
localhost:5000/

Authorization: JWT `the access_token value above`
你会得到

{
  "hello": "user1"
}
如果您尝试使用user2的JWT令牌访问
localhost:5000/
,您将得到
401

装饰器的包装方式如下:

for decorator in self.decorators:
    resource_func = decorator(resource_func)

因此,decorators数组中的后一个可以更早地运行

更多参考:

使用以下方法:

from flask_jwt import current_identity
@jwt_required()
def get(self):
    return {'current_identity': current_identity.json()}

你们读过这个问题吗?问题是如何在decorator中访问
current\u identity
current\u identity
如果由
jwt\u required
decorator包装,则可以访问。为什么你需要一个定制的装饰器?装饰器可以用于许多情况。例如-检测用户的角色。为了避免在所有视图中重写代码,您可以创建类似“detect_role”的装饰器。请阅读OP的全部问题。好的,我明白你的意思。我会尽快解决这个问题(在我自己的项目中)。我已经阅读了
jwt\u required
的源代码,当前的\u标识被注入其中的堆栈中。因此,对于您自己的decorator,我认为如果遵循
jwt\u required
@NikolayFominyh,当前的\u标识是可以访问的。我已经用一个自定义的decorator编辑了我的示例,其中包含当前的\u标识。希望它能让您满意,:)在回答线程时,最好避免使用某些短语,如“试试这个”、“使用这个”等。至于2020年,这个解决方案将不起作用。并将产生:TypeError:jwt_required()缺少1个必需的位置参数:“fn”什么是混乱的方式?你的建议是什么?
for decorator in self.decorators:
    resource_func = decorator(resource_func)
from flask_jwt import current_identity
@jwt_required()
def get(self):
    return {'current_identity': current_identity.json()}