Personal blog development series: Vue.js + Koa.js JWT certification in the project

Time:2020-10-18

preface

JWT (JSON web token) is an open standard based on JSON (RFC 7519) for the purpose of passing statements between network environments.

More introduction and explanation, as well as various principles, I will not repeat here. JWT is not a new thing. There are many related introductions on the Internet. Not very understand, can search for relevant information on the Internet.

Source code

Talk is cheap. Show me the code.

Workflow

JWT is essentially a token. In the front and back end of the HTTP connection to carry out the corresponding verification.

  1. The background management system of the blog initiates the login request, and after the back-end server validates successfully, it generates JWT authentication information;
  2. The front end receives JWT and stores it;
  3. The front-end sends JWT to the back-end in the authorization of HTTP headers parameter every time an interface call initiates an HTTP request;
  4. When receiving the request, the back-end will check whether the user who initiated the HTTP request has access rights according to the information in JWT. If the user has access rights, it will be handed over to the server to continue processing. If not, 401 error will be returned directly.

Implementation process

1. Login successfully and generate JWT

Note: the following code only retains the core code, the detailed code can be viewed in the corresponding file, the same below.

// /server/api/admin/admin.controller.js
const jwt = require('jsonwebtoken');
const config = require('../../config/config');

exports.login = async(ctx) => {
  // ...
  if (hashedPassword === hashPassword) {
    // ...
    //User token
    const userToken = {
      name: userName,
      id: results[0].id
    };
    //Issue token
    const token = jwt.sign(userToken, config.tokenSecret, { expiresIn: '2h' });
    // ...
  }
  // ...
}

2. Add middleware to verify JWT

// /server/middlreware/tokenError.js
const jwt = require('jsonwebtoken');
const config = require('../config/config');
const util = require('util');
const verify = util.promisify(jwt.verify);

/**
 *Determine whether token is available
 */
module.exports = function () {
  return async function (ctx, next) {
    try {
      //Get JWT
      const token = ctx.header.authorization; 
      if (token) {
        try {
          //Decrypt payload to get user name and ID
          let payload = await verify(token.split(' ')[1], config.tokenSecret);
          ctx.user = {
            name: payload.name,
            id: payload.id
          };
        } catch (err) {
          console.log('token verify fail: ', err)
        }
      }
      await next();
    } catch (err) {
      if (err.status === 401) {
        ctx.status = 401;
        ctx.body = {
          success: 0,
          Message: 'authentication failed'
        };
      } else {
        err.status = 404;
        ctx.body = {
          success: 0,
          message: '404'
        };
      }
    }
  }
}

Three Koa.js Add JWT processing in

Here, you need to filter out the login interface during development, otherwise JWT verification will fail forever.

// /server/config/koa.js
const jwt = require('koa-jwt');
const tokenError = require('../middlreware/tokenError');
// ...

const app = new Koa();

app.use(tokenError());
app.use(bodyParser());
app.use(koaJson());
app.use(resource(path.join(config.root, config.appPath)));

app.use(jwt({
  secret: config.tokenSecret
}).unless({
  path: [/^\/backapi\/admin\/login/, /^\/blogapi\//]
}));

module.exports = app;

4. Front end processing

Front end development uses Vue.js The HTTP request is sent using Axios.

  1. After successful login, store JWT in localstorage (it can be stored according to personal needs. I prefer to store JWT in localstorage).

    methods: {
        login: async function () {
          // ...
    
          let res = await api.login(this.userName, this.password);
          if (res.success === 1) {
            this.errMsg = '';
            localStorage.setItem('DON_BLOG_TOKEN', res.token);
            this.$router.push({ path: '/postlist' });
          } else {
            this.errMsg = res.message;
          }
        }
      }

  2. Vue.js Verify the existence of JWT before the router jump. If not, jump to the login page.

    // /src/router/index.js
    router.beforeEach((to, from, next) => {
      if (to.meta.requireAuth) {
        const token = localStorage.getItem('DON_BLOG_TOKEN');
        if (token && token !== 'null') {
          next();
        } else {
          next('/login');
        }
      } else {
        next();
      }
    });

  3. Add authorization information to HTTP in Axios interceptor

    // /src/fetch/fetch.js
    axios.interceptors.request.use(
      config => {
        const token = localStorage.getItem('DON_BLOG_TOKEN');
        if (token) {
          //Bearer is the authentication header information of JWT
          config.headers.common['Authorization'] = 'Bearer ' + token;
        }
        return config;
      },
      error => {
        return Promise.reject(error);
      }
    );

  4. The Axios interceptor processes the return status uniformly when it receives the HTTP return

    // /src/main.js
    axios.interceptors.response.use(
      response => {
        return response;
      },
      error => {
        if (error.response.status === 401) {
          Vue.prototype.$msgBox.showMsgBox({
            Title: 'error prompt',
            Content: 'your login information is invalid, please login again',
            isShowCancelBtn: false
          }).then((val) => {
            router.push('/login');
          }).catch(() => {
            console.log('cancel');
          });
        } else {
          Vue.prototype.$message.showMessage({
            type: 'error',
            Content: 'system error'
          });
        }
        return Promise.reject(error);
      }
    );

summary

The whole process is finished here. Of course, JWT is not absolutely secure, but it is enough for the authentication of a personal blog system.

Finally, I’ll make a small advertisement. At present, a new version of personal blog is being developed, including the front-end and back-end parts, which have been open-source on GitHub, and are gradually improving their functions. Welcome interested students fork and star.