# 注册,登录与鉴权

# 1 注册

  • 数据库定义model
  • 后端写api 处理数据的储存与res; 对密码加密
  • 前端post数据到指定的api

# 2 登录

img

  1. 根据 req.body的username 找password;
  2. 校验密码, 使用(bcrypt) 比较req的密码与找到的密码
  3. 判断密码, 不符合重新登录, 符合返回token
  4. 返回token,(jsonwebtoken)生成token , 参数(选取用户传入的数据, 后端的密匙字段);
  5. 全局错误处理函数, 统一处理让前后端都可以
app.post('/admin/api/login', async (req, res) => {
    const { username, password } = req.body
    // 1.根据用户名找用户

    const user = await AdminUser.findOne({ username }).select('+password')
    assert(user, 422, '用户不存在')
    // 2.校验密码
    const isValid = require('bcrypt').compareSync(password, user.password)
    assert(isValid, 422, '密码错误')
    // 3.返回token
    const token = jwt.sign({ id: user._id }, app.get('secret'))
    res.send({ token })
  })

  // 错误处理函数
  app.use(async (err, req, res, next) => {
    // console.log(err)
    res.status(err.statusCode || 500).send({
      message: err.message
    })
  })

# 3 鉴权

  • 需要登录才能访问资源, req.headers每次请求带token, 后端鉴定token的真实性。

  • 后端鉴权中间件

module.exports = options => {
  const assert = require('http-assert')
  const jwt = require('jsonwebtoken')
  const AdminUser = require('../models/AdminUser')

  return async (req, res, next) => {
    const token = String(req.headers.authorization || '').split(' ').pop()
    assert(token, 401, '请先登录')
    // secret 是加密生成token时的密匙, 
    const { id } = jwt.verify(token, req.app.get('secret'))
    assert(id, 401, '请先登录')
    req.user = await AdminUser.findById(id)
    assert(req.user, 401, '请先登录')
    await next()
  }
}
  • axios前端请求, 每次请求自动加上token.
http.interceptors.request.use(function (config) {
  // Do something before request is sent
  if (localStorage.token) {
    config.headers.Authorization = 'Bearer ' + localStorage.token
  }
  return config;
}, function (error) {
  // Do something with request error
  return Promise.reject(error);
});

# 4 错误处理

  • 前后端约定接口和状态
  • 前端req 错误处理
  • 后端res错误处理
  • 前端res错误处理
前端req 错误处理


http.interceptors.request.use(function (config) {
  // Do something before request is sent
  if (localStorage.token) {
    config.headers.Authorization = 'Bearer ' + localStorage.token
  }
  return config;
}, function (error) {
  // Do something with request error
  return Promise.reject(error);
});



后端res错误处理
app.use(async (err, req, res, next) => {
    // console.log(err)
    res.status(err.statusCode || 500).send({
      message: err.message
    })
  })


前端res错误处理
http.interceptors.response.use(res => {
  return res
}, err => {
  if (err.response.data.message) {
    Vue.prototype.$message({
      type: 'error',
      message: err.response.data.message
    })
    
    if (err.response.status === 401) {
      router.push('/login')
    }
  }
  
  return Promise.reject(err)
})