I recently looked into token-based authentication and integrated this mechanism into personal projects. Nowadays, the authentication mode of many websites has changed from the traditional Seesion +cookie to token verification. Compared with the traditional verification method, the token has better scalability and security.

Traditional session+cookie authentication

Because HTTP is stateless, it does not record the identity of the user. After the user sends the account and password to the server, the background passes the verification, but the status is not recorded. Therefore, the user still needs to verify the identity for the next request. To solve this problem, a record containing the user’s identity, namely session, needs to be generated on the server and then sent to the user and stored in the user’s local, namely cookie. Subsequent requests of the user will carry this cookie. If the cookie of the client matches the session of the server, it indicates that the user has passed the authentication.

Token authentication

The process is roughly as follows:

  • On the first request, the user sends the account and password
  • If the background verification succeeds, a time-sensitive token is generated and sent to the user
  • After a user obtains a token, the token is stored locally, usually in localstorage or cookies
  • Each subsequent request adds the token to the request header. All interfaces that require authentication are authenticated with the token. If the data after the token is resolved contains user identity information, the authentication succeeds.

Compared with the traditional verification method, the token verification has the following advantages:

  • In token-based authentication, tokens are transmitted through the request header rather than storing authentication information in a session or cookie. That means stateless. You can send requests to the server from any terminal that can send HTTP requests.
  • CSRF attacks can be avoided
  • When session reads, writes, or deletes are performed in an application, a file operation takes place in the temp folder of the operating system, at least for the first time. Assume there are multiple servers and a session is created on the first service. When you send a request again and the request lands on another server, the session information does not exist and an “unauthenticated” response is received. I know that you can solve this problem with a sticky session. However, in token-based authentication, this problem is solved naturally. There is no sticky session problem because the token of that request is intercepted on every request sent to the server.

Here is how to set up simple token authentication using Node + JWT (JWT tutorial)

The sample

When the user logs in for the first time, he/she submits his/her account and password to the server. If the server passes the verification, the corresponding token will be generated. The code is as follows:

const fs = require('fs');
const path = require('path');
const jwt = require('jsonwebtoken'); // The token generation methodfunction  generateToken(data){
    let created = Math.floor(Date.now() / 1000);
    let cert = fs.readFileSync(path.join(__dirname, '.. /config/pri.pem')); / / the private keylet token = jwt.sign({
        data,
        exp: created + 3600 * 24
    }, cert, {algorithm: 'RS256'});
    returntoken; } // Log in to router. Post ('/oa/login', async (ctx, next) => {
    letData = CTX. Request. The body;let {name, password} = data;
    let sql = 'SELECT uid FROM t_user WHERE name=? and password=? and is_delete=0', value = [name, md5(password)];
    await db.query(sql, value).then(res => {
        if (res && res.length > 0) {
            let val = res[0];
            let uid = val['uid'];
            lettoken = generateToken({uid}); ctx.body = { ... Tips[0], data: {token} } }else {
            ctx.body = Tips[1006];
        }
    }).catch(e => {
        ctx.body = Tips[1002];
    });
    
});
Copy the code

After verification, the obtained token is stored locally:

store.set('loginedtoken',token); / / store for the plug-inCopy the code

After the client requests the authentication interface, the token will be passed to the server in the request header:

service.interceptors.request.use(config => {
    let params = config.params || {};
    let loginedtoken = store.get('loginedtoken');
    let time = Date.now();
    let{headers} = config; headers = {... headers,loginedtoken}; params = {... params,_:time}; config = {... config,params,headers};return config;
}, error => {
    Promise.reject(error);
})
Copy the code

The server intercepts the token and verifies the validity of all interfaces to be logged in to.

function verifyToken(token){
    let cert = fs.readFileSync(path.join(__dirname, '.. /config/pub.pem')); / / public key try {let result = jwt.verify(token, cert, {algorithms: ['RS256']}) | | {};let {exp = 0} = result,current = Math.floor(Date.now()/1000);
        if(current <= exp){
            res = result.data || {};
        }
    }catch(e){
    
    }
    return res;
    
}

app.use(async(ctx, next) => {
    let {url = ' '} = ctx;
    if(url.indexOf('/user/') > -1){// The login state needs to be verifiedlet header = ctx.request.header;
        let {loginedtoken} = header;
        if (loginedtoken) {
            let result = verifyToken(loginedtoken);
            let {uid} = result;
            if(uid){
                ctx.state = {uid};
                await next();
            }else{
                returnctx.body = Tips[1005]; }}else {
            returnctx.body = Tips[1005]; }}else{ await next(); }});Copy the code

The public and private keys used in this example can be generated as follows:

  1. Open the command line tool and enter openssl to open openssl.
  2. Generate private key:genrsa -out rsa_private_key.pem 2048
  3. Generating a public key: rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem

See the Node backend code here

Click here to see the front-end code