新增云函数

This commit is contained in:
唐明明
2022-01-04 12:05:11 +08:00
parent 304c4c9b98
commit cddd9e7d0e
28 changed files with 1540 additions and 14 deletions

View File

@@ -0,0 +1,503 @@
'use strict';
let uniID = require('uni-id')
const uniCaptcha = require('uni-captcha')
const createConfig = require('uni-config-center')
const uniIdConfig = createConfig({
pluginId: 'uni-id'
}).config()
const db = uniCloud.database()
const dbCmd = db.command
const usersDB = db.collection('uni-id-users')
exports.main = async (event, context) => {
//UNI_WYQ:这里的uniID换成新的保证多人访问不会冲突
uniID = uniID.createInstance({
context
})
console.log('event : ' + JSON.stringify(event))
/*
1.event为客户端 uniCloud.callFunction填写的data的值这里介绍一下其中的属性
action表示要执行的任务名称、比如登陆login、退出登陆 logout等
params业务数据内容
uniIdToken系统自动传递的token数据来源客户端的 uni.getStorageSync('uni_id_token')
*/
const {
action,
uniIdToken,
inviteCode
} = event;
const deviceInfo = event.deviceInfo || {};
let params = event.params || {};
/*
2.在某些操作之前我们要对用户对身份进行校验也就是要检查用户的token再将得到的uid写入params.uid
校验用到的方法是uniID.checkToken 详情https://uniapp.dcloud.io/uniCloud/uni-id?id=checktoken
讨论,我们假设一个这样的场景,代码如下。
如:
uniCloud.callFunction({
name:"xxx",
data:{
"params":{
uid:"通过某种方式获取来的别人的uid"
}
}
})
用户就这样轻易地伪造了他人的uid传递给服务端有一句话叫前端从来的数据是不可信任的
所以这里我们需要将uniID.checkToken返回的uid写入到params.uid
*/
let noCheckAction = ['register', 'checkToken', 'login', 'logout', 'sendSmsCode', 'createCaptcha',
'verifyCaptcha', 'refreshCaptcha', 'inviteLogin', 'loginByWeixin', 'loginByUniverify',
'loginByApple', 'loginBySms', 'resetPwdBySmsCode', 'registerAdmin'
]
if (!noCheckAction.includes(action)) {
if (!uniIdToken) {
return {
code: 403,
msg: '缺少token'
}
}
let payload = await uniID.checkToken(uniIdToken)
if (payload.code && payload.code > 0) {
return payload
}
params.uid = payload.uid
}
//禁止前台用户传递角色
if (action.slice(0, 7) == "loginBy") {
if (params.role) {
return {
code: 403,
msg: '禁止前台用户传递角色'
}
}
}
//3.注册成功后创建新用户的积分表方法
async function registerSuccess(uid) {
//用户接受邀请
if (inviteCode) {
await uniID.acceptInvite({
inviteCode,
uid
});
}
//添加当前用户设备信息
await db.collection('uni-id-device').add({
...deviceInfo,
user_id: uid
})
await db.collection('uni-id-scores').add({
user_id: uid,
score: 1,
type: 1,
balance: 1,
comment: "",
create_date: Date.now()
})
}
//4.记录成功登录的日志方法
const loginLog = async (res = {}) => {
const now = Date.now()
const uniIdLogCollection = db.collection('uni-id-log')
let logData = {
deviceId: params.deviceId || context.DEVICEID,
ip: params.ip || context.CLIENTIP,
type: res.type,
ua: context.CLIENTUA,
create_date: now
};
Object.assign(logData,
res.code === 0 ? {
user_id: res.uid,
state: 1
} : {
state: 0
})
if (res.type == 'register') {
await registerSuccess(res.uid)
} else {
if (Object.keys(deviceInfo).length) {
console.log(979797, {
deviceInfo,
user_id: res
});
//更新当前用户设备信息
await db.collection('uni-id-device').where({
user_id: res.uid
}).update(deviceInfo)
}
}
return await uniIdLogCollection.add(logData)
}
let res = {}
switch (action) { //根据action的值执行对应的操作
case 'bindMobileByUniverify':
let {
appid, apiKey, apiSecret
} = uniIdConfig.service.univerify
let univerifyRes = await uniCloud.getPhoneNumber({
provider: 'univerify',
appid,
apiKey,
apiSecret,
access_token: params.access_token,
openid: params.openid
})
if (univerifyRes.code === 0) {
res = await uniID.bindMobile({
uid: params.uid,
mobile: univerifyRes.phoneNumber
})
res.mobile = univerifyRes.phoneNumber
}
break;
case 'bindMobileBySms':
// console.log({
// uid: params.uid,
// mobile: params.mobile,
// code: params.code
// });
res = await uniID.bindMobile({
uid: params.uid,
mobile: params.mobile,
code: params.code
})
// console.log(res);
break;
case 'register':
var {
username, password, nickname
} = params
if (/^1\d{10}$/.test(username)) {
return {
code: 401,
msg: '用户名不能是手机号'
}
};
if (/^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/.test(username)) {
return {
code: 401,
msg: '用户名不能是邮箱'
}
}
res = await uniID.register({
username,
password,
nickname,
inviteCode
});
if (res.code === 0) {
await registerSuccess(res.uid)
}
break;
case 'login':
//防止黑客恶意破解登录,连续登录失败一定次数后,需要用户提供验证码
const getNeedCaptcha = async () => {
//当用户最近“2小时内(recordDate)”登录失败达到2次(recordSize)时。要求用户提交验证码
const now = Date.now(),
recordDate = 120 * 60 * 1000,
recordSize = 2;
const uniIdLogCollection = db.collection('uni-id-log')
let recentRecord = await uniIdLogCollection.where({
deviceId: params.deviceId || context.DEVICEID,
create_date: dbCmd.gt(now - recordDate),
type: 'login'
})
.orderBy('create_date', 'desc')
.limit(recordSize)
.get();
return recentRecord.data.filter(item => item.state === 0).length === recordSize;
}
let passed = false;
let needCaptcha = await getNeedCaptcha();
console.log('needCaptcha', needCaptcha);
if (needCaptcha) {
res = await uniCaptcha.verify({
...params,
scene: 'login'
})
if (res.code === 0) passed = true;
}
if (!needCaptcha || passed) {
res = await uniID.login({
...params,
queryField: ['username', 'email', 'mobile']
});
res.type = 'login'
await loginLog(res);
needCaptcha = await getNeedCaptcha();
}
res.needCaptcha = needCaptcha;
break;
case 'loginByWeixin':
res = await uniID.loginByWeixin(params);
await uniID.updateUser({
uid: res.uid,
username: "微信用户"
});
res.userInfo.username = "微信用户"
await loginLog(res)
break;
case 'loginByUniverify':
res = await uniID.loginByUniverify(params)
await loginLog(res)
break;
case 'loginByApple':
res = await uniID.loginByApple(params)
await loginLog(res)
break;
case 'checkToken':
res = await uniID.checkToken(uniIdToken);
break;
case 'logout':
res = await uniID.logout(uniIdToken)
break;
case 'sendSmsCode':
/* -开始- 测试期间,为节约资源。统一虚拟短信验证码为: 123456开启以下代码块即可 */
// return uniID.setVerifyCode({
// mobile: params.mobile,
// code: '123456',
// type: params.type
// })
/* -结束- */
// 简单限制一下客户端调用频率
const ipLimit = await db.collection('opendb-verify-codes').where({
ip: context.CLIENTIP,
created_at: dbCmd.gt(Date.now() - 60000)
}).get()
if (ipLimit.data.length > 0) {
return {
code: 429,
msg: '请求过于频繁'
}
}
const templateId = '11753' // 替换为自己申请的模板id
if (!templateId) {
return {
code: 500,
msg: 'sendSmsCode需要传入自己的templateId参考https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=sendsmscode'
}
}
const randomStr = '00000' + Math.floor(Math.random() * 1000000)
const code = randomStr.substring(randomStr.length - 6)
res = await uniID.sendSmsCode({
mobile: params.mobile,
code,
type: params.type,
templateId
})
break;
case 'loginBySms':
if (!params.code) {
return {
code: 500,
msg: '请填写验证码'
}
}
if (!/^1\d{10}$/.test(params.mobile)) {
return {
code: 500,
msg: '手机号码填写错误'
}
}
res = await uniID.loginBySms(params)
await loginLog(res)
break;
case 'resetPwdBySmsCode':
if (!params.code) {
return {
code: 500,
msg: '请填写验证码'
}
}
if (!/^1\d{10}$/.test(params.mobile)) {
return {
code: 500,
msg: '手机号码填写错误'
}
}
params.type = 'login'
let loginBySmsRes = await uniID.loginBySms(params)
// console.log(loginBySmsRes);
if (loginBySmsRes.code === 0) {
res = await uniID.resetPwd({
password: params.password,
"uid": loginBySmsRes.uid
})
} else {
return loginBySmsRes
}
break;
case 'getInviteCode':
res = await uniID.getUserInfo({
uid: params.uid,
field: ['my_invite_code']
})
if (res.code === 0) {
res.myInviteCode = res.userInfo.my_invite_code
delete res.userInfo
}
break;
case 'getInvitedUser':
res = await uniID.getInvitedUser(params)
break;
case 'updatePwd':
res = await uniID.updatePwd(params)
break;
case 'createCaptcha':
res = await uniCaptcha.create(params)
break;
case 'refreshCaptcha':
res = await uniCaptcha.refresh(params)
break;
case 'getUserInviteCode':
res = await uniID.getUserInfo({
uid: params.uid,
field: ['my_invite_code']
})
if (!res.userInfo.my_invite_code) {
res = await uniID.setUserInviteCode({
uid: params.uid
})
}
break;
// =========================== admin api start =========================
case 'registerAdmin': {
var {
username,
password
} = params
let {
total
} = await db.collection('uni-id-users').where({
role: 'admin'
}).count()
if (total) {
return {
code: 10001,
message: '超级管理员已存在,请登录...'
}
}
const appid = params.appid
const appName = params.appName
delete params.appid
delete params.appName
res = await uniID.register({
username,
password,
role: ["admin"]
})
if (res.code === 0) {
const app = await db.collection('opendb-app-list').where({
appid
}).count()
if (!app.total) {
await db.collection('opendb-app-list').add({
appid,
name: appName,
description: "admin 管理后台",
create_date: Date.now()
})
}
}
}
break;
case 'registerUser':
const {
userInfo
} = await uniID.getUserInfo({
uid: params.uid
})
if (userInfo.role.indexOf('admin') === -1) {
res = {
code: 403,
message: '非法访问, 无权限注册超级管理员',
}
} else {
// 过滤 dcloud_appid注册用户成功后再提交
const dcloudAppidList = params.dcloud_appid
delete params.dcloud_appid
res = await uniID.register({
autoSetDcloudAppid: false,
...params
})
if (res.code === 0) {
delete res.token
delete res.tokenExpired
await uniID.setAuthorizedAppLogin({
uid: res.uid,
dcloudAppidList
})
}
}
break;
case 'updateUser': {
const {
userInfo
} = await uniID.getUserInfo({
uid: params.uid
})
if (userInfo.role.indexOf('admin') === -1) {
res = {
code: 403,
message: '非法访问, 无权限注册超级管理员',
}
} else {
// 过滤 dcloud_appid注册用户成功后再提交
const dcloudAppidList = params.dcloud_appid
delete params.dcloud_appid
// 过滤 password注册用户成功后再提交
const password = params.password
delete params.password
// 过滤 uid、id
const id = params.id
delete params.id
delete params.uid
res = await uniID.updateUser({
uid: id,
...params
})
if (res.code === 0) {
if (password) {
await uniID.resetPwd({
uid: id,
password
})
}
await uniID.setAuthorizedAppLogin({
uid: id,
dcloudAppidList
})
}
}
break;
}
case 'getCurrentUserInfo':
res = await uniID.getUserInfo({
uid: params.uid,
...params
})
break;
// =========================== admin api end =========================
default:
res = {
code: 403,
msg: '非法访问'
}
break;
}
//返回数据给客户端
return res
}

View File

@@ -0,0 +1,5 @@
{
"name": "uni-id-cf",
"version": "1.0.0",
"lockfileVersion": 1
}

View File

@@ -0,0 +1,16 @@
{
"name": "uni-id-cf",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"uni-captcha": "file:../../../../uni-captcha/uniCloud/cloudfunctions/common/uni-captcha",
"uni-config-center": "file:../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center",
"uni-id": "file:../../../../uni-id/uniCloud/cloudfunctions/common/uni-id"
}
}