Nest.js 从零到壹系列(三):使用 JWT 实现单点登录

本文由图雀社区认证作者 布拉德特皮 写作而成,点击阅读原文查看作者掘金链接,感谢作者的优质输出,让我们的技术世界变得更加美好????

前言

上一篇介绍了如何使用 Sequelize 连接 MySQL,接下来,在原来代码的基础上进行扩展,实现用户的注册和登录功能。

这里需要简单提一下两个概念 JWT 和 单点登录:

JWT

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

具体原理可以参考《JSON Web Token 入门教程 \- 阮一峰》[1]

单点登录

单点登录(Single Sign On),简称为 SSO,是比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。

所以 JWT 实现【单点登录】的大致流程是:

  1. 客户端用户进行登录请求;

  2. 服务端拿到请求,根据参数查询用户表;

  3. 若匹配到用户,将用户信息进行签证,并颁发 Token;

  4. 客户端拿到 Token 后,存储至某一地方,在之后的请求中都带上 Token ;

  5. 服务端接收到带 Token 的请求后,直接根据签证进行校验,无需再查询用户信息;

下面,就开始我们的实战:

GitHub 项目地址[2],欢迎各位大佬 Star。

一、编写加密的工具函数

src 目录下,新建文件夹 utils,里面将存放各种工具函数,然后新建 cryptogram.ts 文件:

import * as crypto from 'crypto';

/**
 * Make salt
 */
export function makeSalt(): string {
  return crypto.randomBytes(3).toString('base64');
}

/**
 * Encrypt password
 * @param password 密码
 * @param salt 密码盐
 */
export function encryptPassword(password: string, salt: string): string {
  if (!password || !salt) {
    return '';
  }
  const tempSalt = Buffer.from(salt, 'base64');
  return (
    // 10000 代表迭代次数 16代表长度
    crypto.pbkdf2Sync(password, tempSalt, 10000, 16, 'sha1').toString('base64')
  );
}

上面写了两个方法,一个是制作一个随机盐(salt),另一个是根据盐来加密密码。

这两个函数将贯穿注册和登录的功能。

二、用户注册

在写注册逻辑之前,我们需要先修改一下上一篇写过的代码,即 user.service.ts 中的 findeOne() 方法:

// src/logical/user/user.service.ts
import { Injectable } from '@nestjs/common';
import * as Sequelize from 'sequelize'; // 引入 Sequelize 库
import sequelize from '../../database/sequelize'; // 引入 Sequelize 实例

@Injectable()
export class UserService {
  /**
   * 查询是否有该用户
   * @param username 用户名
   */
  async findOne(username: string): Promise<any | undefined> {
    const sql = `
      SELECT
        user_id userId, account_name username, real_name realName, passwd password,
        passwd_salt salt, mobile, role
      FROM
        admin_user
      WHERE
        account_name = '${username}'
    `; // 一段平淡无奇的 SQL 查询语句
    try {
      const user = (await sequelize.query(sql, {
        type: Sequelize.QueryTypes.SELECT, // 查询方式
        raw: true, // 是否使用数组组装的方式展示结果
        logging: true, // 是否将 SQL 语句打印到控制台
      }))[0];
      // 若查不到用户,则 user === undefined
      return user;
    } catch (error) {
      console.error(error);
      return void 0;
    }
  }
}

现在,findOne() 的功能更符合它的方法名了,查到了,就返回用户信息,查不到,就返回 undefined

接下来,我们开始编写注册功能:

// src/logical/user/user.service.ts
import { Injectable } from '@nestjs/common';
import * as Sequelize from 'sequelize'; // 引入 Sequelize 库
import sequelize from '../../database/sequelize'; // 引入 Sequelize 实例

import { makeSalt, encryptPassword } from '../../utils/cryptogram'; // 引入加密函数

@Injectable()
export class UserServic
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值