Flask restx Debug «Несанкционированный» ответ
У меня есть приложение Flask (2.2.3) с Flask-RESTX (1.1.0), используемое в качестве API (без внешнего интерфейса). Я использую библиотеку flask-azure-oauth для аутентификации пользователей с помощью Azure AD. Настройка:
from flask import Flask, current_app
from flask_azure_oauth import FlaskAzureOauth
from flask_restx import Api
app = Flask(__name__)
api = Api(app, <...>)
CORS(app)
auth = FlaskAzureOauth()
auth.init_app(app)
# App routes
@api.route("/foo")
class FooCollection(Resource):
@auth('my_role')
def get(self):
return [<...>]
Это работало нормально, но через несколько дней я начал получать несанкционированные ответы при передаче действующего токена. К сожалению, я не могу отследить причину: токены кажутся в порядке (проверяются вручную или декодируются с помощью jwt.ms), и единственный ответ, который я получил от API:401 UNAUTHORIZED
с телом ответа{ "message": null }
.
Я попытался добавить журнал ошибок и обработчики ошибок:
# Logging request/response
@app.before_request
def log_request_info():
app.logger.debug(f"{request.method} {request.path} {request.data}")
@app.after_request
def log_response_info(response):
app.logger.debug(f"{response.status}")
return response
# Error handling
@app.errorhandler(Unauthorized)
def handle_error(error):
current_app.logger.debug(f"Oops")
<...>
@app.errorhandler
def handle_error(error):
current_app.logger.debug(f"Noooo...!")
<...>
При этом запросы и ответы регистрируются, а исключения, не относящиеся к HTTP, обрабатываютсяhandle_error
. Но ошибки HTTP, такие как 404, 401,... просто проходят мимо, игнорируемые как общим обработчиком ошибок, так и конкретным (@app.errorhandler(Unauthorized)
).
Вот код, используемый для проверки этого:
from werkzeug.exceptions import Unauthorized
def unauth():
def decorator(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
raise Unauthorized("No-no") # <<<
return wrapper
return decorator
@api.route("/dummy")
class Dummy(Resource):
@unauth()
def get(self):
return jsonify(message="Hello there!")
@app.errorhandler
def handle_error(Exception):
current_app.logger.debug("Intercepted")
Фиктивный маршрут защищенunauth
декоратор, который отклоняет все запросы с кодом 401 — НЕАВТОРИЗОВАННО, и это именно то, что получает клиент. Однако@app.errorhandler(Exception)
, который должен перехватывать ВСЕ исключения, все равно его не пропускает. Заменятьraise Unauthorized
с чем-то вроде1 / 0
и исключение обычно будет перехвачено. Ошибки HTTP получают специальную обработку!
Так как же мне правильно их перехватить и изучить? (с акцентом на: как мне узнать, почему было отказано в авторизации токена)
1 ответ
Учетные данные OAuth имеют пожизненный срок действия. Похоже, срок действия вашего токена истек, и вы используете его, не обновляя.
Я бы порекомендовал прочитать сценарий веб-приложения, которое регистрирует пользователей из Microsoft.
Если вы посмотрите документацию Microsoft по токенам доступа , вы увидите, что у каждого токена есть срок жизни . Когда этот срок действия истечет, вам придется запросить новый токен, используя токен обновления , который был бы вам предоставлен, когда вы впервые получили токен доступа (тот, который вы сейчас предоставляете для аутентификации).
Хорошие клиенты обычно автоматически обновляют токены (или пользователи могут просто снова войти в систему после истечения срока действия токена). Поскольку у вас еще нет клиента (Frontend), вам придется сделать это вручную. Существует хорошая документация от Microsoft о том, как получить новый токен доступа с помощью токена обновления .
Что касается того, почему ваши ошибки не обнаруживаются, это потому, чтоFlaskAzureOauth
имеет свою собственную оберткуwerkzeug.exceptions.HTTPException
, который вызывается в случае каких-либо ошибок со стороны Azure. Я бы посоветовал вам попробовать добавить обработчик ошибок дляflask_azure_oauth.errors._HTTPException
и посмотреть, поймает ли он его. Однако я не уверен на 100%, что это произойдет, поскольку код аутентификации и авторизации выполняется до запуска кода API, и я не уверен, что Flaskerrorhandler
s принять этот код во внимание.