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

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

1 ответ

Решение

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

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, но также, если response "s body Если атрибут установлен, то он не генерируется автоматически, это факт, который мы используем для явного задания тела ответа в строковом представлении нашего словаря в формате 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>
Другие вопросы по тегам