vue + koa2 implements session | token login status verification

Differences between Session landing and Token landing

1. Session login is to generate user-related session data on the server side and send the session_id to the client side to store in cookies, so that when the client requests, session_id can verify the existence of session data on the server side, so as to complete user authentication. This authentication method can better control the session on the server side and has high security (session_id is random), but the server needs to store session data (such as memory or database), which undoubtedly increases maintenance costs and reduces scalability (multiple servers). CSRF attacks are generally based on cookies. In addition, if native app s use this service interface, because there is no browser cookie function, access will be relatively troublesome.
2. User authentication based on token is a stateless authentication method on the server side, which does not need to store token data. After user authentication, the server generates a token(hash or encrypt) and sends it to the client. The client can put token in cookie or local Storage. Each request brings token in the Header. The server receives token and confirms the user's identity after verification. This method is simpler than cookie authentication. The server does not need to store authentication data. It is easy to maintain and expand. Local Storage in token can avoid CSRF. web and app applications are relatively simple. However, this approach has some performance overhead (as if it is not very large) when encrypting or decrypting, and some symmetric encryption has security risks (aes cbc byte flip attacks).

koa + session login verification

1. First, install the koa-sisson package

npm install koa-session -S

koa-session actually saves information through cookies. koa-session generates a message on the server. After encryption, it is sent to the user's browser in the form of cookie. It can be seen as an encrypted cookie field on the user's browser. Then it gets the xx information through ctx.session.xx in the server-side routing. Each time a user sends a request, the cookie can be obtained. koa-sesscion decrypts the original stored information for us internally, so we can check whether the user has logged in by judging whether the cookie exists.

2. Initialization in app.js

const Koa = require('koa')
const app = new Koa()
const session = require('koa-session')
const bodyParser = require('koa-bodyparser')
const Router = require('koa-router')
const router = new Router()

const CONFIG = {
  key: 'koa:sess', /** (string) cookie key (default is koa:sess) cookie Name */
  /** (number || 'session') maxAge in ms (default is 1 days) */
  /** 'session' will result in a cookie that expires when session/browser is closed */
  /** Warning: If a session cookie is stolen, this cookie will never expire */
  maxAge: 86400000, /** cookie Overdue time */
  autoCommit: true, /** (boolean) automatically commit headers (default true) */
  overwrite: true, /** (boolean) can overwrite or not (default true) */
  httpOnly: true, /** (boolean) httpOnly or not (default true) */
  signed: true, /** (boolean) signed or not (default true) */
  rolling: false, /** (boolean) Force a session identifier cookie to be set on every response. The expiration is reset to the original maxAge, resetting the expiration countdown. (default is false) */
  renew: false, /** (boolean) renew session when session is nearly expired, so we can always keep user logged in. (default is false)*/
}
app.keys = ['login secret'] // encryption key
app.use(session(CONFIG, app));

app.use(bodyParser())
app.use(router.routes()).use(router.allowedMethods())

3. Landing Routing

router.post('/login', async (ctx) => {
  try {
    const data = ctx.request.body.data
    const { username, password } = data
    if (true) {
      // Save the login status, and this code generates a cookie with "koa:sess" as Name in the browser
      ctx.session.userInfo = {username: '', userID: ''}
      ctx.body = {code: 1, message: 'Successful landing'}
    } else {
      ctx.body = {code: 0, message: 'Error in account or password'}
    }
  } catch(err) {
    throw new Error(err)
  }
})

// Front end
axios.post('/login', {username: '', password: ''}).then(res => {})

4. Check whether it has landed

router.get('/getSession', async (ctx) => {
  try {
    if (ctx.session.userInfo) {
      ctx.body = {code: 1, message: 'Landed'}
    } else {
      ctx.body = {code: 0, message: 'Unlanded'}
      // Jump to the login page
      // ctx.response.redirect('/login') 
    }
  } catch(err) {
    throw new Error(err)
  }
})

// Front end
axios.get('/getSession').then(res => {})

5. Exit landing

router.post('/logout', async (ctx) => {
  try {
    // Clear the login information
    ctx.session = null
    // Jump to the login page or the home page of the website
    ctx.response.redirect('/')
  } catch(err) {
    throw new Error(err)
  }
})

// Front end
axios.post('/logout').then(res => {})

koa + token login verification

1. Install the JSON webtoken package

