JWT

Json Web Token (JWT) is an open jSON-based standard ([(RFC 7519]) implemented for the transfer of declarations between network application environments. The token is designed to be compact and secure, especially suitable for single sign-on (SSO) scenarios in distributed sites. The JWT declaration is generally used to pass authenticated user identity information between the identity provider and the service provider to obtain resources from the resource server, and to add some additional declaration information necessary for other business logic. The token can also be used directly for authentication or can be encrypted.

JWT certification process

  • The user requests the server using a username and password
  • The server authenticates the user’s information
  • The server sends the user a token through authentication
  • The client stores the token and supplies it with each request
  • The server validates the token value and returns data

The main difference between session-based and JWT-BASED approaches is where the user’s state is stored. The Session is stored on the server, while the JWT is stored on the client.

Once a JWT is issued, it remains valid until it expires and cannot be abandoned.

Eggjs implements the signing and authentication of tokens

Install dependencies

# jwt
npm i egg-jwt
# password encryption
bcryptjs
# Data verification
egg-validate
Copy the code

The use of plug-in

config/plugin.js

jwt: {
  enable: true.package: 'egg-jwt',},validate: {
  enable: true.package: 'egg-validate',},Copy the code

Modifying a Configuration File

config/config.default.js

// jwt
config.jwt = {
  secret: '123456'.expiresIn: '24h'};/ / parameters
config.validate = {
  enable: true.package: 'egg-validate'};// Password encryption
config.bcrypt = {
  saltRounds: 10};Copy the code

User registration, login interface development

Creating a user model

app/model/user.js

'use strict';

module.exports = app= > {
  const { STRING, INTEGER, DECIMAL, DATE } = app.Sequelize;

  const User = app.model.define('users', {
    id: { type: INTEGER, primaryKey: true.autoIncrement: true },
    userName: {
      type: STRING,
      allowNull: false.unique: true.comment: 'Username, unique',},passWord: STRING,
  });

  return User;
};
Copy the code

user Controller

app/controller/user.js

// Verify user registration parameters
const vUser = {
  userName: { type: 'string'.required: true },
  passWord: { type: 'string'.required: true}};/ /...
class UserController extends Controller {
    // User registration
  async rigist() {
    const { ctx } = this;
    // Accept and validate parameters
    ctx.validate(vUser, ctx.request.body);
    // Check whether the user name is the same
    const users = await ctx.service.user.checkUserName(ctx.request.body);
    if (users[0]) {
      ctx.body = { status: false.msg: 'Username already exists'.data: users };
      return;
    }
    await ctx.service.user.Rigist(ctx.request.body);
    ctx.body = { status: true.msg: 'Registration successful' };
  }

  // The user logs in
  async login() {
    const { ctx } = this;
    // Accept and validate parameters
    ctx.validate(vUser, ctx.request.body);
    const data = await ctx.service.user.Login(ctx.request.body);
    if(! data) { ctx.status =401;
      ctx.body = { status: false.msg: 'Wrong username or password' };
      return;
    }
    ctx.body = { status: true.msg: 'Successful landing', data }; }}module.exports = UserController;
Copy the code

user Service

app/service/user.js

const bcrypt = require('bcryptjs');

/ /...


// Check the user name
async checkUserName(query) {
  const { userName } = query;
  const users = await this.ctx.model.User.findAll({
    attributes: [ 'userName'].where: { userName },
  });
  return users;
}


// User registration
async Rigist(body) {
  const { userName, passWord } = body;
  // Encrypt the password
  const hash = bcrypt.hashSync(passWord, this.config.bcrypt.saltRounds);
  const user = await this.ctx.model.User.create({ userName, passWord: hash });
  return user;
}


// The user logs in
async Login(body) {
  const { userName, passWord } = body;
  const user = await this.ctx.model.User.findOne({
    where: { userName },
  });
  if(! user)return {};

  const match = await bcrypt.compare(passWord, user.passWord);
  if (match) {
    const { id, userName } = user;
    // Get JWT configuration
    const { jwt: { secret, expiresIn } } = this.app.config;
    / / token is generated
    const token = this.app.jwt.sign({
      id, userName,
    }, secret, { expiresIn });
    return{ userName, token }; }}Copy the code

router

app/router.js

router.post('/api/v1/user/rigist', controller.user.rigist); // User registration
router.post('/api/v1/user/login', controller.user.login); // The user logs in

// Add JWT middleware to the route to use JWT authentication
router.put('/api/v1/user/:id', app.jwt, controller.user.update); // Modify user information
Copy the code

Obtaining token Content

If the interface uses app.jWT middleware

const userToken = this.ctx.state.user;
// Get the content id, userName,
Copy the code

If the interface does not use app.jwt middleware, this.ctx.state.user cannot be retrieved;

Some interfaces may or may not be logged in, and data acquisition is different.

In this case, you need to encapsulate the method to resolve the token

app/extend/utils.js

'use strict';

function getTokenInfo(jwt, auth, secret) {
  // Determine whether the request header contains the token
  if (
    auth.authorization &&
    auth.authorization.split(' ') [0= = ='Bearer'
  ) {
    const token = auth.authorization.split(' ') [1];
    let decode = ' ';
    if (token) {
      decode = jwt.verify(token, secret);
    }
    return decode;
  }
  return;
}

module.exports = {
  getTokenInfo,
};

Copy the code

Use in service

const { jwt: { secret } } = this.app.config;
// Resolve the token if there is one
const authInfo = getTokenInfo(this.ctx.app.jwt, this.ctx.headers, secret);
if (authInfo) {
  // Get the token content
  // authInfo.id authInfo.userName
}
Copy the code