JS登录与注册 | 青训营

57 阅读7分钟

两个月主要主要时间都在磨登录注册,其中学习了node.js、ajax、axios等,以下是一个后台管理系统登录注册代码及思路。

登录

实现思路

第一步:分别对帐号、密码、验证码进行验证,先判断账号、密码、验证码的值是否存在,不存在则引出对应error信息。

第二步:如果值存在,使用正则判断值是否符合要求,正确输出信息,不正确输出error的信息。

第三步:设置表单失焦出现对应的error信息,获焦移除当前的error。

第四步:表单提交的时候,按钮进行获焦,如果没有错误信息就进行提交,并且清除所有信息。

1.检测表单数据是否合法

判断name和password是否为空

const adminInfo = req.body
if (!adminInfo.name || !adminInfo.password) {
    return res.json({ status: 400, message: '用户名或密码为空' })
}

2.检测用户名是否被占用

2.1导入数据库操作模块:

const db = require('../db/index')

 定义sql语句:

const sql = `select * from admin where name = ? `

2.2执行 SQL 语句并根据结果判断用户名是否被占用:

db.query(sql, [adminInfo.name], (err, results) => {
    // 执行sql语句失败
    if (err) {
        return res.send({
            status: 404,
            message: err.message
        })
    }
		
	// 用户名被占用
    if (results.length > 0) {
        return res.status(400).json('用户名已被注册,请更改后重新注册!')
    }
    // TODO: 用户名可用,继续之后流程
})

2.3对密码进行加密处理bcryptjs

为了保证密码的安全性,不建议在数据库以 明文 的形式保存用户密码,推荐对密码进行 加密存储

在当前项目中,使用 bcryptjs 对用户密码进行加密,优点:

加密之后的密码,无法被逆向破解 同一明文密码多次加密,得到的加密结果各不相同,保证了安全性

运行如下命令,安装指定版本的 bcryptjs :

npm i bcryptjs@2.4.3

在 /router_handler/admin.js 中,导入 bcryptjs :

const bcrypt = require('bcryptjs')

2.4在注册用户的处理函数中,确认用户名可用之后,调用bcrypt.hashSync(明文密码, 随机盐的长度)方法,对用户的密码进行加密处理:

// 对用户的密码,进行 bcrype 加密,返回值是加密之后的密码字符串 adminInfo.password = bcrypt.hashSync(adminInfo.password, 10)

插入新用户

  1. 定义插入用户的sql语句
const sqlStr = 'insert into admin set ?'

2.db.query()执行 SQL 语句,插入新用户

db.query(sqlStr, { name: adminInfo.name, password: adminInfo.password, identify: adminInfo.identify }, (err, results) => {
   if (err) {
       return res.send({
           status: 400,
           message: err.message
       })
   }

   if (results.affectedRows !== 1) {
       return res.status(400).json('注册用户失败,请稍后再试')
   }

   res.json({
       status: 200,
       message: '注册成功',
       name: adminInfo.name,
       password: adminInfo.password,
       identify: adminInfo.identify
   })
})

})

注册

检测表单数据是否合法

  1. 判断namepassword是否为空
const adminInfo = req.body
if (!adminInfo.name || !adminInfo.password) {
    return res.json({ status: 400, message: '用户名或密码为空' })
}

1234

检测用户名是否被占用

  1. 导入数据库操作模块:
const db = require('../db/index')

1
  1. 定义sql语句:
const sql = `select * from admin where name = ? `

1
  1. 执行 SQL 语句并根据结果判断用户名是否被占用:
db.query(sql, [adminInfo.name], (err, results) => {
    // 执行sql语句失败
    if (err) {
        return res.send({
            status: 404,
            message: err.message
        })
    }
		
	// 用户名被占用
    if (results.length > 0) {
        return res.status(400).json('用户名已被注册,请更改后重新注册!')
    }
    // TODO: 用户名可用,继续之后流程
})

对密码进行加密处理bcryptjs

为了保证密码的安全性,不建议在数据库以 明文 的形式保存用户密码,推荐对密码进行 加密存储

