国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

基于NodeJs+Express+MySQL 實現(xiàn)實現(xiàn)登錄注冊接口+token生成與解析驗證+跨域-CORS

這篇具有很好參考價值的文章主要介紹了基于NodeJs+Express+MySQL 實現(xiàn)實現(xiàn)登錄注冊接口+token生成與解析驗證+跨域-CORS。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

目錄

一、express是什么?

二、安裝?express

三、安裝Mysql

四、安裝 nodemon 實現(xiàn)項目熱更新

五、這里先了解下express的post get delete接口

post接口說明:

get接口說明?:

?DELETE 接口

六、注冊功能

1、流程分析

校驗表單數(shù)據(jù)是否合法

檢測用戶名是否占用

密碼加密處理

插入新用戶

2、完整注冊接口

regUser(req, res) 注冊函數(shù)

七、封裝錯誤處理函數(shù)(即:注冊功能使用的res.cc)

八、登錄功能

1、流程分析

1.判斷前端提交的后端的數(shù)據(jù)是否合法。

2.查詢登錄的用戶是否存在。

3.判斷當(dāng)前用戶的密碼是否正確。

2、生成token字符

?1.安裝jsonwebtoken用于生成token

2.導(dǎo)入jsonwebtoken

?3.全局配置文件(里面有token的密鑰)

3.使用jwt.sign對用戶的信息進(jìn)行加密,生成 token 字符串?

4.登錄成功后將生成的token返回給客戶端

3、登錄接口的完整代碼

1.login()登錄函數(shù)代碼

九、最后附上users路由模塊和登錄注冊函數(shù).js的完整代碼

users.js

login.js登錄注冊函數(shù)

接口文檔:

十、解析token中間件

?1.安裝解析中間件

2.在App.js 中引入

3.注冊全局中間件并解析token

4.注冊全局錯誤中間件 當(dāng)token失效時 返回信息

十一、CORS跨域中間件

?1. 使用 cors 中間件解決跨域問題

完整代碼:(jsonp就不做過多解釋了)

1、CORS 響應(yīng)頭部 - Access-Control-Allow-Origin

2、CORS 響應(yīng)頭部 - Access-Control-Allow-Headers

3、CORS 響應(yīng)頭部 - Access-Control-Allow-Methods

4、?CORS請求的分類

5、 簡單請求

6、預(yù)檢請求


一、express是什么?

  1. Express 是一個簡潔而靈活的 node.js?Web應(yīng)用框架, 提供了一系列強大特性幫助你創(chuàng)建各種 Web 應(yīng)用,和豐富的 HTTP 工具。
  2. 使用 Express 可以快速地搭建一個完整功能的網(wǎng)站。
  3. Express 框架核心特性:
  • 可以設(shè)置中間件來響應(yīng) HTTP 請求。

  • 定義了路由表用于執(zhí)行不同的 HTTP 請求動作。

  • 可以通過向模板傳遞參數(shù)來動態(tài)渲染 HTML 頁面。

二、安裝?express

搭建Express項目有兩種方式:

  • 方式一:從零搭建自己的express應(yīng)用結(jié)構(gòu)
  • 方式二:安裝express-generator腳手架 一鍵生成express項目

在這里我們使用方式二快速構(gòu)建一個express項目:

????????express-generator 是 Express 應(yīng)用程序生成器工具,我們可以使用它來快速創(chuàng)建應(yīng)用程序框架。

  1. 在項目文件夾下打開node終端
  2. 安裝express-generator 腳手架

    npm install -g express-generator
  3. 創(chuàng)建項目
    express expressFrame (expressFrame 是項目名)

? ? ? ? ?執(zhí)行完后項目目錄下的結(jié)構(gòu)

nodejs 實現(xiàn)登錄,Express,nodejs,express,node.js?

?注:bin/www 是啟動入口文件,在里面可以設(shè)置端口號等

3.?安裝依賴

npm install

4. 啟動項目
?

npm start

nodejs 實現(xiàn)登錄,Express,nodejs,express,node.js

此時在瀏覽器打開?http://localhost:3000/

nodejs 實現(xiàn)登錄,Express,nodejs,express,node.js

?出現(xiàn)以上頁面,那么恭喜你express服務(wù)器已創(chuàng)建完成

三、安裝Mysql

npm i mysql

1、新建db 數(shù)據(jù)庫文件夾,文件夾下新建index.js 用來配置數(shù)據(jù)庫信息,index.js內(nèi)容如下

// 導(dǎo)入 mysql 模塊
const mysql = require('mysql')
// 建立與 MySQL 數(shù)據(jù)庫的連接
const db = mysql.createPool({
	host: '127.0.0.1', // 數(shù)據(jù)庫的IP地址
	port: 3306, //數(shù)據(jù)庫端口號
	user: 'web2245321733', // 登錄數(shù)據(jù)庫的賬號
	password: 'web2245321733', // 登錄數(shù)據(jù)庫的密碼
	database: 'web2245321733' // 指定要操作哪個數(shù)據(jù)庫
})

// 檢測數(shù)據(jù)庫是否連接成功
db.query("select 1", (err, results) => {
	if (err) return console.log(err);
	console.log(results, '數(shù)據(jù)庫鏈接成功');
});

module.exports = db

此時重啟項目,終端看到打印出數(shù)據(jù)庫鏈接成功,nodejs 實現(xiàn)登錄,Express,nodejs,express,node.js

四、安裝 nodemon 實現(xiàn)項目熱更新

在剛才的添加數(shù)據(jù)庫當(dāng)中,我們發(fā)現(xiàn)每次修改代碼都需要重啟項目,非常麻煩

