Search code examples
python-3.xsessionwebflaskflask-restful

Why flask session didn't store the user info when making different posts to it from react?


I wrote several APIs using Flask-RESTful and several react modules for testing purposes. Ideally, if I stored some info in session through a request, python should be able to detect whether there is such session even in other API entries with code, like

if session:
    return jsonify({'user': session['username'], 'status': 2000})
return jsonify({'user': None, 'status': 3000})

However, the problem I met was within a single request, say login request, session was indeed properly used and username was also stored in the session —— for example,

from flask import session
...

# login API

class UserLoginResource(Resource):
    @staticmethod
    def post():
        ...
        ... # a user object (model) is defined
        session['username'] = user.username
        return jsonify({'status': 2000, 'user': session['username']})

with this code, it returned the exact username from session, which meant info was stored. However, when I made another get request from react side to the index API, like

from flask import session
...

# index API (without any practical use)

class IndexResource(Resource):
    @staticmethod
    def get():
        if session:
            return jsonify({'username': session['username']})

In this case, the response was None, cuz the API didn't detect any session.

// makePostRequest Function

makePostRequest = (e: any) => {
        e.preventDefault()
        const payload = {
            'email': this.state.email,
            'password': this.state.password
        }

        fetch('http://127.0.0.1:5000/api/login', {
            method: 'POST',
            headers: {
                'Access-Control-Allow-Origin': '*',
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(payload)
        }).then(res => res.json())
        .then(res => {this.setState({
            status: res['status'],
            username: res['user']
        })})
        .catch(err => console.log(err))
    }

This is the way I make login post request. If login successful, it returns status code 2000; and if the status code is 2000, it means the program has gone through the code session['username']=_the_username_. And I should be able to extract username data from session storage when accessing Index page.

componentDidMount = () => {
        fetch('http://127.0.0.1:5000/api')
        .then(res => res.json())
        .then(res => this.setState({
            user: res['user'],
            status: res['status']
        }))
    }

This is how I make a get request on the homepage module. However, the user is always None and status is always 3000

This may be just improper use of session, but I don't know how to actually correctly use the session in flask. So, what was the mistake here?


Update: So, I added a GET request within class UserLoginResource(Resource) like this

class UserLoginResource(Resource):
    @staticmethod
    def post():
        ... # identical to the previous code

    @staticmethod():
    def get():      # url: http://127.0.0.1:5000/api/login
        session['username'] = 'user_a'
        return jsonify({'message': 'session set'})

And I made a get request in react side to http://127.0.0.1:5000/api/login and got the message: session set. However, when react then accessed http://127.0.0.1:5000/api, the result remained to be status 3000 and None username. Then, I directly accessed the url http://127.0.0.1:5000/api/login and then accessed http://127.0.0.1:5000/api and there we go we had the username user_a and status 2000. So, I think the problem here might be that the backend didn't recognize the browser that was accessing it was the same person, or it might be others. Also, I checked if it was something wrong with componentDidMount, but unfortunately componentDidMount wasn't the source of error — after I turned it into a normal function triggered by onClick, still it didn't work. How to fix this?


Solution

  • fetch does not supports cookie by default, you need to enable it using credentials: 'include'

    makePostRequest = (e: any) => {
            e.preventDefault()
            const payload = {
                'email': this.state.email,
                'password': this.state.password
            }
    
            fetch('http://127.0.0.1:5000/api/login', {
                method: 'POST',
                credentials: 'include',
                headers: {
                    'Access-Control-Allow-Origin': '*',
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(payload)
            }).then(res => res.json())
            .then(res => {this.setState({
                status: res['status'],
                username: res['user']
            })})
            .catch(err => console.log(err))
        }
    

    Enable cors on server using pip install flask-cors

    Then Add this to app.py, where you initialize your app

    from flask_cors import CORS 
    app = Flask(__name__) 
    CORS(app)