Pylons - 重定向会从HTTPS降级到HTTP,如何解决?

2 投票
2 回答
1807 浏览
提问于 2025-04-16 04:07

在我的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 个回答

0

我会对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'])
4

我花了几个小时研究pylons、routes、beaker等的源代码,所以想分享一下我的解决方案。

先说一下背景。我在AWS上使用了弹性负载均衡器(ELB),并且进行了SSL终止。这个应用程序是专门为https设计的;毕竟现在是一个后火绳的时代。它的结构如下:

ELB -> nginx -> pasteWSGI -> pylons

ELB在简单性方面表现得很好,但每次调用pylons.controllers.util.redirect时,都会触发一个302重定向到“http://mysite/”。ELB在返回时不会改变这个(没有理由去改变),所以我的浏览器会被送回到80端口,而在那个端口上没有ELB在监听。

我尝试按照上面的建议更新Mapper。

  1. 但没有成功,
  2. 我希望我的重定向是相对的。在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)

撰写回答