【问题标题】:How to force the use of SSL for some URL of my Django Application?如何强制对我的 Django 应用程序的某些 URL 使用 SSL?
【发布时间】:2010-12-05 14:44:39
【问题描述】:

我想确保对于我网站的某些 URL,将使用 SSL。 我已经在 SO 上看到了很多答案。

Force redirect to SSL for all pages apart from one

所以我想我会使用mod_rewrite

我的问题更多关于如何配置 虚拟主机 以在 HTTPHTTPS 上运行我的 Django 应用程序 而不会出现问题。我正在使用WSGI

只在*:443*:80 上复制配置是否有问题? 我应该怎么做才能获得最佳配置?

【问题讨论】:

标签: django apache mod-rewrite ssl wsgi


【解决方案1】:

如果你所说的 WSGI 实际上是指 Apache/mod_wsgi,那么尽管挂载的 WSGI 应用程序通常在它们自己的子解释器中运行,但 80/443 拆分是一种特殊情况,即使在不同的 VirtualHost 中,只要挂载点为 WSGIScriptAlias,和ServerName相同,会合并。

<VirtualHost *:80>
ServerName www.example.com

WSGIScriptAlias / /some/path/django.wsgi.
</VirtualHost>

<VirtualHost *:443>
ServerName www.example.com

WSGIScriptAlias / /some/path/django.wsgi.
</VirtualHost>

这也将发生在守护进程模式下,但在守护进程模式下,您只需在第一个 VirtualHost 定义中定义一个守护进程组,然后使用 WSGIProcessGroup 引用这两个进程组。

<VirtualHost *:80>
ServerName www.example.com

WSGIDaemonProcess mydjangosite ...
WSGIProcessGroup mydjangosite

WSGIScriptAlias / /some/path/django.wsgi.
</VirtualHost>

<VirtualHost *:444>
ServerName www.example.com

WSGIProcessGroup mydjangosite

WSGIScriptAlias / /some/path/django.wsgi.
</VirtualHost>

WSGIProcessGroup 只能通过相同的 ServerName 访问该 VirtualHost。

Django 提供了一个 is_secure() 方法来确定何时通过 HTTPS 发出请求,该方法源自 WSGI 变量,请求名为“wsgi.url_scheme”,由 mod_wsgi 设置。

因此,您将拥有一个 Django WSGI 脚本文件和设置文件。您只需要按照 Apache/mod_wsgi 配置中的说明复制应用程序安装即可。

【讨论】:

    【解决方案2】:

    除了使用 mod_rewrite,您还可以使用 Django 来控制 SSL 重定向。

    这是来自Satchmo Project 的中间件的修改版本。我倾向于比 mod_rewrite 更喜欢这种方法,因为它更容易管理。

    要使用它,请将 'SSL':True 传递到您的 url conf 中:

    
        urlpatterns = patterns('some_site.some_app.views',
            (r'^test/secure/$','test_secure',{'SSL':True}),
        )
    

    这是中间件代码:

    
        from django.conf import settings
        from django.http import HttpResponseRedirect, get_host
    
        SSL = 'SSL'
    
        def request_is_secure(request):
            if request.is_secure():
                return True
    
            # Handle forwarded SSL (used at Webfaction)
            if 'HTTP_X_FORWARDED_SSL' in request.META:
                return request.META['HTTP_X_FORWARDED_SSL'] == 'on'
    
            if 'HTTP_X_SSL_REQUEST' in request.META:
                return request.META['HTTP_X_SSL_REQUEST'] == '1'
    
            return False
    
        class SSLRedirect:
            def process_request(self, request):
                if request_is_secure(request):
                    request.IS_SECURE=True
                return None
    
            def process_view(self, request, view_func, view_args, view_kwargs):          
                if SSL in view_kwargs:
                    secure = view_kwargs[SSL]
                    del view_kwargs[SSL]
                else:
                    secure = False
    
                if settings.DEBUG:
                    return None
    
                if getattr(settings, "TESTMODE", False):
                    return None
    
                if not secure == request_is_secure(request):
                    return self._redirect(request, secure)
    
            def _redirect(self, request, secure):
                if settings.DEBUG and request.method == 'POST':
                    raise RuntimeError(
                    """Django can't perform a SSL redirect while maintaining POST data.
                        Please structure your views so that redirects only occur during GETs.""")
    
                protocol = secure and "https" or "http"
    
                newurl = "%s://%s%s" % (protocol,get_host(request),request.get_full_path())
    
                return HttpResponseRedirect(newurl)
    
    

    【讨论】:

    • 这也很有用。确保它是 SSL 连接。你认为用 django 处理它更好吗?还是使用 Mod_Rewrite ?
    • 就像我提到的,我倾向于在 Django 中管理它,因为更容易看到哪些 URL 是通过 SSL 保护的。如果您需要保护 URL,只需更新 urls.py 文件即可。不需要凌乱(嗯,更乱)的 mod_rewrite 规则。
    • 我认为上面的代码缺少 _redirect() 函数的最后一行...该函数的最后一行应该是return HttpResponseRedirect(newurl)
    • 我将它放在我的项目根目录中的一个名为ssl_redirect.py 的文件中,并在settings.py 中为MIDDLEWARE_CLASSES 添加了一行'ssl_redirect.SSLRedirect'。另外,请注意,在 Django 1.5 中,您需要将 get_host 调用更改为 request.get_host() 并删除顶部的 get_host 导入,否则您将收到无法导入 get_host 的错误。
    • 此代码信任用户提供的标头,这是不安全的,除非您使用了去除意外标头的代理。您只需检查.is_secure 并根据您的设置适当配置SECURE_PROXY_SSL_HEADER
    【解决方案3】:

    这是一个视图装饰器,您可以将其应用于应该具有 HTTPS 的视图。

    from functools import wraps
    from django.conf import settings
    from django.http import HttpResponseRedirect
    
    
    def require_https(view):
        """A view decorator that redirects to HTTPS if this view is requested
        over HTTP. Allows HTTP when DEBUG is on and during unit tests.
    
        """
    
        @wraps(view)
        def view_or_redirect(request, *args, **kwargs):
            if not request.is_secure():
                # Just load the view on a devserver or in the testing environment.
                if settings.DEBUG or request.META['SERVER_NAME'] == "testserver":
                    return view(request, *args, **kwargs)
    
                else:
                    # Redirect to HTTPS.
                    request_url = request.build_absolute_uri(request.get_full_path())
                    secure_url = request_url.replace('http://', 'https://')
                    return HttpResponseRedirect(secure_url)
    
            else:
                # It's HTTPS, so load the view.
                return view(request, *args, **kwargs)
    
        return view_or_redirect
    

    【讨论】:

      【解决方案4】:

      我们使用一些简单的中间件来检查 url 与 必须处于 HTTPS 模式的基本 url 列表,所有其他的都强制使用 HTTP 模式。这里最大的警告是,除非您格外小心,否则任何 POST 数据都可能丢失(在我们的情况下这无关紧要)。我们在需要信用卡号等的连接页面上执行此操作,因此一旦它们进入该管道,我们就强制它们使用 HTTPS。

      【讨论】:

        猜你喜欢
        • 2011-02-15
        • 1970-01-01
        • 2011-03-19
        • 1970-01-01
        • 2015-07-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-22
        相关资源
        最近更新 更多