In the development of a website, the vast majority of cases will use login, automatic login function. This is the first article to use cookies and sessions to record user data.

It is well known that HTTP is stateless, that is, the server does not know whether it is the same user from one page to another. Therefore, it gradually developed into a set of methods that the front end uses cookies to save sessionID and the back end uses session to encrypt and decrypt.

Cookie and Session

Here I will talk a little bit about how cookie and session work together. When we front-end staff first got into node development, our thinking might need to be transformed, and it might take a while to transform. But when you figure it out, when you become a full stack engineer, you know the whole process. Express is used here

First of all, you have to be clear about what you want to store in your cookie. Note, try not to store passwords and user names in cookies, one is the risk of being stolen, but increase the size of cookies. (Of course, it is not necessary to do this, such as md5 processing of user name and password, which is relatively safe.) Cookie stores sessionID, how does this sessionID interact with the server, will be explained in detail later.

Express-session is the middleware that handles sessions. This middleware, if you read the source code, does two things:

(1) when there is no cookie in the request body

If there is no cookie in the request body, a new session is created, and a sessionID that will not be repeated is created, and the seesionID is associated with the session in the store. (Store is memory by default)

MemoryStore.prototype.set = function set(sessionId, session, callback) {
  this.sessions[sessionId] = JSON.stringify(session)
  callback && defer(callback)
}

Copy the code

When setCookie is set, the option in the session middleware is processed:

Res.setheader (‘ set-cookie ‘, header) is Set to send the encrypted result to the client.

(2) When you visit the page again

In this case, the cookie will be sent to the server with the request header, and the Express-Session will decrypt the cookie, extract the sessionID, and then use this ID to find the session stored in the store, and get the user data in the session. For example, username and so on (if username is saved to session during login, such as req.ression. Username = user).

At this point, the server knows who the visitor is and can return the data belonging to that visitor to the page.

Second, real project development

The above explains the overall process, although not expanded, but I understand that it can help you grasp the overall context.

All right, so let’s start with the code. I won’t talk about the meaning of each key. You can see the document for details.

Express-session is middleware, so you need to load this middleware into your Express application.

const session = require('express-session');
app.use(session({
    secret: 'test-node-session',
    resave: false,
    saveUninitialized: true,
    cookie: {
        path: '/',
        httpOnly: true,
        secure: false//maxAge: 1000 * 60}}));Copy the code

Through the above Settings, when a request comes, if there is no corresponding cookie on the previous page, a new cookie will be generated. If there is, it will be updated and sent to the browser again.

Of course, the cookie with name connect.sid is generated after the page request. At this point we log in:

During login, data and cookies are sent to the server through POST request.

app.post('/author/gologin', (req, res) => {// Get username and password from req.body, whether automatic login... // Go to the database for matching. If a match is found, the login is successful:.... Req.session. user = req.body.username; Json ({code: 0, mesg: {code: 0, mesg: {code: 0, mesg:' '
    });
})

Copy the code

The front-end page takes the return value of the request and decides which page to route to.

// use vue axios.post('/author/gologin', {
        data: JSON.stringify(this.accountFormItem)
    })
    .then(res => {
        console.log('Login account returns data :', JSON.stringify(res));
        switch (+res.data.code) {
            case 0:
                this.$router.push('/go/to/path/list');
                break;
            case 2004:
                this.inputError = true;
                break;
            default:
                break;
        }
    })
    .catch(err => {
        console.error('Login account error :', err);
    });

Copy the code

At this point, vue-Router navigates to the corresponding page. When reaching a new page, such as a list page, it involves accessing the asynchronous interface of the list,

Note that the presence of the user should be checked in all asynchronous requests by checking whether the user is logged in. For example, the client sends a get request ‘/get/total/list’ to the server and processes it:

// node to process app.get('/get/total/list', (req, res) => {
    if(! req.session.user) {return res.status(401).send({msg: 'Unauthorize'}); } // go to the database... // Return data to the clientreturn res.json({code: 0, data: result});
})

Copy the code

In the above code, there is an important sentence, that is, if req.session.user is found, the process continues, if not, return the 401 state, which is not authenticated, which is consistent with HTTP semantics.

Then the server returns this state, which the client needs to retrieve and route to the login page. This usually doesn’t happen, but when someone changes a cookie, for example, the user data doesn’t match.

/ / client USES axios, can return to intercept the data, in a single page of the app. Js page axios. Interceptors. Response. Use (response = > {/ return/to view the statusreturn response
    },
    error => {
        if(error.response.status === 401) {
            router.push('/login'); }});Copy the code

The page returns to the login page and asks the user to log in again.

So that’s how it works. Of course, this is a rough implementation that doesn’t include the user refreshing the page directly. Just a little bit about that.

For example, when the user refreshes the list page directly, we know that the single-page application has only one HTML entry file, for example, the default is index.html. Then the process is to return the index.html to the browser, which renders the corresponding page according to the route, and then makes the asynchronous request for the page content. (See my article on running single-page applications in Node for details on how to do this.)

There is an experience problem here: if the user deletes the cookie at this point, the page will go through the above steps before returning to 401, and then jump to the login page. There will be an obvious blinking process, first loading the list page and then jumping to the login page, and the user experience is not good.

So we can do some optimization.

Optimal point

  • When logging in, you can save user data, such as user name, in the browser’s sessionStorage, when refreshing the page, first through the Vue route guard to determine whether there is a user name, if not, then directly jump to the login page, there is no need to go through the above complicated and ugly process.
  • SessionStorage doesn’t need to worry much about leaks, because as long as XSS does a good filtering job, people with ulterior motives can’t get it, and it will automatically empty when the browser is closed.
  • When the user closes the browser and opens it again, at this time, because the sessionStorage is gone, so it needs to make an asynchronous request in the routing guard to see whether the user is still in the login state (such as automatic login in 7 days) for processing.
// Vue global router guard. BeforeEach ((to, from, next) => {function getRouteEach(to, next) {
        if (sessionStorage.getItem('testuser')) {// If the URL is a login page, route to the content pageif (to.path === '/login') {
                return next({path: '/to/the/path/list'});
            }
            next();
        } else{// If no login is found, request a login status axios.get('/api/getsid'). Then (res => {// The server has login statusif (res.data.code === 0) {
                    sessionStorage.setItem('testuser', res.data.data.sessionName); // Route to the corresponding pagereturn getRouteEach(to, next);
                } else if(to.path ! = ='/login') {// If you confirm that you are not logged in, jump to the login pagereturn next({path:'/login'});
                }
                next();
            })
            .catch(e => {
                console.error('Failed to view SID :', e);
            })
        }
    }
    getRouteEach(to, next);
    
});

Copy the code

conclusion

  • Node asynchronously requests and checks to see if the user is actually logged in.
  • Return status via AXIos’s global listener, intercept 401, and route to the login page.
  • Optimize the user experience through vUE’s route guard.

security

It’s been known for a long time that this approach has been used, but the problem is that it’s easy to get caught up in CSRF attacks. Of course, it can be reinforced with methods such as double cookie authentication, but the token method I’ll talk about in the next article is more convenient. << Node token from a single page application >> Welcome to continue to follow ~~