2015-12-11 14 views
19

Tôi sử dụng bình tĩnh để tạo API của mình. Tôi đã sử dụng flask-jwt để bật xác thực dựa trên JWT. Bây giờ tôi cần phải làm ủy quyền.Cấp quyền sử dụng API Flask-restful. Truy cập current_identity bên trong trang trí

Tôi đã thử đặt trang trí ủy quyền của mình.

test.py (/ kiểm tra 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' 

Về cơ bản để xử lý uỷ quyền cơ bản, tôi cần phải truy cập current_identity và kiểm tra xem nó là loại. Sau đó, dựa trên kiểu của nó, tôi sẽ quyết định liệu người dùng có được phép truy cập vào api/resources hay không.

Nhưng current_identity dường như là empty trong trình trang trí đó. Vì vậy, để có được nó gián tiếp, tôi đã phải xem mã số jwt_handler và làm điều được thực hiện ở đó.

authorization_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 

Tại sao tôi không thể truy cập chỉ current_identity trong authorized_api_user_type trang trí của tôi? Cách thức PHẢI cấp phép trong bình yên tĩnh là gì?

Trả lời

11

Đây là sự kết hợp của quickstarts của cả hai Flask-JWTFlask-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) 

POST

{ 
    "username": "user1", 
    "password": "abcxyz" 
} 

Để localhost:5000/auth và nhận được access_token trong phản ứng.

Sau đó GET localhost:5000/ với tiêu đề

Authorization: JWT `the access_token value above` 

Bạn sẽ nhận được

{ 
    "hello": "user1" 
} 

nếu bạn cố gắng truy cập vào localhost:5000/ với token JWT của user2, bạn sẽ nhận được 401.

Các trang trí được gói theo cách này:

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

https://github.com/flask-restful/flask-restful/blob/master/flask_restful/init.py#L445

Vì vậy, một trong những sau này trong các mảng trang trí được chạy trước đó.

Để tham khảo hơn:

https://github.com/rchampa/timetable/blob/master/restful/users.py

https://github.com/mattupstate/flask-jwt/issues/37

+0

Các bạn đã đọc câu hỏi? Câu hỏi là về truy cập 'current_identity' trong trang trí. –

+0

'current_identity' có thể truy cập được nếu được trang trí bởi trình trang trí' jwt_required'. Tại sao bạn cần một trang trí tùy chỉnh? – aGuegu

+0

Trang trí có thể được sử dụng cho một số trường hợp. Ví dụ - để phát hiện vai trò của người dùng. Để tránh viết lại mã bên trong tất cả các chế độ xem của bạn, bạn có thể tạo trình trang trí như "detect_role". Xin vui lòng, đọc toàn bộ câu hỏi từ OP. –

3

giải pháp hiện tại của tôi trông giống như:

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

Sau đó chúng ta có thể truy cập vào bản sắc trong trang trí qua request.identity. Và tôi đã xóa current_identity ở mọi nơi khỏi mã. Đó vẫn là cách lộn xộn.

-1

Sử dụng này:

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

Trong khi trả lời các chủ đề, bạn nên tránh những cụm từ nhất định như "thử cái này", "dùng cái này" vv –

Các vấn đề liên quan