“This is the first day of my participation in the First Challenge 2022. For details: First Challenge 2022.”

background

Recently I have been studying NodeJS and the related framework KOA. Later, I found that I had learned it when I studied, but forgot it when I wanted to use it again after a while. Therefore, I decided to record the knowledge I learned and used in a small demo for easy review and use in the future.

Case introduced

This article uses a simple example to build a back-end service based on NodeJS + KOA. The main function points involved are as follows:

  • Token generation and verification
  • Token verification middleware
  • Routing split and combination of different modules
  • User login and information query API
  • Encapsulate DB-related operations
  • Common tool class encapsulation

Knowledge points and third-party libraries used

  • Jsonwebtoken: Used to generate and verify tokens
  • Koa: Server framework
  • Koa-router: processes routes
  • Koa-static: Processes static resources
  • Koa-bodyparser: Parses post request parameters
  • MSSQL: connects to the SqlServer database
  • Nodeman: automatically restarts the service

Project directory structure

Configure the common class libraries
  • First create a new config.js in the utils directory to add some general configuration information. In this article we add two properties: PRIVATE_KEY and EXPIRED to hold the key and expiration time when the token is generated
// utils/config.js
module.exports = {
	"PRIVATE_KEY":"TOKEN-DEMO-SECRET"."EXPIRED": 60*60*24
}
Copy the code
  • Create a new httpcode.js file in the utils directory that encapsulates some custom HTTP error codes and error messages (optional, depending on personal preference and business needs).
// utils/HttpCode.js
module.exports = {
  Success: {
    success_ok: 2000.success_ok_msg: 'Request successful'.success_created: 2001.success_created_msg: 'Request created'.success_accepted: 2002.success_accepted_msg: 'Request accepted'
  },
  Redirect: {
    redirect_moved_permanently: 3001.redirect_moved_permanently_msg: 'Requested resource has been permanently moved to new location'.redirect_moved_temporarily: 3002.redirect_moved_temporarily_msg: 'Request resource temporarily request from other URL accordingly'.redirect_not_modified: 3004.redirect_not_modified_msg: 'Resource unchanged, fetched directly from negotiated cache'
  },
  RequestError: {
    request_error_bad_request: 4000.request_error_bad_request_msg: 'Invalid request'.request_error_unauthorized: 4001.request_error_unauthorized_msg: 'Request not authorized, check if request header contains token information'.request_error_forbidden: 4003.request_error_forbidden_msg: 'Request rejected, token invalid or expired'.request_error_not_found: 4004.request_error_not_found_msg: 'Requested resource does not exist on server'.request_error_method_not_allowed: 4005.request_error_method_not_allowed_msg: 'Requested mode not allowed'
  },
  ServerError: {
    server_error_internal_error: 5000.server_error_internal_error_msg: 'Server internal error'.server_error_not_imp: 5001.server_error_not_imp_msg: 'Server does not support current request'.server_error_bad_gateway: 5002.server_error_bad_gateway_msg: 'Invalid gateway'}}Copy the code
  • Create a new jwt. js file in the utils directory to encapsulate the token generation and verification methods. The third party library JsonWebToken is introduced to realize the generation and verification of token by means of jsonWebToken’s sign and Verify methods
const jwt = require('jsonwebtoken');
const {PRIVATE_KEY,EXPIRED } = require('./config')
const HttpCode = require('./HttpCode')

class Jwt {
	static generateToken(payload){
		const token = jwt.sign(payload, PRIVATE_KEY,EXPIRED);
		return token;
	}
	static verifyToken(token){
		try{
			let tokenInfo = jwt.verify(token,PRIVATE_KEY, {algorithms: ['HS256']})return HttpCode.Success.success_ok;
		} catch(err){
			returnHttpCode.RequestError.request_error_forbidden; }}}module.exports = Jwt;
Copy the code
Adding Middleware
  • Add a tokenvalidate.js file to the middleware directory, and add middleware to this file to block all requests except login for token validation, and if token exists and is valid, proceed as normal. If the token does not exist or has expired, the request is blocked and an error message is thrown.