npm install jsonwebtoken -S

2. app.js initialization

const Koa = require('koa')
const app = new Koa()
const jwt = require('jsonwebtoken')
const bodyParser = require('koa-bodyparser')
const Router = require('koa-router')
const router = new Router()
const tokenConfig = {privateKey: 'xxxxxxxxxxxx'} // encryption key

app.use(bodyParser())
app.use(router.routes()).use(router.allowedMethods())

3. Landing Routing

router.post('/login', async (ctx) => {
  try {
    const data = ctx.request.body.data
    const { username, password } = data
    if (true) {
      const userInfo = {username: '', userID: ''}
      const token = jwt.sign(userInfo, tokenConfig.privateKey, {expiresIn: '7d'}) // Issuance of token, valid for 7 days
      ctx.body = {code: 1, message: 'Successful landing', data: {token: 'Bearer ' + token}}
    } else {
      ctx.body = {code: 0, message: 'Error in account or password'}
    }
  } catch(err) {
    throw new Error(err)
  }
})

Front-end landing

axios.post('/login', {username: '', password: ''}).then(res => {
  if (res.data.code === 1) {
    localStorage.setItem('token', res.data.data.token)
    // vuex stores userInfo and login status
    store.commit('SET_USERINFO', {userInfo: res.data.data.userInfo, status: true})
  }
})

4. Check whether it has landed

router.get('/getUserInfo', async (ctx) => {
  try {
    const token = ctx.get('Authorization') // Get the Authorization value in the request Header
    let userInfo = {}
    if (token === '') {
      ctx.body = {code: 0, message: 'Unlanded'}
    } else {
      try {
        userInfo = jwt.verify(token.split(' ')[1], tokenConfig.privateKey) // Verify token
        ctx.body = {code: 1, message: 'Landed', data: {userInfo: userInfo: loginStatus: true}}
      } catch(err) {
        // token expires or is invalid
        ctx.body = {code: 0, message: 'Unlanded', data: {userInfo: {}: loginStatus: false}}}
      }
    }
  } catch(err) {
    throw new Error(err)
  }
})

To bring token information to each request, set up request interception for axios

// Request interception, with token in the header of each request
axios.interceptors.request.use(config => {
  let token = localStorage.getItem('token')
  if (token) {
    config.headers.common.Authorization = token
  }
  return config
}, error => {
  return Promise.reject(error);
})

Before entering the page, I have to decide whether I have logged in and whether I have permission to enter the page. Before that, I asked'/ getUserInfo'in the create hook function of each page to determine whether I am logged in. This is tedious, and the page will be presented first, then flash by (in case of verification, however), on the road. Global configurability from hook functions

// Routing guard, executed before jumping
router.beforeEach((to, from, next) => {
  let token = localStorage.getItem('token')
  let requireAuth = to.meta.requireAuth // Whether the configuration page in VueRouter needs to be logged in or not
  let root = to.meta.root // Whether the configuration page in VueRouter needs to be logged in and administrator access
  if (!token) {
    // vuex clears userInfo and login status
    store.commit('SET_USERINFO', {userInfo: {}, status: false})
    requireAuth ? next({path: '/'}) : next()
  } else {
    axios.get(API.getUserInfo).then(res => {
      // vuex stores userInfo and login status
      store.commit('SET_USERINFO', {userInfo: res.data.userInfo, status: res.data.loginStatus})
      if (requireAuth) {
        if (!res.data.loginStatus || (root && !res.data.userInfo.root)) {
          next({path: '/'})
        } else {
          next()
        }
      } else {
        next()
      }
    })
  }
})

/** VueRouter
{
  path: '/admin',
  name: 'admin',
  meta: {
    requireAuth: true,
    root: true
  },
}
*/

5. Exit landing

Because the server does not store user login information, it is only related to whether token exists in the front end or whether it can be verified, so it is enough to clear token when logged out.

methods: {
  logout() {
    localStorage.removeItem('token')
    // vuex clears landing information
    store.commit('SET_USERINFO', {userInfo: {}, status: false})
    if (this.$route.path !== '/') {
      this.$router.push({path: '/'})
    }
  }
}

Programmer Vocabulary Learning Network: www.english4coder.com

Keywords: Javascript Session axios npm Database

Added by shwanky on Thu, 29 Aug 2019 15:14:01 +0300