如何强制使用SSL为我的Django应用程序的某些URL?

时间:2009-10-10 15:21:23

标签: django apache mod-rewrite ssl wsgi

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

Force redirect to SSL for all pages apart from one

所以我想我会使用mod_rewrite

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

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

4 个答案:

答案 0 :(得分:11)

如果你通过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配置中复制应用程序挂载。

答案 1 :(得分:10)

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

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

要使用它,请将'SSL':True传递到您的网址:


    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)

答案 2 :(得分: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

答案 3 :(得分:0)

我们使用了一些简单的中间件来检查网址列表,其中必须处于HTTPS模式,所有其他网址都被强制为HTTP模式。这里最大的警告是,除非你特别小心,否则任何POST数据都会丢失(在我们的例子中并不重要)。我们在需要信用卡号等的连接页面上这样做,所以一旦他们进入该管道,我们就会强迫他们进入HTTPS。