nodejs -- 登录接口之密码错误限制次数(含代码)

3,593 阅读2分钟

密码次数尝试,可以有效的保护用户账户安全,有了限制之后,就算用量子计算机都束手无策。

银行卡也是这种,尝试次数过多,就锁定,说不定还会自动报警。

效果图

实现思路

数据库表设计

在表里面添加一个字段,string类型。里面包含两个数据,密码失败尝试日期 和 次数 如 2019a10a23|10
这里我使用|做数据段分割,a字母做日期分割

代码逻辑

当记录的日期是当天,那么密码错误的时候,次数+1

当记录的日期不是当天,那么重置

代码封装

这是我实现的简单代码封装

(这里只实现了一天内x次的简单校验,高级规则需要自己改)

/**
 * 尝试登录次数限制
 * login_number [日期, 次数].join('|')
 * 更新到数据库 (更新数据) => {}
 * return {
 *  run bool true: 超过 false: 正常
 *  start 登录失败后修改状态
 * }
 */
exports.Login_n = (login_number, 更新到数据库) => {
    let run = true
    let 当日登录次数 = 0
    let 当日最多尝试次数 = 10
    var getD = () => {
        var date = new Date()
        var d = [date.getUTCFullYear(), date.getMonth() + 1, date.getDate()].join('a')
        return d
    }
    if(login_number){
        let date = login_number.split('|')[0]
        let n = login_number.split('|')[1]
        if(date == getD()){
            当日登录次数 = (+n)
        }
    }
    if(当日登录次数 >= 当日最多尝试次数){
        run = false
    }
    let 登录失败后修改状态函数 = () => {
        let add_login_number
        let 非当日 = () => {
            更新到数据库([getD(), 0].join('|'))
        }
        let 今天 = (n) => {
            更新到数据库([getD(), n].join('|'))
        }
        if(!login_number){
            非当日()
        }else{
            let date = login_number.split('|')[0]
            let n = login_number.split('|')[1]
            if(date == getD()){
                今天((+n) + 1)
            }
        }
    }
    return {
        run,
        start: 登录失败后修改状态函数
    }
}

使用

引入 & 设置状态

var { Login_n } = require('./login_n')
var login_n = Login_n(login_number, (v) => {
    db('all', 'update t_user set login_number=? where id=?', [v, id]).then(results => {
        console.log('修改登录失败次数记录成功')
    })
})

拦截

if(!login_n.run){
    resolve({
        code: 1,
        msg: '账户异常锁定, 请明天再试'
    })
    return
}

密码错误开始记录

if(results[0].pw !== pw){
    // 登录失败,更新登录次数
    login_n.start()
	resolve({
        code: 1,
        msg: '密码错误'
    })
	return
} 

登录完整代码

需要引入上面的(错误限制次数代码)
这里的md5,是为了双重加密,当内部员工拿到数据库密码后也不容易登录, 依赖nodejs内置包crypto

var crypto = require('crypto')
exports.phone_pw_login = (params, req) => new Promise((resolve, reject) => {
    var { Login_n } = require('./login_n')
    let {pass, phone} = params
    var md5 = crypto.createHash("md5");
    let pw = md5.update(pass).digest('hex').toUpperCase()
    db('all', 'SELECT phone, pw, id, name, login_number from t_user WHERE phone=?', [phone]).then(results => {
        let { login_number, id } = results[0]
        // 账号不存在
        if(results.length == 0){
		    resolve({
		        code: 1,
		        msg: '密码错误', // 避免得知是否注册账号
		    })
        	return
        }

        // 次数校验
        var login_n = Login_n(login_number, (v) => {
            db('all', 'update t_user set login_number=? where id=?', [v, id]).then(results => {
                console.log('修改登录失败次数记录成功')
            })
        })
        if(!login_n.run){
            resolve({
                code: 1,
                msg: '账户异常锁定, 请明天再试'
            })
            return
        }

        if(results[0].pw !== pw){
            // 登录失败,更新登录次数
            login_n.start()
        	resolve({
		        code: 1,
		        msg: '密码错误'
            })
        	return
        } 
        let token = Jwt.Create({phone: results[0].phone, id: id, pw})
        
        resolve({
	        code: 200,
	        msg: {
	        	name: results[0].name,
	        	phone: results[0].phone,
	        	token,
	        }
	    })
    })
    .catch(error => {
        console.log(error)
        resolve({
            code: 1,
            msg: '服务器错误'
        })
    })
})

结束了
嘻嘻