- 下面开发登录接口,登录接口分为两种,一种是账号密码登录,一种是手机+验证码登录,因为要用到验证码,这里要封装一下生成验证码和校验验证码的方法,在utils文件夹下新建sms.js
ps:这里用到的是阿里云的验证码,阿里云的短信服务应该需要公司身份才能申请,所以有需要的同学看,没办法申请的 略过这个 手机+验证码登录的接口即可
ps:需要用到两个插件 @alicloud/pop-core 、 lodash
cnpm install @alicloud/pop-core lodash --save
/**
* sms.send(手机号) 发送短信验证码
* sms.verify(手机号,验证码) 校验验证码是否正确
**/
const Core = require('@alicloud/pop-core');
const _ = require('lodash');
// 阿里云控制台 - 短信服务 - 国内消息
const SignName = "xxxx"; //换你自己的签名
const TemplateCode = "xxxxx"; //换你自己的模版code
// https://usercenter.console.aliyun.com/
const accessKeyId = "xxxxxx"; // 换你自己的key
const accessKeySecret = "xxxxxxx"; //换你自己的密钥
var client = new Core({
accessKeyId,
accessKeySecret,
endpoint: 'https://dysmsapi.aliyuncs.com',
apiVersion: '2017-05-25'
});
// 保存手机号和验证码的对应关系
// phone_code_list = {'18855551234':['1024']}
var phone_code_list = {};
exports.send = function(phone) {
function randomCode(length) {
var chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
var result = "";
for (var i = 0; i < length; i++) {
var index = Math.ceil(Math.random() * 9);
result += chars[index];
}
return result;
}
// 生成验证码
// var code = "" + _.random(9) + _.random(9) + _.random(9) + _.random(9);
var code = randomCode(6);
console.log(code);
return new Promise((resolve, reject) => {
try {
client.request('SendSms', {
RegionId: "cn-hangzhou",
PhoneNumbers: phone,
SignName,
TemplateCode,
TemplateParam: "{code:" + code + "}"
}, {
method: 'POST'
}).then((result) => {
if (result.Message && result.Message == "OK" && result.Code && result.Code == "OK") { // 短信发送成功
// 保存验证码
if (phone_code_list[phone]) {
phone_code_list[phone].push(code);
} else {
phone_code_list[phone] = [code];
}
// 三分钟后删除验证码
setTimeout(() => {
_.pull(phone_code_list[phone], code);
if (phone_code_list[phone] && phone_code_list[phone].length == 0) {
delete phone_code_list[phone];
}
}, 3 * 60 * 1000)
resolve(result)
} else {
reject(result)
}
}, (ex) => {
reject(ex)
})
} catch (error) {
reject(error)
}
})
}
exports.verify = function(phone, code) {
if (phone_code_list[phone] != undefined) {
return (phone_code_list[phone].indexOf(code) > -1)
} else {
return false
}
}
- 在user.js内引入 sms.js
//引入token.js
var vertoken = require('../utils/token')
// 引入sms.js
const sms = require("../utils/sms")
- 开始编写用户名+密码的登录方式,先在utils文件夹下新建一个filter.js,把非空检验过滤器简单封装下
//用户名+密码登录接口的过滤器
let loginFilter = (req, res, next) => {
if (req.body.loginame && req.body.password) {
next()
} else {
res.json({
code: -1,
msg: "用户名或密码不能为空"
})
}
}
module.exports = {
loginFilter,
}
- 在user.js内引入这个过滤器
// 引入sms.js
const sms = require("../utils/sms")
//引入过滤filter.js
const filter = require("../utils/filter")
- 用户名+密码的登录接口如下:
//用户名+密码登录接口
router.post('/login', filter.loginFilter, (req, res) => {
const loginame = req.body.loginame;
const password = md5(req.body.password);
User.find({ loginame }, (err, docs) => {
if (docs.length == 0) {
res.json({ code: -1, message: '该用户不存在' })
} else if (docs[0].password !== password) {
res.json({ code: -1, message: '用户名或密码错误' })
} else {
vertoken.setToken(docs[0]._id, docs[0].loginame, docs[0].identity).then(token => {
res.json({ code: 200, data: token, message: '登录成功' })
})
}
})
})
ps:注册接口实际上也可以用loginFilter过滤器,可以在注册接口的后面加上filter.loginFilter
router.post('/register', filter.loginFilter, (req, res) =>{ })
- 在写手机号+验证码登录接口之前,我们先来实现一下发送验证码的接口
//发送验证码
router.post('/sendSms', filter.sendSmsFilter, (req, res) => {
const phone = req.body.phone
sms.send(phone).then(result => {
res.json({
code: 200,
message: "短信发送成功!",
})
}).catch(err => {
res.json({
code: -1,
message: err
})
})
})
- 现在我们再来开发手机号+验证码的登录接口 记得配置非空校验过滤器
//手机号+验证码登录接口的过滤器
let loginSmsFilter = (req, res, next) => {
if (req.body.phone && req.body.code) {
next()
} else {
res.json({
code: -1,
msg: "手机号码或验证码不能为空"
})
}
}
ps:我们要清楚,我们写的这个接口,用户手机号如果没有注册过,我们默认给他注册,走注册流程,即登录即注册!!否则就直接登录成功,返回token
router.post('/login/sms', filter.loginSmsFilter, (req, res) => {
const phone = req.body.phone;
const code = req.body.code;
var isCodeRight = sms.verify(phone, code);
if (isCodeRight) {
res.json({ code: -1, message: "手机号或验证码错误" })
} else {
User.find({ phone }, (err, docs) => {
//该用户不存在,走默认注册流程 loginame 设置成phone
if (docs.length == 0) {
const newUser = new User({
loginame: req.body.phone,
phone: req.body.phone,
});
newUser.save((err, result) => {
if (err) {
res.json({ code: -1, message: err })
} else {
vertoken.setToken(result._id, result.loginame, result.identity).then((token) => {
res.json({
code: 200,
token: token,
message: '登录成功'
})
})
}
})
} else {
//存在直接返回token
vertoken.setToken(docs[0]._id, docs[0].loginame, docs[0].identity).then((token) => {
res.json({
code: 200,
token: token,
message: '登录成功'
})
})
}
})
}
})
- 再来开发一个获取用户信息的接口,前端登录后要用到。
//获取用户信息
router.get('/getInfo', (req, res) => {
vertoken.getToken(req.headers.token).then((data) => {
res.json({ code: 200, data, message: "请求成功", })
}).catch((error) => {
res.json({
code: 401,
message: "token失效了"
})
})
})
前台登录注册接口开发完毕!end
接下一章