使用nodejs实现用户注册登录

612 阅读3分钟

大多数项目,相比都有注册和登录的功能,本文将记录,如何使用node+mongodb来实现用户的无状态登录。至于什么是无状态,可以查看这篇文章 有状态和无状态登录的概念

接上一篇我们新建的express项目,项目创建请移步上一篇文章,我们已经有了一个基础的项目结构,并且我们已经实现了创建用户的接口。我们使用了bcrypt进行用户密码加密。然后我们登录的时候,进行解密,并验证即可。

使用jwt 实现用户登录并生成token

安装jsonwebtoken依赖
npm i -S jsonwebtoken

在config文件夹下,我们新建一个index.js文件,并配置jwt 加密字符串

// jwttoken加密字符串
const JWT_SECRET = 'token_secret_hahahaha'
module.exports = {
    JWT_SECRET
}

然后我们在routes/users.js中

var express = require('express');
var router = express.Router();
const { User } = require('../../model/User')
// 引入 jwt
const jwt = require('jsonwebtoken')
// 引入jwt 加密解密 用的密钥
const { JWT_SECRET } = require('../../../config/index')
// 用户登录
router.post('/login', async (req, res, next) => {
  const user = await User.findOne({
    username: req.body.username
  }).select('password')
 // .select('password') 是将密码字段查询出来,由于我们在模型中设置了默认不返回
  if (!user) {
    return res.status(422).send({
      code: 422,
      msg: '用户名不存在'
    })
  }
  // bcrypt.compareSync 解密匹配,返回 boolean 值
  const isPasswordValid = bcrypt.compareSync(
    req.body.password,
    user.password
  )
  if (!isPasswordValid) {
    return res.status(422).send({
      code:422,
      msg: '密码无效'
    })
  }
  /*   生成 token  jwt.sign() 接受两个参数,一个是传入的对象,一个是自定义的密钥  */
  const token = jwt.sign({ id: String(user._id) }, JWT_SECRET)
  res.send({
    code: 200,
    msg: '登录成功',
    data:{ user_id: user._id, token }
  })});

于是我们就有了我们用户的token,此时token中加密保存的仅仅是用户的_id信息

然后我们在请求其他接口的时候,需要验证用户信息的话,就在header中加上我们的token信息,再接口中校验token,如果通过,就进行下一步

校验token

我们校验用户token一般会写一个中间件函数,然后再需要验证的接口中,加上这个函数即可

在middleware/checkToken.js

// 引入User模型
const { User } = require('../model/User')
// 引入 jwt
const jwt = require('jsonwebtoken')
// 解析 token 用的密钥
const { JWT_SECRET } = require('../../config/index')
// 验证token
let checkToken = async (req, res, next)=>{
  if(!req.headers.authorization) {
    res.send({
      code: 401,
      msg: '尚未登录!'
    })
    return
  }
  const token = String(req.headers.authorization.split(' ').pop())
  if(!token){
    res.send({
      code: 401,
      msg: 'token验证失败'
    })
  }
  // 解密 token 获取对应的 id
  jwt.verify(token, JWT_SECRET, (err,decode)=>{
    if(err) {
      res.send({
        code: 401,
        msg: err
      })
      return
    }
    let { id } = decode
    if(!id) {
      res.send({
        code: 401,
        msg: '当前用户信息不存在'
      })
    }else {
      req.user_id = id
      next()
    }
    // console.log(decode);
  })
  }
module.exports = checkToken

然后再routes/users.js路由文件中

比如我们要在获取用户信息之前,先验证用户token,判断用户是否登录,

var express = require('express');
var router = express.Router();
const { User } = require('../../model/User')
// 引入校验中间件
const checkToken = require('../../middleware/checkToken')
// 获取用户信息 假如checkToken校验token
router.get('/info',checkToken, async (req, res, next) => {
  const user = await User.findOne({
    _id: req.user_id
  })
  res.send({
    code: 200,
    data: user
  })
 })
module.exports = router;

测试接口

在.http文件中

// test.http

@url=http://localhost:3000
### 用户登录  拿到token
POST {{url}}/users/login
Content-Type: application/json
{  "username": "user3",  "password": "123456"}

### 获取用户信息   使用登录后拿到的token进行验证
GET  {{url}}/users/info
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVmZjA3M2I5YjkyMTYwMjM5Y2JlMTQzZiIsImlhdCI6MTYwOTU5NDExOX0.iSXibZxCFKuFI_jJ9xq3-dffe4zPCnVRgNH7ZlrQhvc