Eggjs登录注册 & JWT鉴权

JWT

Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准([(RFC 7519]).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登陆(SSO)场景。JWT的声明通常被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也能够增长一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。web

JWT认证流程npm

  • 用户使用用户名密码来请求服务器
  • 服务器进行验证用户的信息
  • 服务器经过验证发送给用户一个token
  • 客户端存储token,并在每次请求时附送上这个token值
  • 服务端验证token值,并返回数据

基于session和基于JWT的方式的主要区别就是用户的状态保存的位置,session是保存在服务端的,而JWT是保存在客户端的。api

一旦签发一个JWT,在到期以前就会始终有效,没法中途废弃。安全

Eggjs 实现签发、认证 Token

安装依赖

# jwt
npm i egg-jwt
# 密码加密
bcryptjs
# 数据校验
egg-validate
复制代码

使用插件

config/plugin.jsbash

jwt: {
  enable: true,
  package: 'egg-jwt',
}, 
validate: {
  enable: true,
  package: 'egg-validate',
},
复制代码

修改配置文件

config/config.default.js服务器

// jwt
config.jwt = {
  secret: '123456',
  expiresIn: '24h',
};
// 参数
config.validate = {
  enable: true,
  package: 'egg-validate',
};
// 密码加密
config.bcrypt = {
  saltRounds: 10,
};
复制代码

用户注册、登录接口开发

建立用户模型

app/model/user.jsmarkdown

'use strict';

module.exports = app => {
  const { STRING, INTEGER, DECIMAL, DATE } = app.Sequelize;

  const User = app.model.define('users', {
    id: { type: INTEGER, primaryKey: true, autoIncrement: true },
    userName: {
      type: STRING,
      allowNull: false,
      unique: true,
      comment: '用户名,惟一',
    },
    passWord: STRING,
  });

  return User;
};
复制代码

user Controller

app/controller/user.js网络

// 校验用户注册参数
const vUser = {
  userName: { type: 'string', required: true },
  passWord: { type: 'string', required: true },
};

//...
class UserController extends Controller {
    // 用户注册
  async rigist() {
    const { ctx } = this;
    // 接收并校验参数
    ctx.validate(vUser, ctx.request.body);
    // 判断用户名是否重复
    const users = await ctx.service.user.checkUserName(ctx.request.body);
    if (users[0]) {
      ctx.body = { status: false, msg: '用户名已存在', data: users };
      return;
    }
    await ctx.service.user.Rigist(ctx.request.body);
    ctx.body = { status: true, msg: '注册成功' };
  }

  // 用户登录
  async login() {
    const { ctx } = this;
    // 接收并校验参数
    ctx.validate(vUser, ctx.request.body);
    const data = await ctx.service.user.Login(ctx.request.body);
    if (!data) {
      ctx.status = 401;
      ctx.body = { status: false, msg: '用户名或密码错误' };
      return;
    }
    ctx.body = { status: true, msg: '登录成功', data };
  }
}

module.exports = UserController;
复制代码

user Service

app/service/user.jssession

const bcrypt = require('bcryptjs');

// ......


// 检查用户名
async checkUserName(query) {
  const { userName } = query;
  const users = await this.ctx.model.User.findAll({
    attributes: [ 'userName' ],
    where: { userName },
  });
  return users;
}


// 用户注册
async Rigist(body) {
  const { userName, passWord } = body;
  // 对密码加密
  const hash = bcrypt.hashSync(passWord, this.config.bcrypt.saltRounds);
  const user = await this.ctx.model.User.create({ userName, passWord: hash });
  return user;
}


// 用户登录
async Login(body) {
  const { userName, passWord } = body;
  const user = await this.ctx.model.User.findOne({
    where: { userName },
  });
  if (!user) return {};

  const match = await bcrypt.compare(passWord, user.passWord);
  if (match) {
    const { id, userName } = user;
    // 获取jwt配置
    const { jwt: { secret, expiresIn } } = this.app.config;
    // 生成token
    const token = this.app.jwt.sign({
      id, userName,
    }, secret, { expiresIn });
    return { userName, token };
  }
}
复制代码

router

app/router.jsapp

router.post('/api/v1/user/rigist', controller.user.rigist); // 用户注册
router.post('/api/v1/user/login', controller.user.login); // 用户登录

// 在路由里添加jwt中间件 便可使用jwt鉴权
router.put('/api/v1/user/:id', app.jwt, controller.user.update); // 修改用户信息
复制代码

获取token内容

若是接口使用了app.jwt 中间件

const userToken = this.ctx.state.user;
// 可获取登录时写入token的内容 id, userName,
复制代码

若是接口未使用app.jwt中间件 则没法获取 this.ctx.state.user;

对与某些接口可登录也可不登录,且获取数据有差别时。

此时须要封装解析token的方法

app/extend/utils.js

'use strict';

function getTokenInfo(jwt, auth, secret) {
  // 判断请求头是否包含token
  if (
    auth.authorization &&
    auth.authorization.split(' ')[0] === 'Bearer'
  ) {
    const token = auth.authorization.split(' ')[1];
    let decode = '';
    if (token) {
      decode = jwt.verify(token, secret);
    }
    return decode;
  }
  return;
}

module.exports = {
  getTokenInfo,
};

复制代码

在service里使用

const { jwt: { secret } } = this.app.config;
// 若是存在token 解析token
const authInfo = getTokenInfo(this.ctx.app.jwt, this.ctx.headers, secret);
if (authInfo) {
  // 便可获取 token 内容
  // authInfo.id authInfo.userName
}
复制代码
相关文章
相关标签/搜索