Я пишу бэкэнд Flask для обслуживания RESTful API с аутентификацией через JWT.
Я использую Flask-Admin для администратора и, чтобы использовать один метод аутентификации, я хотел бы использоватьJWT аутентификация с ним тоже.
Я добавил в Flask-Admin простую форму входа, которая устанавливает маркеры JWT в файлах cookie.
Маркеры JWT находятся и правильно декодируются в запросе в методе create_form
моегоsqla.ModelView
, но при публикации формы (нажав на кнопку save
в моей форме создания, я получаю сообщение об ошибке 401: "Отсутствует токен CSRF в заголовках .
Кто угодно можетhelp?
Маршрут входа в систему
@bp_api.route('/api/user/login', methods=('POST',))
def login():
data = request.json
web = request.args.get('web', 0, type=int)
user = User.query.filter(User.username==data['username']).first()
if not user:
return jsonify({'msg': 'User {} doesn\'t exist'.format(data['username'])}), 400
if not user.confirmed_on:
return jsonify({'msg': f'{user.email} not confirmed'}), 400
if check_password_hash(user.password, data['password']):
access_token = create_access_token(identity = data['username'], fresh=True)
refresh_token = create_refresh_token(identity = data['username'])
if web:
resp = jsonify({'username': f'{user.username}'})
set_access_cookies(resp, access_token)
set_refresh_cookies(resp, refresh_token)
else:
resp = jsonify({'msg':f'Logged as {user.username}',
'access_token': access_token, 'refresh_token': refresh_token}
)
return resp, 200
else:
return jsonify({'msg': 'Invalid password.'}), 401
Просмотр Flask-Admin
from flask_admin.base import BaseView
from flask_admin.contrib import sqla
from flask_jwt_extended import (
get_current_user,
get_jwt_identity,
jwt_required,
verify_jwt_in_request,
verify_jwt_refresh_token_in_request,
create_access_token,
set_access_cookies,
unset_jwt_cookies,
)
from flask_jwt_extended.exceptions import NoAuthorizationError
from jwt import ExpiredSignatureError
class PhaunosBaseView(BaseView):
def render(self, template, **kwargs):
try:
verify_jwt_in_request()
self._template_args['current_user'] = get_current_user()
current_app.logger.info("Access token ok for user {}".format(get_current_user()))
resp = make_response(super(PhaunosBaseView, self).render(template, **kwargs))
except ExpiredSignatureError:
# if the access token has expired, create new non-fresh token
current_app.logger.info("Access token has expired.")
try:
verify_jwt_refresh_token_in_request()
self._template_args['current_user'] = get_current_user()
access_token = create_access_token(identity=get_jwt_identity(), fresh=False)
resp = make_response(super(PhaunosBaseView, self).render(template, **kwargs))
set_access_cookies(resp, access_token)
except ExpiredSignatureError:
# if the refresh token has expired, user must login again
current_app.logger.info("Refresh token has expired")
resp = make_response(super(PhaunosBaseView, self).render(template, **kwargs))
unset_jwt_cookies(resp)
except NoAuthorizationError:
current_app.logger.info("No authorization token.")
resp = make_response(super(PhaunosBaseView, self).render(template, **kwargs))
return resp
class PhaunosModelView(PhaunosBaseView, sqla.ModelView):
pass
class ProjectAdminView(PhaunosModelView):
def create_form(self, obj=None):
current_app.logger.info("In create_form")
form = super(ProjectAdminView, self).create_form(obj)
current_app.logger.info(request.headers)
verify_jwt_in_request()
return form
def on_model_change(self, form, model, is_created):
current_app.logger.info("In on_model_change")
current_app.logger.info(id(request))
current_app.logger.info(request.headers)
verify_jwt_in_request()
# then set get_current_user() to some model attribute
log
[2019-03-28 18:20:27,311] INFO in views: In create_form
[2019-03-28 18:20:27,312] INFO in views: 140045316455232
[2019-03-28 18:20:27,312] INFO in views: Host: 127.0.0.1:5000
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1:5000/admin/admin_project/
Connection: keep-alive
Cookie: session_id=0c89eb809ae01aa65aa58bbc45faf79b31af32db; access_token_cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NTM3OTcxOTYsIm5iZiI6MTU1Mzc5NzE5NiwianRpIjoiMWU0ZTA3YzItMjJjOC00NTFhLWJkNjAtYjllNzZmNWYzMTYyIiwiZXhwIjoxNTUzNzk3Mzc2LCJpZGVudGl0eSI6ImR1bW15X3VzZXI0MiIsImZyZXNoIjp0cnVlLCJ0eXBlIjoiYWNjZXNzIiwiY3NyZiI6IjkwZTY5ZjM1LWQwNDctNDM0NC1hOWVlLTg2NDM4OWFiNzM4OCJ9.0p1CBGxpUzLgIR369I1yP-FTRel4-fhAIeL084YV_O0; csrf_access_token=90e69f35-d047-4344-a9ee-864389ab7388; refresh_token_cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NTM3OTcxOTYsIm5iZiI6MTU1Mzc5NzE5NiwianRpIjoiODI0MGJkODItYjg0NC00MjI5LWFiN2MtZTRhN2IwYzgxYzYzIiwiZXhwIjoxNTUzNzk3NTU2LCJpZGVudGl0eSI6ImR1bW15X3VzZXI0MiIsInR5cGUiOiJyZWZyZXNoIiwiY3NyZiI6Ijg1M2FiYzk0LWU2YjctNGZkZi05YzRhLTczNDMxZWE4NGRlOCJ9.CcHzlWsT9kBURZ1FaeCjG8du7FGXLD-fm5-HF0sBdJ8; csrf_refresh_token=853abc94-e6b7-4fdf-9c4a-73431ea84de8
Upgrade-Insecure-Requests: 1
[2019-03-28 18:20:27,316] INFO in views: Access token ok for user dummy_user42
172.23.0.1 - - [28/Mar/2019 18:20:27] "GET /admin/admin_project/new/?url=%2Fadmin%2Fadmin_project%2F HTTP/1.1" 200 -
[2019-03-28 18:21:11,496] INFO in views: In create_form
[2019-03-28 18:21:11,496] INFO in views: 140045316455232
[2019-03-28 18:21:11,496] INFO in views: Host: 127.0.0.1:5000
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1:5000/admin/admin_project/new/?url=%2Fadmin%2Fadmin_project%2F
Content-Type: multipart/form-data; boundary=---------------------------209115246111667105161673380
Content-Length: 857
Connection: keep-alive
Cookie: session_id=0c89eb809ae01aa65aa58bbc45faf79b31af32db; access_token_cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NTM3OTcxOTYsIm5iZiI6MTU1Mzc5NzE5NiwianRpIjoiMWU0ZTA3YzItMjJjOC00NTFhLWJkNjAtYjllNzZmNWYzMTYyIiwiZXhwIjoxNTUzNzk3Mzc2LCJpZGVudGl0eSI6ImR1bW15X3VzZXI0MiIsImZyZXNoIjp0cnVlLCJ0eXBlIjoiYWNjZXNzIiwiY3NyZiI6IjkwZTY5ZjM1LWQwNDctNDM0NC1hOWVlLTg2NDM4OWFiNzM4OCJ9.0p1CBGxpUzLgIR369I1yP-FTRel4-fhAIeL084YV_O0; csrf_access_token=90e69f35-d047-4344-a9ee-864389ab7388; refresh_token_cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NTM3OTcxOTYsIm5iZiI6MTU1Mzc5NzE5NiwianRpIjoiODI0MGJkODItYjg0NC00MjI5LWFiN2MtZTRhN2IwYzgxYzYzIiwiZXhwIjoxNTUzNzk3NTU2LCJpZGVudGl0eSI6ImR1bW15X3VzZXI0MiIsInR5cGUiOiJyZWZyZXNoIiwiY3NyZiI6Ijg1M2FiYzk0LWU2YjctNGZkZi05YzRhLTczNDMxZWE4NGRlOCJ9.CcHzlWsT9kBURZ1FaeCjG8du7FGXLD-fm5-HF0sBdJ8; csrf_refresh_token=853abc94-e6b7-4fdf-9c4a-73431ea84de8
Upgrade-Insecure-Requests: 1
172.23.0.1 - - [28/Mar/2019 18:21:11] "POST /admin/admin_project/new/?url=%2Fadmin%2Fadmin_project%2F HTTP/1.1" 401 -