const Jwt = require('.. /utils/Jwt')
const HttpCode = require('.. /utils/HttpCode')
module.exports = function (){
	return async function(ctx, next){	
		if(ctx.req.url ! = ='/api/user/login') {const token = ctx.request.header.authorization;// Get the token from the authorization attribute of the request header
			if(token){	
				const status = Jwt.verifyToken(token);
				if(status === HttpCode.RequestError.request_error_forbidden){
					ctx.body = {
						code: HttpCode.RequestError.request_error_forbidden,
						message:HttpCode.RequestError.request_error_forbidden_msg
					}
				}else{
					awaitnext(); }}else{
				ctx.body = {
					code: HttpCode.RequestError.request_error_unauthorized,
					message:HttpCode.RequestError.request_error_unauthorized_msg
				}
			}
		}else{
			await next()
		}
	}
}
Copy the code
Configuring the DB Server
  • Db. js is added in the db directory to configure data related to database operations. This section uses Microsoft SqlServer as an example
// db/db.js
const sql = require('mssql')
const db_server = '127.0.0. L'
const db_name = 'demo'
const config = {
	user:'sa'.password:'admin@123'.server:db_server,
	database:db_name,
	options: {trustServerCertificate: true}}// Encapsulates a common method for getting data
async function dataGet(sql_text){
	try{
		await sql.connect(config);
		const result = await sql.query(sql_text);
		await sql.close();
		return result;
	}catch(err){
		console.log(err)
	}
}

module.exports = {
	dataGet
}
Copy the code
  • Add the db_user.js file in the DB directory to encapsulate some methods related to user operations, such as obtaining user information
// db/db_user.js
const db = require('./db')

function getUserInfo(userNo){
	return db.dataGet("select * from userInfo where userno = `${userNo}`")}module.exports = {
	getUserInfo
}
Copy the code
API package

The ENCAPSULATION of API needs to be realized by means of routing, but it is generally divided into different business modules in a project, and different business modules also have a variety of different interfaces. Therefore, we cannot define all APIS in the same file. Then we need to define multiple routes (KOA-Routers) to encapsulate different business interfaces for different business modules, and finally integrate all routes into one large route.

  • Add the user.js file to the Routers directory and encapsulate some service interfaces related to users. This section uses login routes as an example
// routers/user.js
const Router = require('koa-router')
const Jwt = require('.. /utils/Jwt')
const HttpCode = require('.. /utils/HttpCode')

const router = new Router();
const dbUser = require('.. /db/db_user')

router.post('/login'.async (ctx, next)=>{
	let {name, pwd} = ctx.request.body;
	/ /... The user password verification is omitted
	// If the authentication is successful, the user information will be returned to the front desk
	const result = await dbUser.getUserInfo(name);
	const token = Jwt.generateToken({userInfo: {userName:name}})
	ctx.body = {
		code: HttpCode.Success.success_ok,
		msg:HttpCode.Success.success_ok_msg,
		token:token,
		data:result.recordset
	}
})

module.exports = router;
Copy the code
  • Index.js has been added to the Routers directory to integrate all sub-routes of other service modules as primary routes
// rouers/index.js
const Router = require('koa-router')
const user = require('./user')

const router = new Router({
	prefix:'/api' // Unified route prefix
})

// Integrate business module subroutes
router.use('/user',user.routes(), user.allowedMethods())

module.exports = router;
Copy the code
Configure the main entrance of the server
  • All the preparation work is completed, the next step is to configure our main entry file app.js, in which there are mainly the following operations:
    • To introduce the class library
    • Create a KOA object and call the LISTEN method to start the service
    • Add koastatic middleware to handle static resources
    • Added bodyParser middleware to handle POST request parameter parsing
    • Add tokenValidate middleware to intercept all requests for token validity verification
    • Add routing middleware to process routing information
const Koa = require('koa')
const koastatic = require('koa-static')
const bodyParser = require('koa-bodyparser')
const router = require('./routers')
const TokenValidate = require('./middleware/TokenValidate')

const app = new Koa();

app.listen(3000.function(){
	console.log(`The server started at port: 3000, you can access it by http://localhost:3000`)}); app.use(koastatic('./statics/'));
app.use(bodyParser());
app.use(TokenValidate());
app.use(router.routes());
app.use(router.allowedMethods());
Copy the code

conclusion

To this a simple token generation and verification based on nodeJS + KOa small demo is implemented, although the function is not much, but some basic function points of the server are involved, you can expand the need for partners. Like small partners welcome to add comments and comments oh.