return JSON 认证失败时如何输出?
How can I return JSON output when repoze.who authentication fails?
我正在编写 repoze.who
plugin 并希望从 repoze.who
身份验证中间件 return JSON 并且仍然控制 HTTP 状态代码。如何做到这一点?
实现此目的的一种方法是实施 repoze.who
Challenger interface. The following solution takes advantage of the fact that the WebOb exceptions, in webob.exc
, can be used as a WSGI application. The following example shows how this can be used in a hypothetical Facebook plugin, where the 2.x API 让用户 不 授予对其电子邮件的访问权限,这可能是成功 registration/authentication:
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
的 sub-class 的一个实例,被用作 WSGI 应用程序,而且如果 response
' s body
属性被设置,那么它是 not 自动生成的,事实上我们用来显式设置响应的 body 为 JSON-formatted 字符串表示我们的字典。如果在处理对以 '.json' 结尾的 URL 或 Accept
header 包含 application/json
的请求期间调用上述挑战者,则 body 的响应可能呈现为:
{
"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"]}
}
如果不是,则 body 将呈现为 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>
我正在编写 repoze.who
plugin 并希望从 repoze.who
身份验证中间件 return JSON 并且仍然控制 HTTP 状态代码。如何做到这一点?
实现此目的的一种方法是实施 repoze.who
Challenger interface. The following solution takes advantage of the fact that the WebOb exceptions, in webob.exc
, can be used as a WSGI application. The following example shows how this can be used in a hypothetical Facebook plugin, where the 2.x API 让用户 不 授予对其电子邮件的访问权限,这可能是成功 registration/authentication:
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
的 sub-class 的一个实例,被用作 WSGI 应用程序,而且如果 response
' s body
属性被设置,那么它是 not 自动生成的,事实上我们用来显式设置响应的 body 为 JSON-formatted 字符串表示我们的字典。如果在处理对以 '.json' 结尾的 URL 或 Accept
header 包含 application/json
的请求期间调用上述挑战者,则 body 的响应可能呈现为:
{
"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"]}
}
如果不是,则 body 将呈现为 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>