Search code examples
authenticationnginxweb2py

Web2py & nginx - do I have to set up static folder


I'm running nginx/uWSGI and trying to lock down a web2py site using 'auth.requires_login()' (https://groups.google.com/forum/#!topic/web2py/0j92-sPp4bc) so that only logged in users can get to it, even the content under /static/. If I set up nginx config file with

location ~* /(\w+)/static/ {
        root /home/www-data/web2py/applications/;
}

as recommended in the docs, won't that bypass the access control, and allow anyone to see the static content? If I leave this line out of the config file, will web2py still share the static content to logged-in users (although presumably a little slower)?


Solution

  • Yes, using that nginx rule will bypass web2py. Removing it and letting web2py handle /static/ won't change much either, as this is directly from the web2py manual:

    http://127.0.0.1:8000/a/static/filename There is no controller called "static". web2py interprets this as a request for the file called "filename" in the subfolder "static" of the application "a". When static files are downloaded, web2py does not create a session, nor does it issue a cookie or execute the models.

    So because there is no controller, you cannot directly use auth.requires_login() for static content. This is because files in /static/ are generally not meant to be access-controlled, or else browsers will not be able to get the css, js, etc. needed to even render the welcome or login page.

    However, if you still want site-wide access control to static files (i.e. private pdf files) you can do it like so:

    • in your application directory, create a folder called private_static

    then in your controller add the following:

    #default.py
    import os
    
    auth.requires_login()
    def private_static():
        filename = os.path.join(*request.args)
        allowed = ['private1.pdf', 'private2.pdf']  # have some kind of validation for security!
        if not filename in allowed:
            raise HTTP(404)
        return response.stream(open(os.path.join(request.folder, 'private_static', filename)))
    

    and in your view something like the following:

    <a href="{{=URL('private_static', args=['private1.pdf'])}}">Private Document</a>
    

    Now accessing http://.../private_static/private1.pdf will force the user to login before getting the static file.