How to force the use of SSL for some URL of my Django Application?

前端 未结 4 994
北海茫月
北海茫月 2020-12-08 12:20

I want to be sure that for some URL of my website, SSL will be use. I saw a lot of answer already on SO.

Force redirect to SSL for all pages apart from one

S

相关标签:
4条回答
  • 2020-12-08 12:34

    Besides using mod_rewrite, you can also use Django to control the SSL redirects.

    Here's a modified version of a middleware from the Satchmo Project. I tend to like this method better than mod_rewrite as it's easier to manage.

    To use it, pass 'SSL':True into your url conf:

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

    Here's the middleware code:

    
        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)
    
    
    0 讨论(0)
  • 2020-12-08 12:38

    We used some simple middleware to check urls against a list of base urls that must be in HTTPS mode, all others are forced to HTTP mode. The big caveat here is that any POST data can be lost unless you take extra care (it didn't matter in our case). We were doing this on join pages that required credit card numbers and the like so as soon as they were in that pipeline we forced them into HTTPS.

    0 讨论(0)
  • 2020-12-08 12:45

    Here's a view decorator that you can apply to the views that should have 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
    
    0 讨论(0)
  • 2020-12-08 12:50

    If by WSGI you actually mean Apache/mod_wsgi, then although mounted WSGI applications normally get run in their own sub interpreters, the 80/443 split is a special case and even though in different VirtualHost so long as mount point for WSGIScriptAlias, and the ServerName are the same, they will be merged.

    <VirtualHost *:80>
    ServerName www.example.com
    
    WSGIScriptAlias / /some/path/django.wsgi.
    </VirtualHost>
    
    <VirtualHost *:443>
    ServerName www.example.com
    
    WSGIScriptAlias / /some/path/django.wsgi.
    </VirtualHost>
    

    This will happen for daemon mode as well, but with daemon mode you need to define only a single daemon process group in first VirtualHost definition and then just refer to that from both with 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>
    

    The WSGIProcessGroup can only reach across like to that VirtualHost for same ServerName.

    Django provides a is_secure() method for determining when request came via HTTPS which derives from WSGI variable with request called 'wsgi.url_scheme' which is set by mod_wsgi.

    So, you would have one single Django WSGI script file and settings file. You just need to duplicate application mounting as decsribed in Apache/mod_wsgi configuration.

    0 讨论(0)
提交回复
热议问题