1. What is

json web token
Copy the code

Advantages:

  • No state,
  • Cross domain,
  • Can convert JSON objects into tokens through JWT and restore JSON objects
  • Encryption security

2. The format

  • header.payload.signature
  • Such as: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiJiMDhmODZhZi0zNWRhLTQ4ZjItOGZhYi1jZWYzOTA0NjYwYmQifQ.-xN_h82PHVTCMA9v doHrcZxH-x5mb11y1537t3rGzcM

1. Header encryption mode

  • Represents the encryption that can be decrypted, a JSON object that describes the metadata of the JWT
  • Declare type, in this case JWT
  • Algorithms that declare encryption usually use HMAC SHA256 directly
Such as: {"typ":"JWT"."alg":"HS256"}
Copy the code

2. Payload Transmits the content

  • Represents the specific transmission content can be decrypted, a JSON object
  • 3 Components
  1. A declaration of registration in a standard
  2. Public statement
  3. Private declaration

// Include the user information to be passed;

{ 
  / / standard
  "iss": "Online JWT Builder"."iat": 1416797419."exp": 1448333419."aud": "www.gusibi.com"."sub": "uid".// Public/private
  "nickname": "goodspeed"."username": "goodspeed"."scopes": [ "admin"."user"]}Copy the code

3. Sign signature

  • Signature: Encrypts (payload+secret) = encrypts results using the encryption method described in the header
  • The secret private key is saved by the user

4. JWT control flow chart of Egg

3. The actual combat

1. The client requests Settings

Vue /nuxt sets the header information

// /plugins/axios.js
import Vue from 'vue'
import axios from 'axios' 
let service = axios.create({
  timeout:5000./ / prefix
  baseURL:'/api'
})
const TOKEN_KEY = 'USER_TOKEN'

// @todo interceptor manages tokens
export default({store, redirect})=>{
  // Request interception
  service.interceptors.request.use(
    config= >{
      // Request a token
      const token = window.localStorage.getItem(TOKEN_KEY)
      // Set the URL whitelist
      if(token){
        config.headers.common['Authorization'] = 'Bearer '+token // Add Bearer space format used by JWT
      }
      return config
    },
    err= >{
      return Promise.reject(err)
    }
  )
}
Copy the code

2.1 Egg-JWT back-end implementation

NPM I egg-jwt-s // install libraryCopy the code
//config/plugin.js
jwt:
{ enable: true.package: 'egg-jwt',}//config/config.default.js
  config.jwt = {
    secret: 'Great4-M'.enable: true.// default is false
    match: /^\/api/.// optional
  }
//service/actionToken.js
// Generate a token. The _id is the database ID
const { Service } = require('egg')
class ActionTokenService extends Service {
    async apply(_id) {
        const { ctx } = this
        return ctx.app.jwt.sign({
            data: {
                _id: _id
            },
            exp: Math.floor(Date.now() / 1000 + (60 * 60 * 7))
        }, ctx.app.config.jwt.secret)
    }

}
module.exports = ActionTokenService

//service/userAccess.js
const { Service } = require('egg')
class UserAccessService extends Service {
    async login(payload) {
        const { ctx, service } = this
        const user = await service.user.findByMobile(payload.mobile)
        console.log('88888mobile'+payload.moblie)
        if(! user) { ctx.throw(404.'user not found')}let verifyPsw = await ctx.compare(payload.password, user.password)
        if(! verifyPsw) { ctx.throw(404.'user password is error')}// Generate a Token
        return { token: await service.actionToken.apply(user._id) }
    }
    async logout(){}async current() {
        const { ctx, service } = this
        // ctx.state.user can extract jWt-encoded data
        const _id = ctx.state.user.data._id
        const user = await service.user.find(_id)
        if(! user) { ctx.throw(404.'user is not found')
        }
        user.password = 'How old are you? '
        return user
    }
}

module.exports = UserAccessService

// app/contract/userAccess.js
module.exports = {
    loginRequest: {
      mobile: { type: 'string'.required: true.description: 'Mobile phone Number'.example: '1880000000'.format: /^1[34578]\d{9}$/,},password: { type: 'string'.required: true.description: 'password'.example: '111111',,}}}//controller/userAccess.js
'use strict'
const Controller = require('egg').Controller
/ * * *@Controller User authentication */
class UserAccessController extends Controller {

  constructor(ctx) {
    super(ctx)
  }

  / * * *@summary User Login@description User Login@router post /auth/jwt/login
   * @request body loginRequest *body
   * @response 200 baseResponse created successfully */
  async login() {
    const { ctx, service } = this
    // Check parameters
    ctx.validate(ctx.rule.loginRequest);
    // Assemble parameters
    const payload = ctx.request.body || {}

    // Call Service for business processing
    const res = await service.userAccess.login(payload)
    // Set the response content and response status code
    ctx.helper.success({ ctx, res })
  }

  / * * *@summary User logs out *@description User logs out *@router post /auth/jwt/logout
   * @request body loginRequest *body
   * @response 200 baseResponse created successfully */
  async logout() {
    const { ctx, service } = this
    // Call Service for business processing
    await service.userAccess.logout()
    // Set the response content and response status code
    ctx.helper.success({ ctx })
  }
}

module.exports = UserAccessController

Copy the code

2.2 Custom registration middleware, egg back-end implementation

NPM I jsonWebToken -s // install JWTCopy the code

server/config/config.default.js  
module.exports = appInfo= > { 
  return{... config, ... userConfig,jwt: {
      secret: 'xxxxxxx'.// Define configuration information}}},//app/middleware/jwt.js
// The middleware that parses tokens can also use egg-jwt, which is more suitable for understanding the principle
const jwt = require('jsonwebtoken')
module.exports = ({ app }) = > {
  return async function verify(ctx, next) {
    if(! ctx.request.header.authorization) { ctx.body = {code: -Awesome!.message: 'User not logged in',}return
    }
    const token = ctx.request.header.authorization.replace('Bearer '.' ')
    try {
      const ret = await jwt.verify(token, app.config.jwt.secret)
      ctx.state.email = ret.email
      ctx.state.userid = ret._id
      await next()
    } catch (err) {
      console.log(err)
      if (err.name === 'TokenExpiredError') {
        ctx.body = {
          code: -Awesome!.message: 'Login expired',}}else {
        ctx.body = {
          code: -1.message: 'User information error',}}}}}//app/router.js 
module.exports = app= > {
  const { router, controller } = app
  const jwt = app.middleware.jwt({ app })
  router.get('/', controller.home.index)

  router.group({ name: 'user'.prefix: '/user' }, router= > {
    const {
      info,login, register,
    } = controller.user
    router.post('/register', register)
    router.post('/login', login) 
    router.get('/info', jwt, info) // Add JWT validation for those requiring authentication}}//app/controller/user.js
const md5 = require('md5')
const jwt = require('jsonwebtoken')
const BaseController = require('./base')
const HashSalt = 'xxxxxx11223' 

class UserController extends BaseController {

  async login() {
    // this.success('token')
    const { ctx, app } = this
    const { email, captcha, passwd, emailcode } = ctx.request.body  
    const user = await ctx.model.User.findOne({
      email,
      passwd: md5(passwd + HashSalt),
    })
    if(! user) {return this.error('Wrong username and password')}// The user's information is encrypted into a token and returned
    const token = jwt.sign({
      _id: user._id,
      email,
    }, app.config.jwt.secret, {
      expiresIn: '100h',})this.success({ token, email, nickname: user.nickname })
  } 
}

module.exports = UserController



Copy the code