My first Flask app: authentication
July 23, 2018 10:08 AM   Subscribe

I'm trying my hand at my first-ever bit of modernish web development for a thing at work. I'm a Python guy primarily, so I'm doing it in Flask. (I've also looked at Django, but Flask seems to be a lot faster to get going with.) I can get all the individual pieces to work just fine, but I can't get the bit where I authenticate users to work. Help me, Stack Overflow're my only hope.

Long story short: our main student system I support/develop for has a facility where you can upload formatted text files to do batch processing--e.g., create hundreds of courses at once, or enroll dozens of people on those courses.

However, the screen where you can do this also has an option where if you leave it checked, the system will erase everything except what's in your upload file. (Apparently some people use this to do complete refreshes of their systems nightly. Madness.) As you can imagine, we keep things locked down pretty tightly so accidents don't happen--there are maybe three or four of us in the entire university who can upload these files. However, things get pretty bottleneck-y if we're all out of the office at once.

Enter the app I'm working on, which will let a user upload a file while completely avoiding the super dangerous HISTORY ERASER BUTTON. It's currently structured into three routes:

- The root/index route. Basically just a form with a dropdown box to choose the file type, a file selector to choose the upload file, and a button to upload it to the server. Simple, and it works by forwarding to...

- ...the upload route, which does a POST to the proper URL with the contents of the file and gets the result from the server, then goes back to the main page.

- The login route, which people are redirected to if they're not logged in.

All of that works just fine, including the routing to the login page if a user isn't logged in (which of course is all users right now). The difficulty comes in when I start trying to use libraries like flask-login. From what I can tell from my admittedly limited experience, it looks like most of the authentication libraries out there really, really want you to use a database with them, and I'm only needing to authenticate against LDAP. (This is such a lightweight application that will see maybe eight or nine uses a day, and all I really need to know is a.) that someone hitting the site is a user in the university, and b.) they are who they say they are, and then to get Flask to hang on to that information somehow. I don't need to store their identity anywhere or make them register or anything.)

I've tried playing around with the application and request context objects, but I can't seem to get the hang of either one. Does anyone have any advice on techniques/tutorials/libraries to do what I'm trying to do? Thanks in advance.

Also, let me know if I need to clarify anything--I'm typing this after four or five hours of trying to get this to work, and I'd be pulling my hair out if I had any left.
posted by Mr. Bad Example to Computers & Internet (6 answers total) 2 users marked this as a favorite
Have you tried flask-ldap? It doesn't appear to need a backing DB (it mentions mongo, but it's not required if you don't want to store any info about the users).
posted by BungaDunga at 10:44 AM on July 23, 2018

Best answer: You need a database if you're using sessions, because the session key has to be stored somewhere on the server side as well as in the browser in order for successive actions to know that the user is auth'd (or other data that might be stored in the session). SQLite3 is a common file-based database that can be used for this in light-duty apps such as yours.

The alternative is to set/check a cookie that has the value "logged_in = true" or similar in it.
posted by rhizome at 10:50 AM on July 23, 2018

You need a database if you're using sessions, because the session key has to be stored somewhere on the server side as well as in the browser in order for successive actions to know that the user is auth'd (or other data that might be stored in the session).

I'm a Flask newbie myself, but I believe the Flask has a simple implementation of sessions that does not require a database. It's stored server-side but uses a secret_key to build that relationship.

Mr. Bad Example, my best guess is to use the flask-ldap-login library. You'll notice under "LDAPLoginForm form" that this requires using flask-login's login_user method. More info on that here. I think you could ignore flask-ldap-login's instructions for "Store the ldap user into your server's DB" and instead follow the flask-login pattern for storing logins within a session, and that would get around db use entirely.

Hope that helps/good luck!
posted by elephantsvanish at 12:22 PM on July 23, 2018 [1 favorite] lays out a fairly simple contract for how a 'user' object need to behave to play will with flask_login, but there's nothing that requires that such an object comes from a database.

Take a look at the example `login` method in that doc, and imagine that instead of the usual 'emit a page with a form on GET, and act on that form on POST', you instead did some LDAP (or single-sign-on cookie) magic on GET to verify identity, and then created a non-database-backed user and passing it to `login_user`. You'll need to do something equivalent in the `user_loader` callback.
posted by dws at 1:18 PM on July 23, 2018

(I've also looked at Django, but Flask seems to be a lot faster to get going with.)

FWIW, this is a common trap to fall into. Flask will let you get *something* up and going more quickly than Django will, but since it's so minimal once you start doing anything complicated (like, say, authentication) you need to either find a plugin for it or write a bunch of code yourself. Django, OTOH, comes with all sorts of things, including authentication, right out of the box.
posted by asterix at 4:04 PM on July 23, 2018 [1 favorite]

Response by poster: Thanks, everybody. I managed to get my head around the session variables thing after I got some sleep. What I'm doing for the moment is checking to see if there's an authorized user set in the session, and if not, redirecting them to the login page. After they log in, I'm storing their authorized status in the session and then expiring that after a few minutes. (Currently five to ten--we'll see what works best when people actually start using the thing.)

If this sees more heavy use, I'll probably wind up doing a more robust login system with flask-login and MySQL/MariaDB behind it. This should work for now, though. Off to do terrible, terrible things with CSS now. :)
posted by Mr. Bad Example at 2:50 AM on July 24, 2018

« Older Books to read a toddler by a lake in New Hampshire...   |   Massachusetts pool owners - how do you heat your... Newer »
This thread is closed to new comments.