«Отсутствует токен CSRF в заголовках» с аутентификацией JWT во Flask-Admin - PullRequest
1 голос
/ 29 марта 2019

Я пишу бэкэнд 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 -
...