我有一个实施了一些方法的App Engine服务,在其中我使用app.yaml中的login: admin选项来限制所有路由。
向我的服务发出POST请求有效:
fetch('http://localhost:8081/api/foo', {
credentials: 'include'});
但是发出PUT请求失败
await fetch('http://localhost:8081/api/foo', {
credentials: 'include',
method: 'PUT',
body: 'hi there'});
,出现以下错误:
Response to preflight request doesn't pass access control check:
Redirect is not allowed for a preflight request.
我了解这是因为我的请求未通过身份验证,并且服务器将我的请求重定向到登录页面。我不了解如何进行身份验证。
我正在使用webapp2处理请求,并设置以下标头:
self.response.headers['Access-Control-Allow-Credentials'] = 'true'
self.response.headers['Content-Type'] = 'application/json'
# This feels wrong, but I still don't clearly understand what this header's purpose is...
self.response.headers['Access-Control-Allow-Origin'] = self.request.headers['Origin']
我认为更深层的问题是我不理解该登录功能的工作原理(它是基于cookie的吗?为什么它可以与GET一起使用,但不能与PUT一起使用?...),我也不是真正理解CORS
感谢您的帮助!
答案 0 :(得分:1)
因此,在与Dan Cornilescu讨论之后,这是我想出的解决方案(谢谢Dan!)
它们继承了自定义HandlerWrapper,而不是让我的类继承webapp2.RequestHandler。 最大的区别在于,当接收到“ OPTIONS”请求(即预检)时,不需要登录。这就是造成我的问题的原因:我无法获得预检请求的身份验证,因此现在不必如此。
还可以在其中处理CORS,并提供允许的来源列表
class HandlerWrapper(webapp2.RequestHandler):
def __init__(self, request, response):
super(HandlerWrapper, self).__init__(request, response)
self.allowed_origins = [
r'http://localhost(:\d{2,})?$', # localhost on any port
r'https://\w+-dot-myproject.appspot.com' # all services in the app engine project
]
self.allowed_methods = 'GET, PUT, POST, OPTIONS'
self.content_type = 'application/json'
# login mode: either 'admin', 'user', or 'public'
self.login = 'admin'
def dispatch(self):
# set the Allow-Origin header.
if self.request.headers.has_key('origin') and match_origin(self.request.headers['Origin'], self.allowed_origins):
self.response.headers['Access-Control-Allow-Origin'] = self.request.headers['Origin']
# set other headers
self.response.headers['Access-Control-Allow-Methods'] = self.allowed_methods
self.response.headers['Content-Type'] = 'application/json'
self.response.headers['Access-Control-Allow-Credentials'] = 'true'
# Handle preflight requests: Never require a login.
if self.request.method == "OPTIONS":
# For some reason, the following line raises a '405 (Method Not Allowed)'
# error, so we just skip the dispatch and it works.
# super(HandlerWrapper, self).dispatch()
return
# Handle regular requests
user = users.get_current_user()
if self.login == 'admin' and not users.is_current_user_admin():
self.abort(403)
elif self.login == 'user' and not user:
self.abort(403)
else:
super(HandlerWrapper, self).dispatch()
def match_origin(origin, allowed_origins):
for pattern in allowed_origins:
if re.match(pattern, origin): return True
return False
答案 1 :(得分:0)
login: admin
配置基于Users API,仅在第一代标准环境中可用。不是CORS问题。在handlers element表的login
行中:
使用具有登录设置(而非可选)的URL处理程序时 匹配URL,处理程序将首先检查用户是否已登录 使用其authentication option连接到应用程序。如果没有,通过 默认情况下,用户将被重定向到登录页面。您也可以使用
auth_fail_action
将应用程序配置为仅拒绝请求 用于未经过正确身份验证的用户的处理程序 将用户重定向到登录页面的过程。
要使用Users API,用户必须在发出PUT
请求之前直接登录。首先发出一个GET
请求,这会将您重定向到登录页面,执行登录,然后发出PUT
请求。
如果那不是您可以实现的,那么您需要使用a different authentication mechanism,而不是基于login: admin
的那个。
更新:
以上内容是正确的,但在解决了用户API身份验证时却没有关系-您确实提到了对同一URL的其他一些请求方法也可以使用。
您得到的错误确实与CORS相关,请参阅Response to preflight request doesn't pass access control check。但是我建议不要将注意力集中在已接受的答案上(仅用于解决CORS问题),而应关注this one,这是关于正确执行CORS。