Как я могу вернуть вывод JSON при сбое аутентификации repoze.who?

Я пишу repoze.who плагин и хочу чтобы вернуть JSON из промежуточного программного обеспечения аутентификации repoze.who и по-прежнему контролировать код состояния HTTP. Как это может быть сделано?


person Martin Thorsen Ranang    schedule 16.04.2015    source источник


Ответы (1)


Один из способов добиться этого — реализовать интерфейс repoze.who Challenger. . В следующем решении используется тот факт, что исключения WebOb в webob.exc можно использовать как приложение WSGI. В следующем примере показано, как это можно использовать в гипотетическом плагине Facebook, где 2.x API позволяет пользователям не предоставлять доступ к своей электронной почте, что может потребоваться для успешной регистрации/аутентификации:

import json
from webob.acceptparse import MIMEAccept
from webob.exc import HTTPUnauthorized, HTTPBadRequest


FACEBOOK_CONNECT_REPOZE_WHO_NOT_GRANTED = 'repoze.who.facebook_connect.not_granted'


class ExampleJSONChallengerPlugin(object):
    json_content_type = 'application/json'
    mime_candidates = ['text/html',
                       'application/xhtml+xml',
                       json_content_type,
                       'application/xml',
                       'text/xml']

    def is_json_request_env(self, environ):
        """Checks whether the current request is a json request as deemed by
        TurboGears (i.e. response_type is already set) or if the http
        accept header favours 'application/json' over html.
        """
        if environ['PATH_INFO'].endswith('.json'):
            return True

        if 'HTTP_ACCEPT' not in environ:
            return False

        # Try to mimic what Decoration.lookup_template_engine() does.
        return MIMEAccept(environ['HTTP_ACCEPT']) \
            .best_match(self.mime_candidates) is self.json_content_type

    def challenge(self, environ, status, app_headers, forget_headers):
        if FACEBOOK_CONNECT_REPOZE_WHO_NOT_GRANTED in environ:
            response = HTTPBadRequest(detail={
                'not_granted': 
                environ.pop(FACEBOOK_CONNECT_REPOZE_WHO_NOT_GRANTED),
            })
        elif status.startswith('401 '):
            response = HTTPUnauthorized()
        else:
            response = None

        if response is not None and self.is_json_request_env(environ):
            response.body = json.dumps({
                'code': response.code,
                'status': response.title,
                'explanation': response.explanation,
                'detail': response.detail,
            })
            response.content_type = self.json_content_type

        return response

Центральным моментом здесь является то, что response, экземпляр подкласса webob.exc.WSGIHTTPException, используется в качестве приложения WSGI, но также и то, что если атрибут body response установлен, то он не генерируется автоматически, а факт, который мы используем, чтобы явно установить в теле ответа строковое представление нашего словаря в формате JSON. Если вышеупомянутый претендент вызывается во время обработки запроса к URL-адресу, оканчивающемуся на «.json», или заголовок Accept включает application/json, тело ответа может отображаться примерно так:

{
    "status": "Bad Request",
    "explanation": "The server could not comply with the request since it is either malformed or otherwise incorrect.",
    "code": 400, 
    "detail": {"not_granted": ["email"]}
}

а если нет, то тело будет отображаться как HTML:

<html>
 <head>
  <title>400 Bad Request</title>
 </head>
 <body>
  <h1>400 Bad Request</h1>
  The server could not comply with the request since it is either 
  malformed or otherwise incorrect.<br /><br />
{'not_granted': [u'email']}


 </body>
</html>
person Martin Thorsen Ranang    schedule 16.04.2015