在当前项目中,使用 bcryptjs 对用户密码进行加密,优点:

  • 加密之后的密码,无法被逆向破解
  • 同一明文密码多次加密,得到的加密结果各不相同,保证了安全性
  1. 运行如下命令,安装指定版本的 bcryptjs
npm i bcryptjs@2.4.3

1
  1. /router_handler/admin.js 中,导入 bcryptjs
const bcrypt = require('bcryptjs')

1
  1. 在注册用户的处理函数中,确认用户名可用之后,调用bcrypt.hashSync(明文密码, 随机盐的长度)方法,对用户的密码进行加密处理:
// 对用户的密码,进行 bcrype 加密,返回值是加密之后的密码字符串
adminInfo.password = bcrypt.hashSync(adminInfo.password, 10)

12

插入新用户

  1. 定义插入用户的sql语句
const sqlStr = 'insert into admin set ?'

1

2.db.query()执行 SQL 语句,插入新用户:

db.query(sqlStr, { name: adminInfo.name, password: adminInfo.password, identify: adminInfo.identify }, (err, results) => {
   if (err) {
       return res.send({
           status: 400,
           message: err.message
       })
   }

   if (results.affectedRows !== 1) {
       return res.status(400).json('注册用户失败,请稍后再试')
   }

   res.json({
       status: 200,
       message: '注册成功',
       name: adminInfo.name,
       password: adminInfo.password,
       identify: adminInfo.identify
   })
})

})

12345678910111213141516171819202122

此时router_handler/amdin_handler.js为:

/**
 * 在这里定义和登录注册相关的路由处理函数
 * 供/router/admin.js模块进行调用
 */
const db = require('../db/index')
const bcrypt = require('bcryptjs')

// 注册用户的处理函数
exports.register = (req, res) => {
    const adminInfo = req.body
    if (!adminInfo.name || !adminInfo.password) {
        return res.json({ status: 400, message: '用户名或密码为空' })
    }

    const sql = `select * from admin where name = ? `
    db.query(sql, [adminInfo.name], (err, results) => {
        if (err) {
            return res.send({
                status: 404,
                message: err.message
            })
        }

        if (results.length > 0) {
            return res.status(400).json('用户名已被注册,请更改后重新注册!')
        }

        // 对用户的密码,进行 bcrype 加密,返回值是加密之后的密码字符串
        adminInfo.password = bcrypt.hashSync(adminInfo.password, 10)

        const sqlStr = 'insert into admin set ?'
        db.query(sqlStr, { name: adminInfo.name, password: adminInfo.password, identify: adminInfo.identify }, (err, results) => {
            if (err) {
                return res.send({
                    status: 400,
                    message: err.message
                })
            }

            if (results.affectedRows !== 1) {
                return res.status(400).json('注册用户失败,请稍后再试')
            }

            res.json({
                status: 200,
                message: '注册成功',
                name: adminInfo.name,
                password: adminInfo.password,
                identify: adminInfo.identify
            })
        })

    })
}

// 登录的处理函数
exports.login = (req, res) => {
    res.send('login')
}

登录

根据名字查询用户的数据

接收表单数据:

const adminInfo = req.body
定义sql语句:

const sql = `select * from admin where name = ?`
执行sql语句,查询用户的数据:

db.query(sql, adminInfo.name, (err, results) => {
    if (err) {
        return res.status(400).json(err)
    }

    if (results.length !== 1) {
        return res.status(400).json('用户不存在')
    }

})

判断用户输入的密码是否正确

核心实现思路:调用 bcrypt.compareSync(用户提交的密码, 数据库中的密码) 方法比较密码是否一致 返回值是布尔值(true 一致、false 不一致)

// 拿着用户输入的密码,和数据库中存储的密码进行对比
const compareResult = bcrypt.compareSync(adminInfo.password, results[0].password)

// 如果对比的结果为false,则证明用户输入的密码错误
if(!compareResult) {
	return res.status(400).json('用户名或密码输入错误,请重新输入')
}

生成 JWT 的 Token 字符串