1、安裝 nodemon 來監(jiān)控 node.js 源代碼的任何變化和自動重啟你的服務(wù)器

npm install -g nodemon

2、在package.json中修改啟動命令

nodejs 實現(xiàn)登錄,Express,nodejs,express,node.js

?然后重啟項目,就可以了。

五、這里先了解下express的post get delete接口

post接口說明:

// 定義 POST 接口
router.post('/post', (req, res) => {
  // 通過 req.body 獲取請求體中包含的 url-encoded 格式的數(shù)據(jù)
  const body = req.body
  // 調(diào)用 res.send() 方法,向客戶端響應(yīng)結(jié)果
  res.send({
    status: 0, // 0 表示處理成功,1 表示處理失敗
    msg: 'POST 請求成功!', // 狀態(tài)的描述
    data: body, // 需要響應(yīng)給客戶端的數(shù)據(jù)
  })
})

get接口說明?:

// 在這里掛載對應(yīng)的路由
router.get('/get', (req, res) => {
  // 通過 req.query 獲取客戶端通過查詢字符串,發(fā)送到服務(wù)器的數(shù)據(jù)
  const query = req.query
  // 調(diào)用 res.send() 方法,向客戶端響應(yīng)處理的結(jié)果
  res.send({
    status: 0, // 0 表示處理成功,1 表示處理失敗
    msg: 'GET 請求成功!', // 狀態(tài)的描述
    data: query, // 需要響應(yīng)給客戶端的數(shù)據(jù)
  })
})

?DELETE 接口

// 定義 DELETE 接口
router.delete('/delete', (req, res) => {
  res.send({
    status: 0,
    msg: 'DELETE請求成功',
  })
})

參數(shù)說明:

  • router.post 用于創(chuàng)建post接口? 它有兩個參數(shù) 參數(shù)1:路由匹配規(guī)則? ? 參數(shù)2:請求的回調(diào)函數(shù)
  • 回調(diào)函數(shù)的req參數(shù):客戶端請求信息,包括 請求頭 請求參數(shù)等,req.bodey或req.query獲取請求參數(shù)
  • 回調(diào)函數(shù)的res參數(shù):用于提交服務(wù)端的響應(yīng)給客戶端
  • 調(diào)用 res.send() 方法,向客戶端響應(yīng)處理的結(jié)果

六、注冊功能

1、流程分析

注冊的一般流程 1.校驗表單數(shù)據(jù)是否合法 2.檢測用戶名是否占用 3.密碼加密處理 4.插入新用戶

校驗表單數(shù)據(jù)是否合法

// 通過 req.body 獲取請求體中包含的 url-encoded 格式的數(shù)據(jù)
	const userInfo = req.body
	//【步驟一】對客戶端的數(shù)據(jù)進(jìn)行校驗
	if (userInfo.username == '' || userInfo.password == '') {
		return res.send({
			status: 1,
			msg: '用戶名和密碼不能為空'
		})
	}

檢測用戶名是否占用

// 定義sql語句,查詢用戶名是否被占用
	let sql = 'select * from ev_users where username=?'
	db.query(sql, [userInfo.username], (error, result) => {
		if (error) {
			return res.cc(error)
		}
		if (result.length > 0) {
			return res.cc('用戶名已被占用!')
		}
	})

密碼加密處理

安裝bcryptjs 加密包 用于密碼加密

npm i bcryptjs

?引入加密包

// 導(dǎo)入 bcryptjs 加密包
const bcrypt = require('bcryptjs')

調(diào)用 bcrypt.hashSync() 對密碼加密

// 調(diào)用 bcrypt.hashSync() 對密碼加密
		userInfo.password = bcrypt.hashSync(userInfo.password, 10)

?說明:bcrypt.hashSync() 的參數(shù)1:要加密的密碼? 參數(shù)2:?加密等級 填10即可

插入新用戶

前面我們已經(jīng)連接過數(shù)據(jù)庫了,這里我們直接引入數(shù)據(jù)庫操作模塊

// 導(dǎo)入數(shù)據(jù)庫操作模塊
const db = require('../../db/index')

?定義插入新用戶的 SQL 語句

// 定義插入新用戶的 SQL 語句
		let sql1 = 'insert into ev_users set ?'

?調(diào)用 db.query() 執(zhí)行 sql 語句 插入新用戶 并給客戶端返回結(jié)果

