文章目录
- 前言
- 实现步骤
-
-
- 一、检测登录表单的数据是否合法
- 二、根据用户名查询用户的数据
- 三、判断用户输入的密码是否正确
- [四、生成JWT 的 Token 字符串](#四、生成JWT 的 Token 字符串)
-
- 最终登录接口代码如下:
-
-
- [五、在app.js中注册路由之前,配置解析token的中间件,为了指定那些接口不需要进行Token 的身份认证](#五、在app.js中注册路由之前,配置解析token的中间件,为了指定那些接口不需要进行Token 的身份认证)
-
前言
实现步骤
1.检测表单数据是否合法
2.根据用户名查询用户的数据
3.判断用户输入的密码是否正确
4.生成JWT 的 Token 字符串
登录接口完整代码如下:controllers/user.js文件
javascript
// 登录接口
var db = require("../utils/db");
// 导入密码加密
const bcrypt = require("bcryptjs");
// 导入jwt 包来生成token
const jwt = require("jsonwebtoken");
// 导入密钥
const config = require("../config");
exports.login = (req, res) => {
// 获取客户端提交到服务器的用户信息
const userinfo = req.body;
// 定义sql语句,根据用户名查询用户的信息
const sql = `select * from ev_users where username=?`;
// 执行sql语句,根据用户名查询用户的信息
db.query(sql, userinfo.username, (err, results) => {
// 执行sql语句失败
if (err) return res.cc(err);
// 执行sql语句成功,但是获取到的数据条件不等于1
if (results.length !== 1) return res.cc("登录失败!");
// 判断密码是否和数据库中的密码是否一致
// compareSync 第一个参数用户输入的,第二个参数数据库查询到的
// 返回值为ture 一致,反之
const compareResult = bcrypt.compareSync(
userinfo.password,
results[0].password
);
console.log("1", userinfo.password);
console.log("2", results[0].password);
if (!compareResult) {
return res.cc("登录失败233");
}
// 生成jwt的token字符串
// 清空用户信息的密码和头像
const user = { ...results[0], password: "", user_pic: "" };
console.log(user);
// 对用户的信息进行加密,生成token字符串
const tokenStr = jwt.sign(user, config.jwtSecretKey, {
expiresIn: "10h", // token 有效期为10小时
});
// 将生成的token字符串响应给客户端
res.send({
status: 0,
message: "登录成功!",
// 为了方便客户端使用,在服务器端直接拼接上Bearer的前缀
// 注意:Bearer 后面必须有空格
token: "Bearer "+ tokenStr,
});
// res.cc("ok");
});
};
实现步骤
一、检测登录表单的数据是否合法
1)安装 jOi 包,为表单中携带的每个数据项,定义验证规则:
javascript
npm install joi
(2)安装 @escook/express-j01 中间件,来实现自动对表单数据进行验证的功能:
javascript
npm install @escook/express-joi
(3)新建schema/user.js
javascript
// 导入定义验证规则的包
// const joi = require("@hapi/joi");
const joi = require("joi");
/**
* string()值必须是字符串
* alphanum()值只能包含a-zA-ZO-9的字符串
* min(length) 最小长度
* max(length) 大长度
* required() 值是必填项,不能为 undefined
* pattern(正则表达式) 值必须符合正则表达式的规则
*/
// 定义用户名和密码的验证规则
const username = joi.string().alphanum().min(1).max(10).required();
const password = joi
.string()
.pattern(/^[\S]{6,12}$/)
.required();
// 定义验证注册和登录表单数据的规则对象
exports.reg_login_schema = {
body: {
username,
password,
},
};
(4)在routes/use.js中引入schema/user.js中的方法reg_login_schema,代码如下:
javascript
var express = require("express");
var router = express.Router();
// 引入封装的获取验证码的方法
var unr_handler = require("../controllers/user");
// 1.导入验证数据的中间件
const expressJoi = require("@escook/express-joi");
// 2.导入需要的验证规则对象
const { reg_login_schema } = require("../schema/user");
// 新用户注册
// router.post("/regUser", expressJoi(reg_login_schema), unr_handler.regUser);
// router.post("/regUser", unr_handler.regUser);
// 登录
router.post("/login", expressJoi(reg_login_schema), unr_handler.login);
module.exports = router;
二、根据用户名查询用户的数据
javascript
var db = require("../utils/db");
// 导入密码加密
const bcrypt = require("bcryptjs");
// 导入jwt 包来生成token
const jwt = require("jsonwebtoken");
// 导入密钥
const config = require("../config");
// 登录接口
exports.login = (req, res) => {
// 获取客户端提交到服务器的用户信息
const userinfo = req.body;
// 定义sql语句,根据用户名查询用户的信息
const sql = `select * from ev_users where username=?`;
// 执行sql语句,根据用户名查询用户的信息
db.query(sql, userinfo.username, (err, results) => {
// 执行sql语句失败
if (err) return res.cc(err);
// 执行sql语句成功,但是获取到的数据条件不等于1
if (results.length !== 1) return res.cc("登录失败!");
// res.cc("ok");
});
};
三、判断用户输入的密码是否正确
javascript
// 导入密码加密
const bcrypt = require("bcryptjs");
exports.login = (req, res) => {
// 获取客户端提交到服务器的用户信息
const userinfo = req.body;
// 定义sql语句,根据用户名查询用户的信息
const sql = `select * from ev_users where username=?`;
// 执行sql语句,根据用户名查询用户的信息
db.query(sql, userinfo.username, (err, results) => {
// 执行sql语句失败
if (err) return res.cc(err);
// 执行sql语句成功,但是获取到的数据条件不等于1
if (results.length !== 1) return res.cc("登录失败!");
// 判断密码是否和数据库中的密码是否一致
// compareSync 第一个参数用户输入的,第二个参数数据库查询到的
// 返回值为ture 一致,反之
const compareResult = bcrypt.compareSync(
userinfo.password,
results[0].password
);
console.log("1", userinfo.password);
console.log("2", results[0].password);
if (!compareResult) {
return res.cc("登录失败233");
}
// res.cc("ok");
});
};
四、生成JWT 的 Token 字符串
1)在生成 Token 字符串的时候,一定要别除 密码 和 头像 的值
javascript
// 清空用户信息的密码和头像
const user = { ...results[0], password: "", user_pic: "" };
2)安装成成token的字符串包
javascript
npm 1 jsonwebtoken@8.5.1
3)在 /controllers/user.js 模块的头部区域,导入 jsonwebtoken 包:
javascript
// 导入jwt 包来生成token
const jwt = require("jsonwebtoken");
4)创建 config.js 文件,并向外共享加密和还原Token 的 jwtSecretKey 字符串:
javascript
// 全局的配置文件
module.exports = {
// 加密和解密 token 的密钥
jwtSecretKey: "itheima No1. ^_^",
};
5)将用户信息对象加密成 Token 字符串, 在controllers/user.js文件引入config.js
javascript
// 导入密钥
const config = require("../config");
const user = { ...results[0], password: "", user_pic: "" };
console.log(user);
// 对用户的信息进行加密,生成token字符串
const tokenStr = jwt.sign(user, config.jwtSecretKey, {
expiresIn: "10h", // token 有效期为10小时
});
// 将生成的token字符串响应给客户端
res.send({
status: 0,
message: "登录成功!",
// 为了方便客户端使用,在服务器端直接拼接上Bearer的前缀
token: "Bearer"+ tokenStr,
});
最终登录接口代码如下:
javascript
// 登录接口
var db = require("../utils/db");
// 导入密码加密
const bcrypt = require("bcryptjs");
// 导入jwt 包来生成token
const jwt = require("jsonwebtoken");
// 导入密钥
const config = require("../config");
exports.login = (req, res) => {
// 获取客户端提交到服务器的用户信息
const userinfo = req.body;
// 定义sql语句,根据用户名查询用户的信息
const sql = `select * from ev_users where username=?`;
// 执行sql语句,根据用户名查询用户的信息
db.query(sql, userinfo.username, (err, results) => {
// 执行sql语句失败
if (err) return res.cc(err);
// 执行sql语句成功,但是获取到的数据条件不等于1
if (results.length !== 1) return res.cc("登录失败!");
// 判断密码是否和数据库中的密码是否一致
// compareSync 第一个参数用户输入的,第二个参数数据库查询到的
// 返回值为ture 一致,反之
const compareResult = bcrypt.compareSync(
userinfo.password,
results[0].password
);
console.log("1", userinfo.password);
console.log("2", results[0].password);
if (!compareResult) {
return res.cc("登录失败233");
}
// 生成jwt的token字符串
// 清空用户信息的密码和头像
const user = { ...results[0], password: "", user_pic: "" };
console.log(user);
// 对用户的信息进行加密,生成token字符串
const tokenStr = jwt.sign(user, config.jwtSecretKey, {
expiresIn: "10h", // token 有效期为10小时
});
// 将生成的token字符串响应给客户端
res.send({
status: 0,
message: "登录成功!",
// 为了方便客户端使用,在服务器端直接拼接上Bearer的前缀
// 注意:Bearer 后面必须有空格
token: "Bearer "+ tokenStr,
});
// res.cc("ok");
});
};
/utils/db文件代码
javascript
const mysql = require("mysql");
const db = mysql.createPool({
host: "localhost", // 连接地址
port: "3306", //端口号
user: "root", //用户名
password: "XXXXXXX", //密码
database: "exapp2", //数据库名
});
module.exports = db;
五、在app.js中注册路由之前,配置解析token的中间件,为了指定那些接口不需要进行Token 的身份认证
1.安装解析 Token 的中间件:
javascript
npm i express-jwt@5.3.3
2). app.js
javascript
// 导入配置文件
const config = require("./config");
// 解析token的中间件
const expressJWT = require("express-jwt");
// 使用 unless({ path:[/^\/user\//] )) 指定哪些接口不需要进行 Token 的身份认证
// ps: path: [/^\/user/] 改成你自己的接口前缀path: [/^\/XXX/]
app.use(
expressJWT({ secret: config.jwtSecretKey }).unless({ path: [/^\/user/] })
);
3)在 app.js 中的 错误级别中间件 里面,捕获并处理 Token 认证失败后的错误:
javascript
// 定义表单验证失败的错误的中间件,并把验证失败的结果响应给客户端
// 错误中间件
app.use(function (err, req, res, next) {
// 数据验证失败,instanceof判断
if (err instanceof joi.ValidationError) {
return res.cc(err);
}
// token身份认证失败后的错误
if (err.name === "UnauthorizedError") return res.cc("身份认证失败");
// 未知错误
res.cc(err);
});