Pylons - 重定向会从HTTPS降级到HTTP,如何解决?
在我的Pylons网站上,我的登录表单会把数据发送到 'https://mysite.com'。登录成功后,系统会把用户重定向到他们的个人资料页面。
redirect(url(controller='profile'))
这样一来,用户就会被送到 http://mysite.com/profile
,而不是 https://mysite.com/profile
。我找到的唯一解决办法是把重定向改成:
redirect(url(controller='profile', protocol='https'))
我对这个解决办法有个担心,那就是“如果因为某种原因,我的证书失效了,我不得不放弃SSL怎么办?”我不想逐个检查我的代码,找出所有我指定为'https'的重定向。我希望我的登录能直接把用户送到HTTPS就行了……
为什么重定向会变成HTTP?有没有办法阻止这种情况发生? :/
2 个回答
我会对Mapper进行一些定制,这样每次调用“url”时都会强制使用正确的协议...
在 routing.py
文件里:
class CustomMapper(Mapper):
def generate(self, *args, **kwargs):
kwargs["protocol"] = "https"
return Mapper.generate(self, *args, **kwargs)
def make_map(config):
"""Create, configure and return the routes Mapper"""
map = CustomMapper(directory=config['pylons.paths']['controllers'],
always_scan=config['debug'])
我花了几个小时研究pylons、routes、beaker等的源代码,所以想分享一下我的解决方案。
先说一下背景。我在AWS上使用了弹性负载均衡器(ELB),并且进行了SSL终止。这个应用程序是专门为https设计的;毕竟现在是一个后火绳的时代。它的结构如下:
ELB -> nginx -> pasteWSGI -> pylons
ELB在简单性方面表现得很好,但每次调用pylons.controllers.util.redirect时,都会触发一个302重定向到“http://mysite/”。ELB在返回时不会改变这个(没有理由去改变),所以我的浏览器会被送回到80端口,而在那个端口上没有ELB在监听。
我尝试按照上面的建议更新Mapper。
- 但没有成功,
- 我希望我的重定向是相对的。在pylons中切换到https意味着URL生成器会去获取主机名来创建一个新的URL(https://localhost/....)
注意,Mapper.redirect_to是开箱即用的,并且使用相对重定向,所以不需要去修改它。根本的问题是controllers.redirect使用了稍微不同的代码路径。特别是在Routes中,controllers.util.redirect并不是一个重定向(有一个“if routes and routes.redirect”的判断,结果是False)。
我的解决方案是:用一个新的控制器方法(也叫redirect)替换所有的重定向调用,把重定向从绝对路径改为相对路径。
代码如下:
lib/helpers.py
def relative_redirect(to_url, start_response):
"""Returns a redirect that is compatible with AWS ELB (no absolute http responses)
Using pylons.controllers.util.redirect triggers an exception that'll be turned into a 302
But with an absolute path so the response does not contains https but simple http
"""
start_response("302 Found", [("Content-Type", "text/plain; charset=utf-8"), ("Location", url(to_url))])
return ["You are being redirected to {0}".format(url(to_url))]
然后在我的控制器的基类中调用这个方法:
class BaseController(WSGIController):
...
def redirect(self, to_url):
"""Force a relative redirection, to work with AWS ELB"""
return relative_redirect(to_url, self.start_response)