[PYTHON] I investigated the mechanism of flask-login!

flask-login I have implemented the login function using flask-login, but I wanted to know the internal mechanism, so I investigated the mechanism from the documentation and source code!

Let's define the following properties / methods in the: dolphin: User class

You may extend the UserMixin class.

: dolphin: Let's initialize flask_login

from flask_login import LoginManager
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = "login"

Let's define a callback function to load: dolphin: user

@login_manager.user_loader
def load_user(userid):
    return User(userid)

The argument received by load_user here is the value returned by get_id () defined in the User class. If necessary, let get_id () return the value needed to get the user from the DB: smile:

: cat: Let's implement login process

def login():
    form = LoginForm()
    if form.validate_on_submit():
        login_user(user)
        flask.flash('Logged in successfully.')
        next = flask.request.args.get('next')
        if not is_safe_url(next):
            return flask.abort(400)
        return flask.redirect(next or flask.url_for('index'))
    return flask.render_template('login.html', form=form)

Pass user to login_user and flask-login will do the rest. It mainly stores the information necessary to maintain the login status in the session, updates the user in the request context, sends a login signal, etc .: bow:

: dog: Let's implement logout processing

@app.route("/logout")
@login_required
def logout():
    logout_user()
    return redirect(somewhere)

It's very simple, just call logout_user. In the logout_user function, the logged-in user is fetched and the logout process is executed, so there is no need to pass the user. Roughly speaking, it's the opposite of logging in. To keep the login status, delete the value held in the session, update the user in the request context to anonymous_user, and send the logout signal. : rolling_eyes:

: rabbit: Behavior before login

In the login_required decorator, get the current_user. current_user attempts to get the user from the information stored in the session (specifically user_id). [a] Since it is before login, the session does not have user_id, so getting the user fails. If request_loader is defined, use them to try to log in. Since request_loader is not defined this time, current_user will be Anonymous User. Since is_authenticated defined in the Anonymous User class returns False, it is determined that it is not authenticated, and LoginManger's unauthorized () is called to redirect to the login screen.

: rabbit: Behavior after login

It is the same as [a] of the behavior before login. If the user is successfully acquired, the user is returned as it is. Check if the user is authenticated with is_authenticated. Since it is not an Anonymous User, True is returned as defined in the User model. It is determined to be authenticated, so subsequent processing continues: laughing:

: bear: Security measures

--HttpOnly attribute By default, Flask holds session information on the client side, called a cookie based session. Therefore, set SESSION_COOKIE_HTTPONLY to True to prevent javascript from accessing this information. (Default is True) [1]

--Limited cookie based session cookie transmission to Https only Let's set SESSION_COOKIE_SECURE to True. (Default is False) [2]

--Session protection Flask-login generates a hash value from the IP address and user-agent and holds it in the session, so if that value changes from the previous time, the default basic mode behavior will drop the login state. However, on the flask side, if the session persistence setting is set, the login state will be maintained, but this session will be flagged as not fresh. In strong mode, the login state is discarded if the hash has changed.

By default, it is activated in "basic" mode. It can be disabled in the app’s configuration by setting the SESSION_PROTECTION setting to None, "basic", or "strong". When session protection is active, each request, it generates an identifier for the user’s computer (basically, a secure hash of the IP address and user agent). If the session does not have an associated identifier, the one generated will be stored. If it has an identifier, and it matches the one generated, then the request is OK. If the identifiers do not match in basic mode, or when the session is permanent, then the session will simply be marked as non-fresh, and anything requiring a fresh login will force the user to re-authenticate. (Of course, you must be already using fresh logins where appropriate for this to have an effect.) If the identifiers do not match in strong mode for a non-permanent session, then the entire session (as well as the remember token if it exists) is deleted. [3]

[1] https://flask.palletsprojects.com/en/1.1.x/config/#SESSION_COOKIE_HTTPONLY [2] https://flask.palletsprojects.com/en/1.1.x/config/#SESSION_COOKIE_SECURE [2] https://flask-login.readthedocs.io/en/latest/#session-protection

Recommended Posts

I investigated the mechanism of flask-login!
I investigated the reinforcement learning algorithm of algorithmic trading
I investigated how the scope looks
I investigated the device tree Overlay
I investigated the X-means method that automatically estimates the number of clusters
I investigated the behavior of the difference between hard links and symbolic links
Explain the mechanism of PEP557 data class
I checked the contents of docker volume
I tried the asynchronous server of Django 3.0
I checked the options of copyMakeBorder of OpenCV
I summarized the folder structure of Flask
I didn't know the basics of Python
The Python project template I think of.
I read the implementation of golang channel
Let's investigate the mechanism of Kaiji's cee-loline
I tried the pivot table function of pandas
I read the implementation of range (Objects / rangeobject.c)
I checked the list of shortcut keys of Jupyter
I tried to touch the API of ebay
I tried to correct the keystone of the image
Try the free version of Progate [Python I]
I checked the session retention period of django
I checked the processing speed of numpy one-dimensionalization
I touched some of the new features of Python 3.8 ①
I read and implemented the Variants of UKR
I want to customize the appearance of zabbix
I tried using the image filter of OpenCV
I tried to predict the price of ETF
I tried to vectorize the lyrics of Hinatazaka46!
The beginning of cif2cell
[Linux] I learned LPIC lv1 in 10 days and tried to understand the mechanism of Linux.
[Trainer's Recipe] I touched the flame of the Python framework.
I tried to summarize the basic form of GPLVM
I tried the MNIST tutorial for beginners of tensorflow.
The meaning of self
I followed the implementation of the du command (first half)
I compared the identity of the images by Hu moment
[Statistics] Understand the mechanism of Q-Q plot by animation.
Maybe I overestimated the impact of ShellShock on CGI
the zen of Python
The story of sys.path.append ()
I checked the output specifications of PyTorch's Bidirectional LSTM
I checked out the versions of Blender and Python
I want to fully understand the basics of Bokeh
The performance of PHP was better than I expected
I examined the argument class_weight of Chainer's softmax_cross_entropy function.
I measured the performance of 1 million documents with mongoDB
I checked the default OS and shell of docker-machine
I followed the implementation of the du command (second half)
I tried using the API of the salmon data project
I tried to visualize the spacha information of VTuber
[Ev3dev] Let's understand the mechanism of LCD (screen) control
I investigated the calculation time of "X in list" (linear search / binary search) and "X in set"
I tried to erase the negative part of Meros
I tried scraping the advertisement of the pirated cartoon site
I counted the grains
I tried the simplest method of multi-label document classification
Revenge of the Types: Revenge of types
I tried to classify the voices of voice actors
I want to increase the security of ssh connections
I searched for the contents of CloudWatch Logs Agent