// 調(diào)用 db.query() 執(zhí)行 sql 語句
		db.query(sql1, {
			username: userInfo.username,
			password: userInfo.password
		}, (error, result) => {
			if (error) return res.cc(error)
			// 判斷影響行數(shù)是否為 1
			if (result.affectedRows !== 1) return res.cc('注冊用戶失?。?)
			return res.cc('注冊用戶成功', 0, {
				username: userInfo.username
			})
		})

2、完整注冊接口

  • 打開routes文件夾下的users.js 路由模塊,添加以下內(nèi)容
/**
 * POST 用戶注冊
 * @param username  用戶名
 * @param password  用戶密碼
 */
router.post('/add', (req, res, next) => {
	// 通過 req.body 獲取請求體中包含的 url-encoded 格式的數(shù)據(jù)
	console.log(req.body)
	const userInfo = req.body
	//【步驟一】對客戶端的數(shù)據(jù)進(jìn)行校驗
	if (userInfo.username == '' || userInfo.password == '') {
		return res.send({
			status: 1,
			msg: '用戶名和密碼不能為空'
		})
	}
	// 【步驟二】執(zhí)行定義好的注冊函數(shù)
	regUser(req, res)
});

regUser(req, res) 注冊函數(shù)

在這里我單獨新建了個login.js文件用于寫注冊和登錄的處理的函數(shù)放

nodejs 實現(xiàn)登錄,Express,nodejs,express,node.js?

?引入

// 導(dǎo)入寫好的注冊/登錄函數(shù)
const {
	regUser,
	login
} = require('../public/javascripts/login')

regUser(req, res) 注冊函數(shù)內(nèi)容如下:

// 導(dǎo)入數(shù)據(jù)庫操作模塊
const db = require('../../db/index')
// 導(dǎo)入 bcryptjs 加密包
const bcrypt = require('bcryptjs')

/**
 * POST 用戶注冊
 * @param username  用戶名
 * @param password  用戶密碼
 */
exports.regUser = (req, res) => {
	// 獲取客戶端提交到服務(wù)器的用戶信息
	const userInfo = req.body
	// 定義sql語句,查詢用戶名是否被占用
	let sql = 'select * from ev_users where username=?'
	db.query(sql, [userInfo.username], (error, result) => {
		if (error) {
			return res.cc(error)
		}
		if (result.length > 0) {
			return res.cc('用戶名已被占用!')
		}
		// 調(diào)用 bcrypt.hashSync() 對密碼加密
		userInfo.password = bcrypt.hashSync(userInfo.password, 10)
		// 定義插入新用戶的 SQL 語句
		let sql1 = 'insert into ev_users set ?'
		// 調(diào)用 db.query() 執(zhí)行 sql 語句
		db.query(sql1, {
			username: userInfo.username,
			password: userInfo.password
		}, (error, result) => {
			if (error) return res.cc(error)
			// 判斷影響行數(shù)是否為 1
			if (result.affectedRows !== 1) return res.cc('注冊用戶失敗!')
			return res.cc('注冊用戶成功', 0, {
				username: userInfo.username
			})
		})
	})
}

/**
 * POST 登錄的回調(diào)函數(shù)
 * @param username  用戶名
 * @param password  用戶密碼
 */
exports.login = (req, res) => {
	
}

七、封裝錯誤處理函數(shù)(即:注冊功能使用的res.cc)

在注冊功能里我對res.send向客戶端響應(yīng)函數(shù)做了處理,

在app.js中,放在路由前面

//封裝錯誤處理函數(shù)
app.use((req, res, next) => {
	res.cc = function(err, status = 1, data = {}) {
		res.send({
			status,
			data,
			message: err instanceof Error ? err.message : err
		})
	}
	next()
})

八、登錄功能

1、流程分析

登錄的一般流程 1.判斷前端提交的后端的數(shù)據(jù)是否合法。 2.查詢登錄的用戶是否存在。 3.判斷當(dāng)前用戶的密碼是否正確。

1.判斷前端提交的后端的數(shù)據(jù)是否合法。

// 通過 req.body 獲取請求體中包含的 url-encoded 格式的數(shù)據(jù)
	console.log(req.body)
	const userInfo = req.body
	//【步驟一】對客戶端的數(shù)據(jù)進(jìn)行校驗
	if (userInfo.username == '' || userInfo.password == '') {
		return res.send({
			status: 1,
			msg: '用戶名和密碼不能為空'
		})
	}

2.查詢登錄的用戶是否存在。

// 定義 SQL 語句
	const sql = 'select * from ev_users where username=?'
	// 執(zhí)行 SQL 語句,根據(jù)用戶名查詢用戶的信息
	db.query(sql, userInfo.username, (err, result) => {
		// 執(zhí)行 SQL 語句失敗
		if (err) return res.cc(err)
		// 執(zhí)行 SQL 語句成功,但是獲取的數(shù)據(jù)條數(shù)不為1 也是失敗的
		if (result.length !== 1) return res.cc('登錄失??!')
		// 經(jīng)過上方倆條判斷條件,則證明執(zhí)行 SQL 成功
	})

3.判斷當(dāng)前用戶的密碼是否正確。

使用 加密包的bcrypt.compareSync方法對比用戶提交的密碼和數(shù)據(jù)庫中的密碼是否一致,如果一直即:登錄成功

// TODO :判斷密碼是否正確
		const comRes = bcrypt.compareSync(userInfo.password, result[0].password)
		if (!comRes) return res.cc('登陸失敗')

2、生成token字符

密碼正確的話,登錄成功,根據(jù)用戶信息生成唯一的token返回給客戶端

?1.安裝jsonwebtoken用于生成token

npm i jsonwebtoken

2.導(dǎo)入jsonwebtoken

// 導(dǎo)入生成Token的包
const jwt = require('jsonwebtoken')

?3.全局配置文件(里面有token的密鑰)

config.js放在根目錄

// 全局配置文件 config.js
module.exports = {
	// 加密和解密 token 的密鑰
	jwtSecretKey: 'itheima No1. ^_^',
	// token 有效期
	expiresIn: '10h'
}

導(dǎo)入

// 導(dǎo)入全局配置文件(里面有token的密鑰)
const config = require('../../config')

3.使用jwt.sign對用戶的信息進(jìn)行加密,生成 token 字符串?

jwt.sign 有三個參數(shù)依次是 生成token的數(shù)據(jù),加密的形式,token有效期

?加密前先處理用戶信息,將用戶的敏感信息置空(如:密碼等)

// 在服務(wù)器端生成 Token 字符串
		const user = {
			...result[0], // 解構(gòu)用戶信息
			password: '', //密碼等敏感信息置空
		}
		// 對用戶的信息進(jìn)行加密,生成 token 字符串 
		const tokenStr = jwt.sign(user, config.jwtSecretKey, {
			expiresIn: config.expiresIn //tonken 有效期
		})

4.登錄成功后將生成的token返回給客戶端

// 調(diào)用 res.send 將Token響應(yīng)給客戶端
		res.send({
			status: 0,
			data: {
				user: user,
				token: 'Bearer ' + tokenStr,
			},
			message: '登錄成功?。?!',
		})

3、登錄接口的完整代碼

/**
 * POST 用戶登錄
 * @param username  用戶名
 * @param password  用戶密碼
 */
router.post('/login', (req, res, next) => {
	// 通過 req.body 獲取請求體中包含的 url-encoded 格式的數(shù)據(jù)
	// console.log(req.body)
	const userInfo = req.body
	//對客戶端的數(shù)據(jù)進(jìn)行校驗
	if (userInfo.username == '' || userInfo.password == '') {
		return res.send({
			status: 1,
			msg: '用戶名和密碼不能為空'
		})
	}
	// 執(zhí)行定義好的登錄函數(shù)
	login(req, res)
});

1.login()登錄函數(shù)代碼

/**
 * POST 登錄的回調(diào)函數(shù)
 * @param username  用戶名
 * @param password  用戶密碼
 */
exports.login = (req, res) => {
	console.log('user', req.user);
	// 接收表單的數(shù)據(jù)
	const userInfo = req.body
	// 定義 SQL 語句
	const sql = 'select * from ev_users where username=?'
	// 執(zhí)行 SQL 語句,根據(jù)用戶名查詢用戶的信息
	db.query(sql, userInfo.username, (err, result) => {
		// 執(zhí)行 SQL 語句失敗
		if (err) return res.cc(err)
		// 執(zhí)行 SQL 語句成功,但是獲取的數(shù)據(jù)條數(shù)不為1 也是失敗的
		if (result.length !== 1) return res.cc('登錄失?。?)
		// 經(jīng)過上方倆條判斷條件,則證明執(zhí)行 SQL 成功

		// TODO :判斷密碼是否正確
		const comRes = bcrypt.compareSync(userInfo.password, result[0].password)
		if (!comRes) return res.cc('登陸失敗')
		// 在服務(wù)器端生成 Token 字符串
		const user = {
			...result[0], // 解構(gòu)用戶信息
			password: '', //密碼等敏感信息置空
		}
		// 對用戶的信息進(jìn)行加密,生成 token 字符串 
		const tokenStr = jwt.sign(user, config.jwtSecretKey, {
			expiresIn: config.expiresIn //tonken 有效期
		})
		// 調(diào)用 res.send 將Token響應(yīng)給客戶端
		res.send({
			status: 0,
			data: {
				user: user,
				token: 'Bearer ' + tokenStr,
			},
			message: '登錄成功?。。?,
		})
	})
}

九、最后附上users路由模塊和登錄注冊函數(shù).js的完整代碼

users.js

var express = require('express');
var router = express.Router();
// 導(dǎo)入寫好的注冊/登錄函數(shù)
const {
	regUser,
	login
} = require('../public/javascripts/login')

/* GET users listing. */
router.get('/', function(req, res, next) {
	// 獲取客戶端提交到服務(wù)器的用戶信息
	const userInfo = req.body
	if(req.user){
		return res.cc('獲取成功', 0, req.user)
	}
	// 獲取到中間件的時間
	res.send('GET 請求成功');
});

/**
 * POST 用戶注冊
 * @param username  用戶名
 * @param password  用戶密碼
 */
router.post('/add', (req, res, next) => {
	// 通過 req.body 獲取請求體中包含的 url-encoded 格式的數(shù)據(jù)
	console.log(req.body)
	const userInfo = req.body
	//【步驟一】對客戶端的數(shù)據(jù)進(jìn)行校驗
	if (userInfo.username == '' || userInfo.password == '') {
		return res.send({
			status: 1,
			msg: '用戶名和密碼不能為空'
		})
	}
	// 【步驟二】執(zhí)行定義好的注冊函數(shù)
	regUser(req, res)
});

/**
 * POST 用戶登錄
 * @param username  用戶名
 * @param password  用戶密碼
 */
router.post('/login', (req, res, next) => {
	// 通過 req.body 獲取請求體中包含的 url-encoded 格式的數(shù)據(jù)
	// console.log(req.body)
	const userInfo = req.body
	//對客戶端的數(shù)據(jù)進(jìn)行校驗
	if (userInfo.username == '' || userInfo.password == '') {
		return res.send({
			status: 1,
			msg: '用戶名和密碼不能為空'
		})
	}
	// 執(zhí)行定義好的登錄函數(shù)
	login(req, res)
});





/* 模板 */
// // 在這里掛載對應(yīng)的路由
// router.get('/get', (req, res) => {
//   // 通過 req.query 獲取客戶端通過查詢字符串,發(fā)送到服務(wù)器的數(shù)據(jù)
//   const query = req.query
//   // 調(diào)用 res.send() 方法,向客戶端響應(yīng)處理的結(jié)果
//   res.send({
//     status: 0, // 0 表示處理成功,1 表示處理失敗
//     msg: 'GET 請求成功!', // 狀態(tài)的描述
//     data: query, // 需要響應(yīng)給客戶端的數(shù)據(jù)
//   })
// })

// // 定義 POST 接口
// router.post('/post', (req, res) => {
//   // 通過 req.body 獲取請求體中包含的 url-encoded 格式的數(shù)據(jù)
//   const body = req.body
//   // 調(diào)用 res.send() 方法,向客戶端響應(yīng)結(jié)果
//   res.send({
//     status: 0,
//     msg: 'POST 請求成功!',
//     data: body,
//   })
// })

// // 定義 DELETE 接口
// router.delete('/delete', (req, res) => {
//   res.send({
//     status: 0,
//     msg: 'DELETE請求成功',
//   })
// })

module.exports = router;

login.js登錄注冊函數(shù)

// 導(dǎo)入數(shù)據(jù)庫操作模塊
const db = require('../../db/index')
// 導(dǎo)入 bcryptjs 加密包
const bcrypt = require('bcryptjs')
// 導(dǎo)入生成Token的包
const jwt = require('jsonwebtoken')
// 導(dǎo)入全局配置文件(里面有token的密鑰)
const config = require('../../config')

/**
 * POST 用戶注冊
 * @param username  用戶名
 * @param password  用戶密碼
 */
exports.regUser = (req, res) => {
	// 獲取客戶端提交到服務(wù)器的用戶信息
	const userInfo = req.body
	// 定義sql語句,查詢用戶名是否被占用
	let sql = 'select * from ev_users where username=?'
	db.query(sql, [userInfo.username], (error, result) => {
		if (error) {
			return res.cc(error)
		}
		if (result.length > 0) {
			return res.cc('用戶名已被占用!')
		}
		// 調(diào)用 bcrypt.hashSync() 對密碼加密
		userInfo.password = bcrypt.hashSync(userInfo.password, 10)
		// 定義插入新用戶的 SQL 語句
		let sql1 = 'insert into ev_users set ?'
		// 調(diào)用 db.query() 執(zhí)行 sql 語句
		db.query(sql1, {
			username: userInfo.username,
			password: userInfo.password
		}, (error, result) => {
			if (error) return res.cc(error)
			// 判斷影響行數(shù)是否為 1
			if (result.affectedRows !== 1) return res.cc('注冊用戶失??!')
			return res.cc('注冊用戶成功', 0, {
				username: userInfo.username
			})
		})
	})
}

/**
 * POST 登錄的回調(diào)函數(shù)
 * @param username  用戶名
 * @param password  用戶密碼
 */
exports.login = (req, res) => {
	console.log('user', req.user);
	// 接收表單的數(shù)據(jù)
	const userInfo = req.body
	// 定義 SQL 語句
	const sql = 'select * from ev_users where username=?'
	// 執(zhí)行 SQL 語句,根據(jù)用戶名查詢用戶的信息
	db.query(sql, userInfo.username, (err, result) => {
		// 執(zhí)行 SQL 語句失敗
		if (err) return res.cc(err)
		// 執(zhí)行 SQL 語句成功,但是獲取的數(shù)據(jù)條數(shù)不為1 也是失敗的
		if (result.length !== 1) return res.cc('登錄失敗!')
		// 經(jīng)過上方倆條判斷條件,則證明執(zhí)行 SQL 成功

		// TODO :判斷密碼是否正確
		const comRes = bcrypt.compareSync(userInfo.password, result[0].password)
		if (!comRes) return res.cc('登陸失敗')
		// 在服務(wù)器端生成 Token 字符串
		const user = {
			...result[0], // 解構(gòu)用戶信息
			password: '', //密碼等敏感信息置空
		}
		// 對用戶的信息進(jìn)行加密,生成 token 字符串 
		const tokenStr = jwt.sign(user, config.jwtSecretKey, {
			expiresIn: config.expiresIn //tonken 有效期
		})
		// 調(diào)用 res.send 將Token響應(yīng)給客戶端
		res.send({
			status: 0,
			data: {
				user: user,
				token: 'Bearer ' + tokenStr,
			},
			message: '登錄成功?。?!',
		})
	})
}

到此我們的登錄和注冊接口已經(jīng)實現(xiàn),

接口文檔:

注冊:post? ? ? ?http://127.0.0.1/users/add

? ? ? ? ? ?請求參數(shù):username:用戶名? ?

?????????????????????????????password:密碼

登錄:post? ? ? ?http://127.0.0.1/users/login

? ? ? ? ? ?請求參數(shù):username:用戶名? ?

?????????????????????????????password:密碼

十、解析token中間件

在剛剛我沒完成了token的生成,現(xiàn)在我們做一個中間件用來解析token,來對用戶進(jìn)行身份認(rèn)證

?1.安裝解析中間件

npm i express-jwt

2.在App.js 中引入

//token解析中間件 一定要在路由之前配置解析 Token 的中間件
const expressJWT = require('express-jwt')
//映入解密
const config = require('./config')

3.注冊全局中間件并解析token

// 注冊全局中間件  鏈?zhǔn)秸{(diào)用 unless 方法,接收一個配置對象,path 字段設(shè)置一個正則表達(dá)式,表示不需要 token 身份認(rèn)證的路由前綴。
app.use(expressJWT({
	// 加密時設(shè)置的密鑰
	secret: config.jwtSecretKey,
	// 設(shè)置算法
	algorithms: ['HS256'],
	// 無token請求不進(jìn)行解析,并且拋出異常
	// credentialsRequired: false
}).unless({
	path: [
		'/users/add',
		'/users/login',
		{
			url: /^\/public\/.*/,
			methods: ['GET', 'POST']
		}
	]
	// path: ['/users/login','/users']
}))

4.注冊全局錯誤中間件 當(dāng)token失效時 返回信息

// 錯誤中間件 當(dāng)token失效時 返回信息
app.use((err, req, res, next) => {
	if (err.name === 'UnauthorizedError') {
		res.status(401).send({
			status: 1,
			data: {},
			message: '身份認(rèn)證失敗!'
		});
	}
});

十一、CORS跨域中間件

注冊登錄接口寫好了,但是使用的時候會有一個很嚴(yán)重的問題:不支持跨域請求。

解決接口跨域問題的方案主要有兩種:

① CORS(主流的解決方案,推薦使用)

② JSONP(有缺陷的解決方案:只支持 GET 請求)

?1. 使用 cors 中間件解決跨域問題

cors 是 Express 的一個第三方中間件。通過安裝和配置 cors 中間件,可以很方便地解決跨域問題。

使用步驟分為如下 3 步:

① 運行 npm install cors 安裝中間件

npm install cors

② 使用 const cors = require(‘cors’) 導(dǎo)入中間件

// 一定要在路由之前,配置 cors 這個中間件,從而解決接口跨域的問題
const cors = require('cors')

③ 在路由之前調(diào)用 app.use(cors()) 配置中間件

app.use(cors())

完整代碼:(jsonp就不做過多解釋了)

// 【必須在配置 cors 中間件之前,配置 JSONP 的接口】
app.get('/api/jsonp', (req, res) => {
	// TODO: 定義 JSONP 接口具體的實現(xiàn)過程
	// 1. 得到函數(shù)的名稱
	const funcName = req.query.callback
	// 2. 定義要發(fā)送到客戶端的數(shù)據(jù)對象
	const data = {
		name: 'zs',
		age: 22
	}
	// 3. 拼接出一個函數(shù)的調(diào)用
	const scriptStr = `${funcName}(${JSON.stringify(data)})`
	// 4. 把拼接的字符串,響應(yīng)給客戶端
	res.send(scriptStr)
})

// 一定要在路由之前,配置 cors 這個中間件,從而解決接口跨域的問題
const cors = require('cors')
app.use(cors())

注意事項:

①CORS 主要在服務(wù)器端進(jìn)行配置??蛻舳藶g覽器無須做任何額外的配置,即可請求開啟了CORS的接口。

②CORS在瀏覽器中有兼容。只有支持XMLHttpRequest Level2的瀏覽器,才能正常訪問開啟了CORS的服務(wù)端接口(例如:IE10+、Chrome4+、FireFox3.5+)。

1、CORS 響應(yīng)頭部 - Access-Control-Allow-Origin

如果指定了 Access-Control-Allow-Origin 字段的值為通配符 *,表示允許來自任何域的請求,示例代碼如下:

res.setHeader('Access-Control-Allow-Origin','*')

2、CORS 響應(yīng)頭部 - Access-Control-Allow-Headers

默認(rèn)情況下,CORS 僅支持客戶端向服務(wù)器發(fā)送如下的 9 個請求頭:
Accept、Accept-Language、Content-Language、DPR、Downlink、Save-Data、Viewport-Width、Width 、Content-Type (值僅限于 text/plain、multipart/form-data、application/x-www-form-urlencoded 三者之一)
如果客戶端向服務(wù)器發(fā)送了額外的請求頭信息,則需要在服務(wù)器端,通過 Access-Control-Allow-Headers 對額外的請求頭進(jìn)行聲明,否則這次請求會失敗!

?

// 允許客戶端額外向服務(wù)器發(fā)送 Content-Type 請求頭和 X-Custom-Header 請求頭
// 注意: 多個請求頭之間使用英文的逗號進(jìn)行分割
res.setHeader('Access-Control-Allow-Headers ''Content-Type X-Custom-Header')

3、CORS 響應(yīng)頭部 - Access-Control-Allow-Methods

默認(rèn)情況下,CORS 僅支持客戶端發(fā)起 GET、POST、HEAD 請求。
如果客戶端希望通過?PUT、DELETE?等方式請求服務(wù)器的資源,則需要在服務(wù)器端,通過 Access-Control-Alow-Methods來指明實際請求所允許使用的 HTTP 方法。示例代碼如下:

// 只允許 POST、GET、DELETE、HEAD 請求方法
res,setHeader('Access-Control-A1low-Methods','POST,GET,DELETE,HEAD')
 // 允許所有的 HTTP 請求方法
 res,setHeader('Access-Control-A1low-Methods','*')

4、?CORS請求的分類

客戶端在請求 CORS 接口時,根據(jù) 請求方式和請求頭的不同,可以將 CORS 的請求分為兩大類,分別是:
① 簡單請求
② 預(yù)檢請求

5、 簡單請求

同時滿足以下兩大條件的請求,就屬于簡單請求:
① 請求方式:GET、POST、HEAD 三者之一
② HTTP 頭部信息不超過以下幾種字段:無自定義頭部字段、Accept、Accept-Language、Content-Language、DPR、Downlink、Save-Data、Viewport-Width、Width 、Content-Type(只有三個值application/x-www-form-urlencoded、multipart/form-data、text/plain)

6、預(yù)檢請求

只要符合以下任何一個條件的請求,都需要進(jìn)行預(yù)檢請求:
① 請求方式為 GET、POST、HEAD 之外的請求 Method 類型
② 請求頭中包含自定義頭部字段
③ 向服務(wù)器發(fā)送了 application/json 格式的數(shù)據(jù)

在瀏覽器與服務(wù)器正式通信之前,瀏覽器會先發(fā)送 OPTION 請求進(jìn)行預(yù)檢,以獲知服務(wù)器是否允許該實際請求,所以這一次的 OPTION 請求稱為“預(yù)檢請求”。服務(wù)器成功響應(yīng)預(yù)檢請求后,才會發(fā)送真正的請求,并且攜帶真實數(shù)據(jù)。

7.、簡單請求和預(yù)檢請求的區(qū)別

簡單請求的特點:客戶端與服務(wù)器之間只會發(fā)生一次請求。
預(yù)檢請求的特點:客戶端與服務(wù)器之間會發(fā)生兩次請求,OPTION 預(yù)檢請求成功之后,才會發(fā)起真正的請求。

2、最后附上app.js完整代碼?

// 導(dǎo)入 express
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');

// 引入路由模塊
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

// 創(chuàng)建服務(wù)器實例
var app = express();

app.use(logger('dev'));

// 處理 application/json
app.use(express.json());

// 配置解析表單數(shù)據(jù)的中間件 處理 x-www-form-urlencoded
app.use(express.urlencoded({
	extended: false
}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

//token解析中間件 一定要在路由之前配置解析 Token 的中間件
const expressJWT = require('express-jwt')
//映入解密
const config = require('./config')
// 注冊全局中間件  鏈?zhǔn)秸{(diào)用 unless 方法,接收一個配置對象,path 字段設(shè)置一個正則表達(dá)式,表示不需要 token 身份認(rèn)證的路由前綴。
app.use(expressJWT({
	// 加密時設(shè)置的密鑰
	secret: config.jwtSecretKey,
	// 設(shè)置算法
	algorithms: ['HS256'],
	// 無token請求不進(jìn)行解析,并且拋出異常
	// credentialsRequired: false
}).unless({
	path: [
		'/users/add',
		'/users/login',
		{
			url: /^\/public\/.*/,
			methods: ['GET', 'POST']
		}
	]
	// path: ['/users/login','/users']
}))

// 【必須在配置 cors 中間件之前,配置 JSONP 的接口】
app.get('/api/jsonp', (req, res) => {
	// TODO: 定義 JSONP 接口具體的實現(xiàn)過程
	// 1. 得到函數(shù)的名稱
	const funcName = req.query.callback
	// 2. 定義要發(fā)送到客戶端的數(shù)據(jù)對象
	const data = {
		name: 'zs',
		age: 22
	}
	// 3. 拼接出一個函數(shù)的調(diào)用
	const scriptStr = `${funcName}(${JSON.stringify(data)})`
	// 4. 把拼接的字符串,響應(yīng)給客戶端
	res.send(scriptStr)
})

// 一定要在路由之前,配置 cors 這個中間件,從而解決接口跨域的問題
const cors = require('cors')
app.use(cors())

//定義第一個全局中間件
app.use((req, res, next) => { //res用于返回客戶端 req客戶端的請求參數(shù)  next() 提交給下一個中間件
	// 只允許  請求方法
	res.setHeader('Access-Control-Allow-Methods', 'POST, GET, DELETE,HEAD')
	// 響應(yīng)頭 允許所有的 HTTP 請求方法
	res.setHeader('Access-Control-Allow-Methods', '*')
	// 如果指定了 Access-Control-Allow-Origin 字段的值為通配符 *,表示允許來自任何域的請求
	res.setHeader('Access-Control-Allow-Origin', '*')
	// res.setHeader("Access-Control-Allow-Headers", "content-type,Authorization");
	next();
})



//封裝錯誤處理函數(shù)
app.use((req, res, next) => {
	res.cc = function(err, status = 1, data = {}) {
		res.send({
			status,
			data,
			message: err instanceof Error ? err.message : err
		})
	}
	next()
})

// 錯誤中間件 當(dāng)token失效時 返回信息
app.use((err, req, res, next) => {
	if (err.name === 'UnauthorizedError') {
		res.status(401).send({
			status: 1,
			data: {},
			message: '身份認(rèn)證失??!'
		});
	}
});

// 掛載路由
app.use('/', indexRouter);

/* 用戶路由 */
app.use('/users', usersRouter);

module.exports = app;

?跨域這部分和jsonp參考了以下文章?

【nodejs-03】黑馬nodejs學(xué)習(xí)筆記03-express中間件與跨域_簡單長庚的博客-CSDN博客文章來源地址http://www.zghlxwxcb.cn/news/detail-672639.html

到了這里,關(guān)于基于NodeJs+Express+MySQL 實現(xiàn)實現(xiàn)登錄注冊接口+token生成與解析驗證+跨域-CORS的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • WEB通訊技術(shù)。前端實現(xiàn)SSE長連接,nodejs+express搭建簡單服務(wù)器,進(jìn)行接口調(diào)試,通過curl請求數(shù)據(jù)

    WEB通訊技術(shù)。前端實現(xiàn)SSE長連接,nodejs+express搭建簡單服務(wù)器,進(jìn)行接口調(diào)試,通過curl請求數(shù)據(jù)

    長連接(Keep-Alive)是一種HTTP/1.1的持久連接技術(shù),它允許客戶端和服務(wù)器在一次TCP連接上進(jìn)行多個HTTP請求和響應(yīng),而不必為每個請求/響應(yīng)建立和斷開一個新的連接。長連接有助于減少服務(wù)器的負(fù)載和提高性能。 長連接的HTTP請求方法與普通HTTP請求方法相同,可以使用GET、P

    2024年02月09日
    瀏覽(30)
  • node.js(express.js)+mysql實現(xiàn)登錄功能

    node.js(express.js)+mysql實現(xiàn)登錄功能

    實現(xiàn)步驟 1.檢測表單數(shù)據(jù)是否合法 2.根據(jù)用戶名查詢用戶的數(shù)據(jù) 3.判斷用戶輸入的密碼是否正確 4.生成JWT 的 Token 字符串 登錄接口完整代碼如下:controllers/user.js文件 一、檢測登錄表單的數(shù)據(jù)是否合法 1)安裝 jOi 包,為表單中攜帶的每個數(shù)據(jù)項,定義驗證規(guī)則: (2)安裝 @e

    2024年01月19日
    瀏覽(28)
  • 30天精通Nodejs--第二十天:express-操作mysql

    在Node.js中使用Express框架進(jìn)行開發(fā)時,經(jīng)常會需要持久化數(shù)據(jù),與關(guān)系型數(shù)據(jù)庫MySQL的集成是至關(guān)重要的一步。本文將詳細(xì)闡述如何在Express項目中連接MySQL數(shù)據(jù)庫,并通過實例代碼演示如何執(zhí)行基本的增刪改查(CRUD)操作。

    2024年01月18日
    瀏覽(18)
  • 基于微信評選投票小程序畢業(yè)設(shè)計作品成品(11)用戶注冊和登錄接口

    基于微信評選投票小程序畢業(yè)設(shè)計作品成品(11)用戶注冊和登錄接口

    博主介紹: 《Vue.js入門與商城開發(fā)實戰(zhàn)》《微信小程序商城開發(fā)》圖書作者,CSDN博客專家,在線教育專家,CSDN鉆石講師;專注大學(xué)生畢業(yè)設(shè)計教育和輔導(dǎo)。 所有項目都配有從入門到精通的基礎(chǔ)知識視頻課程,免費 項目配有對應(yīng)開發(fā)文檔、開題報告、任務(wù)書、PPT、論文模版

    2024年02月07日
    瀏覽(20)
  • 基于微信電子書小說閱讀小程序畢業(yè)設(shè)計成品作品(12)用戶注冊和登錄接口

    基于微信電子書小說閱讀小程序畢業(yè)設(shè)計成品作品(12)用戶注冊和登錄接口

    博主介紹: 《Vue.js入門與商城開發(fā)實戰(zhàn)》《微信小程序商城開發(fā)》圖書作者,CSDN博客專家,在線教育專家,CSDN鉆石講師;專注大學(xué)生畢業(yè)設(shè)計教育和輔導(dǎo)。 所有項目都配有從入門到精通的基礎(chǔ)知識視頻課程,免費 項目配有對應(yīng)開發(fā)文檔、開題報告、任務(wù)書、PPT、論文模版

    2024年02月08日
    瀏覽(22)
  • 【Unity+MySQL】實現(xiàn)注冊登錄系統(tǒng)(封裝版)

    【Unity+MySQL】實現(xiàn)注冊登錄系統(tǒng)(封裝版)

    接著 上篇文章的注冊登錄系統(tǒng),這篇文章將MySQL相關(guān)操作封裝,在Unity交互腳本中直接調(diào)用封裝的方法。 編寫一個DBConnector腳本,封裝MySQL中常用的操作,如連接數(shù)據(jù)庫、關(guān)閉數(shù)據(jù)庫、查詢數(shù)據(jù)庫、除查詢外的插入、更新、刪除等操作。 編寫一個User腳本用于封裝用戶注冊、登

    2024年02月05日
    瀏覽(17)
  • 【Unity+MySQL】實現(xiàn)簡單的注冊登錄系統(tǒng)

    【Unity+MySQL】實現(xiàn)簡單的注冊登錄系統(tǒng)

    確保這兩個軟件都能夠在你的計算機上良好地運行。 鏡像地址:http://mirrors.sohu.com/mysql/MySQL-8.0/ 下載完成后雙擊運行msi文件。 Next→ Next→ 選擇自定義安裝, Next→ 選擇安裝路徑, Next→ Install安裝, 安裝完成,F(xiàn)inish。 此電腦→計算機→屬性, 關(guān)于→高級系統(tǒng)設(shè)置, 高級→環(huán)

    2024年02月05日
    瀏覽(36)
  • 使用JSP+Servlet+MySQL實現(xiàn)登錄注冊功能

    使用JSP+Servlet+MySQL實現(xiàn)登錄注冊功能

    ?作者簡介:大家好,我是Leo,熱愛Java后端開發(fā)者,一個想要與大家共同進(jìn)步的男人???? ??個人主頁:Leo的博客 ??當(dāng)前專欄: Java從入門到精通 ?特色專欄: MySQL學(xué)習(xí) ??本文內(nèi)容:使用JSP+Servlet+MySQL實現(xiàn)登錄注冊功能 ??個人知識庫: Leo知識庫,歡迎大家訪問 大家好,

    2024年02月04日
    瀏覽(15)
  • 【Unity+MySQL】實現(xiàn)注冊登錄系統(tǒng)(升級版)

    【Unity+MySQL】實現(xiàn)注冊登錄系統(tǒng)(升級版)

    接著 上篇文章所談到的系統(tǒng)缺陷,這篇文章進(jìn)行升級解決。 問題 :注冊界面與登錄界面是同一個界面,導(dǎo)致用戶輸入用戶密碼進(jìn)行注冊后,即可點擊登錄。 解決 :在同一個場景中分別創(chuàng)建注冊界面和登錄界面,使用SetActive控制注冊/登錄成功后UI的顯示與隱藏。 整體的UI框

    2024年02月09日
    瀏覽(18)
  • 100 行代碼實現(xiàn)用戶登錄注冊與 RESTful 接口 - 手把手教程附 Python 源碼

    在開發(fā)大多數(shù)應(yīng)用時,用戶系統(tǒng)都是必不可少的部分,而我們總是需要開發(fā)圍繞用戶的登錄,注冊,獲取,更新等接口。在這篇文章將帶你用一百多行代碼簡潔地實現(xiàn)一套這樣的用戶鑒權(quán)與 RESTful 接口,并使用 Session 來處理用戶的登錄登出 我們將使用 UtilMeta 框架 完成接口開

    2024年02月19日
    瀏覽(26)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包