目录
前言
服务器
编写登录接口API
使用sql语句查询数据库中是否有该用户
判断密码是否正确
生成JWT的Token字符串
配置解析token的中间件
配置捕获错误中间件
完整的登录接口代码
本文介绍如何使用node编写登录接口以及解密生成token,如何编写注册接口已经在Node编写用户注册接口这篇文章中介绍,本文是建立在编写注册接口这篇文章的基础之上
同时也可以在在前端html页面中向服务器发送post登录请求这篇文章中了解登录请求
关于创建服务器,本文中和Node编写用户注册接口共用一个服务器,已经引入了router对象
// 导入express模块
const express = require('express')
// 创建express服务器实例
const app = express()
// 导入跨域cors
const cors = require('cors')
// 全局挂载
app.use(cors())
// 配置解析表单数据中间件
app.use(express.urlencoded({extended:false}))
// 导入用户路由对象
const userRouter = require('./router/user')
app.use('/api',userRouter)
// 启动服务器
app.listen(3007,()=> {
console.log('running the http://127.0.0.1:3007');
})
const userinfo = req.body
const sql = 'select * from ev_users where username = ?'
db.query(sql, userinfo.username, function (err, results) {
// 执行 SQL 语句失败
if (err) {
return res.send({status:1,message:err.message})
}
// 执行 SQL 语句成功,但是查询到数据条数不等于 1
if (results.length !== 1) {
return res.send({status:1,message:'登录失败'})
}
res.send('登录成功')
})
使用postman模拟发送登录请求,查询是否有用户名为b
返回登录成功
数据库中有b用户
如果未注册
数据库中没有c用户
调用了bcrypt.compareSync()方法,用来解密,因为在注册时已经把密码加密了,所以需要解密
bcrypt.compareSync(用户提交的密码,数据库中的密码)
// 判断密码是否正确
const compareResult = bcrypt.compareSync(userinfo.password,results[0].password)
if(!compareResult) return res.send({status:1,message:'密码错误'})
res.send('登录成功')
验证b的密码是否正确
b的密码是000000
当把b的密码换成111111时,也就是错误密码
返回密码错误
关于JWT认证,可以浏览JWT认证这篇文章
生成token字符串时,要把密码和用户头像剔除,因为生成的token会保留在浏览器中,很容易泄露
// 剔除完毕之后,user 中只保留了用户的 id, username, nickname, email 这四个属性的值
const user = { ...results[0], password: '', user_pic: '' }
先安装jsonwebtoken
npm i jsonwebtoken
导入jwt
const jwt = require('jsonwebtoken')
导入成功后调用jwt.sign()生成JWT字符串
jwt.sign(用户的信息,加密的密钥,配置对象有效token的时间)
// 生成 Token 字符串
const tokenStr = jwt.sign(user, jwtSecreKey, {
expiresIn: '10h', // token 有效期为 10 个小时
})
将生成的token字符串发送给客户端
在生成的的token字符串前拼接上"Bearer",固定用法
res.send({
status: 0,
message: '登录成功!',
// 为了方便客户端使用 Token,在服务器端直接拼接上 Bearer 的前缀
token: 'Bearer ' + tokenStr,
})
使用postman模拟发送请求
将jwt字符串还原为JSON对象,在get请求时,可以获得用户信息
安装express-jwt
npm i express-jwt
导入
/ 导入解析token字符串
const exoressjwt = require('express-jwt')
解析token
// 使用 .unless({ path: [/^\/api\//] }) 指定哪些接口不需要进行 Token 的身份认证
app.use(expressjwt.expressjwt({
secret:jwtSecreKey,
algorithms:['HS256'],
}).unless({path:[/^\/api\//]}))
// 错误中间件
app.use(function (err, req, res, next) {
// 捕获身份认证失败的错误
if (err.name === 'UnauthorizedError') return res.send({satus:1,message:'身份认证失败'})
// 未知错误
res.send({status:1,message:err.message})
})
// 导入express模块
const express = require('express')
// 导入数据库对象
const db = require('../db/index')
// 导入加密模块
const bcrypt = require('bcryptjs')
// 创建路由对象
const router = express.Router()
// 导入JWT
const jwt = require('jsonwebtoken')
// 定义密钥
const jwtSecreKey = 'notbald'
// 登录接口
router.post('/login',(req,res)=>{
const userinfo = req.body
const sql = 'select * from ev_users where username = ?'
db.query(sql, userinfo.username, function (err, results) {
// 执行 SQL 语句失败
if (err) {
return res.send({status:1,message:err.message})
}
// 执行 SQL 语句成功,但是查询到数据条数不等于 1
if (results.length !== 1) {
return res.send({status:1,message:'登录失败'})
}
// 判断密码是否正确
const compareResult = bcrypt.compareSync(userinfo.password,results[0].password)
if(!compareResult) return res.send({status:1,message:'密码错误'})
// 生成token字符串,展开运算符,剔除密码和用户头像
const user = {...results[0],password:'',user_pic:''}
// console.log(user);
// 生成 Token 字符串
const tokenStr = jwt.sign(user, jwtSecreKey, {
expiresIn: '10h', // token 有效期为 10 个小时
})
res.send({
status: 0,
message: '登录成功!',
// 为了方便客户端使用 Token,在服务器端直接拼接上 Bearer 的前缀
token: 'Bearer ' + tokenStr,
})
})
})
解析token以及全局捕获错误中间件在服务器中