核心注意点:在生成 Token 字符串的时候,一定要剔除 密码 的值

通过 ES6 的高级语法,快速剔除 密码的值:

// 剔除完毕之后,admin 中只保留了用户的 id,name, identify 这四个属性的值
const admin = { ...results[0], password: '' }
或者
const admin = {
	id: results[0].id,
	name: results[0].name,
	identify: results[0].identify
}

运行如下的命令,安装生成 Token 字符串的包: npm i jsonwebtoken@8.5.1

在/router_handler/admin_handler.js模块的头部区域,导入jsonwebtoken包:

// 用这个包来生成 Token 字符串
const jwt = require('jsonwebtoken')

创建 config.js 文件,并向外共享 加密 和 还原 Token 的 jwtSecretKey 字符串:

module.exports = {
  jwtSecretKey: 'zhanglijun',
}

将用户信息对象加密成 Token 字符串(/router_handler/admin_handler.js):

// 导入配置文件
const config = require('../config')

// 生成 Token 字符串
const tokenStr = jwt.sign(admin, config.jwtSecretKey, {
  expiresIn: '10h', // token 有效期为 10 个小时
})

将生成的 Token 字符串响应给客户端:

res.json({
  status: 200,
  message: '登录成功!',
  // 为了方便客户端使用 Token,在服务器端直接拼接上 Bearer 的前缀
  token: 'Bearer ' + tokenStr,
})

admin_hadler.js代码:

/**
 * 在这里定义和登录注册相关的路由处理函数
 * 供/router/admin.js模块进行调用
 */
const db = require('../db/index')
const bcrypt = require('bcryptjs')
const jwt = require('jsonwebtoken')
const config = require('../config')

// 注册用户的处理函数
exports.register = (req, res) => {
    const adminInfo = req.body
    if (!adminInfo.name || !adminInfo.password) {
        return res.json({ status: 400, message: '用户名或密码为空' })
    }

    const sql = `select * from admin where name = ? `
    db.query(sql, [adminInfo.name], (err, results) => {
        if (err) {
            return res.send({
                status: 404,
                message: err.message
            })
        }

        if (results.length > 0) {
            return res.status(400).json('用户名已被注册,请更改后重新注册!')
        }

        // 对用户的密码,进行 bcrype 加密,返回值是加密之后的密码字符串
        adminInfo.password = bcrypt.hashSync(adminInfo.password, 10)

        const sqlStr = 'insert into admin set ?'
        db.query(sqlStr, { name: adminInfo.name, password: adminInfo.password, identify: adminInfo.identify }, (err, results) => {
            if (err) {
                return res.send({
                    status: 400,
                    message: err.message
                })
            }

            if (results.affectedRows !== 1) {
                return res.status(400).json('注册用户失败,请稍后再试')
            }

            res.json({
                status: 200,
                message: '注册成功',
                name: adminInfo.name,
                password: adminInfo.password,
                identify: adminInfo.identify
            })
        })

    })
}

// 登录的处理函数
exports.login = (req, res) => {
    const adminInfo = req.body
    const sql = `select * from admin where name = ?`
    db.query(sql, adminInfo.name, (err, results) => {
        if (err) {
            return res.status(400).json(err)
        }

        if (results.length !== 1) {
            return res.status(400).json('用户不存在')
        }

        const compareResult = bcrypt.compareSync(adminInfo.password, results[0].password)
        if (!compareResult) {
            return res.status(400).json('用户名或密码输入错误,请重新输入')
        }

        // const admin = { ...results[0], password: '' }
        const admin = {
            id: results[0].id,
            name: results[0].name,
            identify: results[0].identify
        }
        const tokenStr = jwt.sign(admin, config.jwtSecretKey, {
            expiresIn: '10h', // token 有效期为 10 个小时
        })

        // 将生成的 Token 字符串响应给客户端
        res.json({
            status: 200,
            message: '登录成功!',
            // 为了方便客户端使用 Token,在服务器端直接拼接上 Bearer 的前缀
            token: 'Bearer ' + tokenStr,
        })

    })
}