# 四、Koa 与登录鉴权

# 1、cookie 与 session

① cookie 使用

const Router = require('koa-router')
const router = new Router()

router.get('/', async (ctx, next) => {
  //获取cookie
  console.log(ctx.cookies)
  console.log(ctx.cookies.get('password'))

  // 设置cookie
  console.log(ctx.cookies.set('username', 'lencamo'))
})

module.exports = router

② session 使用

安装:

npm i koa-session-minimal

使用:

  • index.js
const Koa = require('koa')

const views = require('koa-session-minimal')

const app = new Koa()

// session配置
app.use(
  session({
    key: 'lencamoSessionID',
    cookie: {
      maxAge: 1000 * 60 * 60
    }
  })
)

// session✨判断拦截
app.use(async (ctx, next) => {
  if (ctx.url.includes('login')) {
    await next()
    return
  }

  if (ctx.session.user) {
    // 重置过期时间
    ctx.session.mydate = Date.now()
    await next()
  } else {
    ctx.redirect('/login')
  }
})

app.listen(3000, '127.0.0.1', function () {
  console.log('Server running at http://127.0.0.1:3000')
})
  • routes/user.js
const Router = require('koa-router')
const router = new Router()

router.post('/login', (ctx, next) => {
  const {username, password} = ctx.request.body

  if(username==="lencamo" && password==="123"){
    // 设置🚩session(随便赋予一个值)
    ctx.session.user = {
      username: 'lencamo'
    }
    ctx.body = {
      ok: 1
    }
  }else{
    ctx.body = {
      ok: 0
    }
  }

  await ctx.render('home', { username: 'lencamo' })
})

module.exports = router

# 2、JWT

  总的来说,逻辑上和前面 express 中使用 JWT 是一样的,只是语法上有些许差别罢了(ctx、async/await)。

安装:

npm i jsonwebtoken

使用:

  • util/JWT.js
const jwt = require('jsonwebtoken')

const secret = '<秘钥>'
const JWT = {
  // 1、生成token字符串
  generate(value, expires) {
    // 使用sign函数
    return jwt.sign(
      {
        // data: '<数据>'
        data: value
      },
      secret,
      {
        // expiresIn: '<有效期>'
        expiresIn: expires
      }
    )
  },

  // 2、解密数据
  verify() {
    try {
      return jwt.verify(token, secret)
    } catch (error) {
      return false
    }
  }
}

module.exports = JWT
  • index.js
// 🚩校验token的中间件
app.use(async (ctx, next) => {
  if (req.url.includes('login')) {
    await next()
    return
  }

  // 思考?ES6语法
  // const token = req.headers['authorization'] && req.headers['authorization'].split(" ")[1]
  const token = ctx.headers['authorization']?.split(' ')[1]

  if (token) {
    const payload = JWT.verify(token)
    if (payload) {
      // 重新计算token✨过期时间(以最后一次离开的时间为准)
      const newToken = JWT.generate(
        {
          // 设置要存储到token的数据
          _id: payload._id,
          username: payload.username
        },
        '2h'
      )
      ctx.set('Authorization', newToken)

      await next()
    } else {
      ctx.status(401)
      ctx.body = { errCode: -1, errInfo: 'token过期' }
    }
  } else {
    await next()
  }
})
  • routes/user.js
const Router = require('koa-router')
const router = new Router()

router.post('/login', (ctx, next) => {
  const {username, password} = ctx.request.body

  if(username==="lencamo" && password==="123"){
    // 在服务端设置设置🚩header
    const token = JWT.generate({
      _id: '65462fdq'
      username: 'lencamo'
    }, '2h')

    // token返回到✨header上
    ctx.set('Authorization', token)

    ctx.body = {
      ok: 1
    }
  }else{
    ctx.body = {
      ok: 0
    }
  }

  await ctx.render('home', { username: 'lencamo' })
})

module.exports = router
  • views/login.ejs
<head>
  <script>
    axios.interceptors.request.use(
      function (config) {
        // 在发送请求之前做些什么
        // 向服务端发送token✨(校验使用)
        const token = localStorage.getItem('token')
        config.headers.Authorization = `Bearer ${token}`

        return config
      },
      function (error) {
        return Promise.reject(error)
      }
    )

    // 添加响应拦截器
    axios.interceptors.response.use(
      function (response) {
        // 2xx 范围内的状态码都会触发该函数
        // 客户端接收✨token
        console.log(response.headers)
        const { authorization } = response.headers
        authorization && localStorage.setItem('token', authorization)

        return response
      },
      function (error) {
        if (err.response.status === 401) {
          localStorage.removeItem('token')
          localtion.href = '/login'
        }

        return Promise.reject(error)
      }
    )
  </script>
</head>
<body>
  ……
  <script>
    login.onclick = () => {
      aixos
        .post('/user/login', {
          username: username.value,
          password: password.value
        })
        .then((res) => {
          // console.log(res.data)
          // console.log(res.headers)
          if (res.ok === 1) {
            location.href = '/backend'
          } else {
            alert('用户名密码不匹配!!')
          }
        })
    }
  </script>
</body>

# 六、Koa 与 MongoDB 数据库

# 1、安装

npm i mongoose

# 2、连接数据库

  • index.js
require('./config/db.config.js')
  • 新建:config/db.config.js
const mongoose = require('mongoose')

mongoose.connect('mongodb://127.0.0.1:27017/ren_db')

# 3、创建集合对应的 MongoDB 模型

  • 新建:model/userModel.js
const mongoose = require('mongoose')

const Schema = mongoose.Schema
const UserType = {
  username: String,
  password: String,
  age: Number
  phone: String,
}

// 创建的user模型,会自动对应users集合
const userModel = mongoose.model('user', new Schema(UserType))

module.exports = UserModel

# 4、API 接口

  • index.js
const usersRouter = require('./router/usersRouter')

app.use('/api', usersRouter)
  • router/usersRouter.js
// 导入user模型(这样就可以🚩使用user.create | user.find | user.delete | user.update来操作数据了)
const UserModel = require('../model/UserModel')

router.post('/user/add', async (ctx) => {
  console.log(ctx.request.body)
  // ✨前端传来的数据
  const { username, password, age, phone } = ctx.request.body

  await UserModel.create({
    username,
    password,
    age,
    phone
  }).then((data) => {
    console.log(data)

    ctx.body = {
      ok: 1
    }
  })
})
更新于 : 8/7/2024, 2:16:31 PM