Использование ролей Flask-Security с API REST Flask-JWT

Я создаю основанный на Flask REST API и использую Flask-JWT для обработки аутентификации JWT. Я также хочу использовать встроенное управление ролями с Flask-Security. Тем не менее, декоратор @roles_required() Flask-Security предполагает, что в случае сбоя отображается окно Flask.

Вот моя конечная точка токена (которая работает так, как я хочу):

$ http POST localhost:5000/auth/token username='test' password='test'
HTTP/1.0 200 OK
Content-Length: 192
Content-Type: application/json
Date: Sun, 08 Nov 2015 17:45:46 GMT
Server: Werkzeug/0.10.4 Python/3.5.0

{
    "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE0NDcwMDQ3NDYsIm5iZiI6MTQ0NzAwNDc0NiwiZXhwIjoxNDQ3MDA1MDQ2LCJpZGVudGl0eSI6MX0.RFIeaLuvJNM9fDjFYFQ7sh_WaDVU-_aM7e46tVJzlBQ"
}

Вот успешный ответ на ресурс, который не имеет никаких требований к роли (используя только @jwt_required). Это также работает так, как я хочу:

$http GET localhost:5000/protected Authorization:'JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE0NDcwMDQ3NDYsIm5iZiI6MTQ0NzAwNDc0NiwiZXhwIjoxNDQ3MDA1MDQ2LCJpZGVudGl0eSI6MX0.RFIeaLuvJNM9fDjFYFQ7sh_WaDVU-_aM7e46tVJzlBQ'
HTTP/1.0 200 OK
Content-Length: 25
Content-Type: text/html; charset=utf-8
Date: Sun, 08 Nov 2015 17:46:24 GMT
Server: Werkzeug/0.10.4 Python/3.5.0

<models.User[email=test]>

Когда я делаю то же самое для ресурса, для которого требуются роли (например, admin в этом примере), кажется, что у меня есть страница для отображения, такая как /login, которую я не делаю, так как это безголовый REST API:

$ http GET localhost:5000/admin Authorization:'JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE0NDcwMDQ3NDYsIm5iZiI6MTQ0NzAwNDc0NiwiZXhwIjoxNDQ3MDA1MDQ2LCJpZGVudGl0eSI6MX0.RFIeaLuvJNM9fDjFYFQ7sh_WaDVU-_aM7e46tVJzlBQ'
HTTP/1.0 302 FOUND
Content-Length: 209
Content-Type: text/html; charset=utf-8
Date: Sun, 08 Nov 2015 17:46:43 GMT
Location: http://localhost:5000/
Server: Werkzeug/0.10.4 Python/3.5.0
Set-Cookie: session=eyJfZmxhc2hlcyI6W3siIHQiOlsiZXJyb3IiLCJZb3UgZG8gbm90IGhhdmUgcGVybWlzc2lvbiB0byB2aWV3IHRoaXMgcmVzb3VyY2UuIl19XX0.CSEcAw.pjwXLeSWUsORXR-OU5AfFvq6ESg; HttpOnly; Path=/

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>Redirecting...</title>
<h1>Redirecting...</h1>
<p>You should be redirected automatically to target URL: <a href="/">/</a>.  If not click the link.

Я знаю, что Flask-Security использует Flask-Principal за сценой для управления своими ролями (@roles_required и т. Д.), И он связывается с RoleMixin и UserMixin для хранилища данных, что очень хорошо. Однако, если нет способа заставить Flask-Security просто пропустить ресурс без использования моего заголовка JWT, тогда, возможно, лучше всего создать свои собственные декораторы, которые используют Flask-Principal для управления ролями.

У кого-нибудь есть опыт с этим? Идея заключается в том, что весь интерфейс может и будет построен на любом языке, который нам нужен, и это означает, что это могут быть не шаблоны / представления Flask, как это делает Flask-Security.

Спасибо за любую информацию, которую может предоставить каждый!

0 ответов

Вместо перенаправления вы захотите ответить кодом состояния HTTP 403.

Лучше всего создать собственный декоратор для управления ролями и отказаться от использования Flask-Security целиком.

Автор Flask-Security упомянул, что есть более эффективные способы защиты API, и это имеет еще больший смысл, поскольку библиотека не поддерживается.

Flask-JWT или Flask-JWT-Extendedявляются идеальными кандидатами для этой задачи. Для первого потребовалось бы немного больше шаблонов, чтобы все заработало. Существует устаревший PR, предлагающий API для поддержки ролей, который вы могли бы использовать для создания своего собственного декоратора, если решите пойти сFlask-JWT.

В Flask-JWT-Extendedдокументы предлагают более простое решение, которое может соответствовать вашему случаю. Вы должны следовать разделу документации о пользовательских декораторах для получения полного примера, но вот вкратце декоратор:

from functools import wraps

from flask import jsonify
from flask_jwt_extended import (
    verify_jwt_in_request, get_jwt_claims
)

def admin_required(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        verify_jwt_in_request()
        claims = get_jwt_claims()
        if claims['roles'] != 'admin':
            return jsonify(msg='Admins only!'), 403
        else:
            return fn(*args, **kwargs)
    return wrapper

Этот код ищет roles претензии в JWT и возвращает ответ 403, если это не так. admin.

Другие вопросы по тегам