首次完整推送,
V:1.20240808.006
This commit is contained in:
@ -0,0 +1,16 @@
|
||||
const {
|
||||
setUserStatus
|
||||
} = require('../../lib/utils/update-user-info')
|
||||
const {
|
||||
USER_STATUS
|
||||
} = require('../../common/constants')
|
||||
|
||||
/**
|
||||
* 注销账户
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#close-account
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function () {
|
||||
const { uid } = this.authInfo
|
||||
return setUserStatus(uid, USER_STATUS.CLOSED)
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
const {
|
||||
userCollection
|
||||
} = require('../../common/constants')
|
||||
const {
|
||||
ERROR
|
||||
} = require('../../common/error')
|
||||
|
||||
function isUsernameSet (userRecord) {
|
||||
return !!userRecord.username
|
||||
}
|
||||
function isNicknameSet (userRecord) {
|
||||
return !!userRecord.nickname
|
||||
}
|
||||
function isPasswordSet (userRecord) {
|
||||
return !!userRecord.password
|
||||
}
|
||||
function isMobileBound (userRecord) {
|
||||
return !!(userRecord.mobile && userRecord.mobile_confirmed)
|
||||
}
|
||||
function isEmailBound (userRecord) {
|
||||
return !!(userRecord.email && userRecord.email_confirmed)
|
||||
}
|
||||
function isWeixinBound (userRecord) {
|
||||
return !!(
|
||||
userRecord.wx_unionid ||
|
||||
Object.keys(userRecord.wx_openid || {}).length
|
||||
)
|
||||
}
|
||||
function isQQBound (userRecord) {
|
||||
return !!(
|
||||
userRecord.qq_unionid ||
|
||||
Object.keys(userRecord.qq_openid || {}).length
|
||||
)
|
||||
}
|
||||
function isAlipayBound (userRecord) {
|
||||
return !!userRecord.ali_openid
|
||||
}
|
||||
function isAppleBound (userRecord) {
|
||||
return !!userRecord.apple_openid
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取账户账户简略信息
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-account-info
|
||||
*/
|
||||
module.exports = async function () {
|
||||
const {
|
||||
uid
|
||||
} = this.authInfo
|
||||
const getUserRes = await userCollection.doc(uid).get()
|
||||
const userRecord = getUserRes && getUserRes.data && getUserRes.data[0]
|
||||
if (!userRecord) {
|
||||
throw {
|
||||
errCode: ERROR.ACCOUNT_NOT_EXISTS
|
||||
}
|
||||
}
|
||||
return {
|
||||
errCode: 0,
|
||||
isUsernameSet: isUsernameSet(userRecord),
|
||||
isNicknameSet: isNicknameSet(userRecord),
|
||||
isPasswordSet: isPasswordSet(userRecord),
|
||||
isMobileBound: isMobileBound(userRecord),
|
||||
isEmailBound: isEmailBound(userRecord),
|
||||
isWeixinBound: isWeixinBound(userRecord),
|
||||
isQQBound: isQQBound(userRecord),
|
||||
isAlipayBound: isAlipayBound(userRecord),
|
||||
isAppleBound: isAppleBound(userRecord)
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
const { userCollection } = require('../../common/constants')
|
||||
const { ERROR } = require('../../common/error')
|
||||
const { decryptData } = require('../../common/sensitive-aes-cipher')
|
||||
const { dataDesensitization } = require('../../common/utils')
|
||||
|
||||
/**
|
||||
* 获取实名信息
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-realname-info
|
||||
* @param {Object} params
|
||||
* @param {Boolean} params.decryptData 是否解密数据
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
decryptData: {
|
||||
required: false,
|
||||
type: 'boolean'
|
||||
}
|
||||
}
|
||||
|
||||
this.middleware.validate(params, schema)
|
||||
|
||||
const { decryptData: isDecryptData = true } = params
|
||||
|
||||
const {
|
||||
uid
|
||||
} = this.authInfo
|
||||
const getUserRes = await userCollection.doc(uid).get()
|
||||
const userRecord = getUserRes && getUserRes.data && getUserRes.data[0]
|
||||
if (!userRecord) {
|
||||
throw {
|
||||
errCode: ERROR.ACCOUNT_NOT_EXISTS
|
||||
}
|
||||
}
|
||||
|
||||
const { realname_auth: realNameAuth = {} } = userRecord
|
||||
|
||||
return {
|
||||
errCode: 0,
|
||||
type: realNameAuth.type,
|
||||
authStatus: realNameAuth.auth_status,
|
||||
realName: isDecryptData ? dataDesensitization(decryptData.call(this, realNameAuth.real_name), { onlyLast: true }) : realNameAuth.real_name,
|
||||
identity: isDecryptData ? dataDesensitization(decryptData.call(this, realNameAuth.identity)) : realNameAuth.identity
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
module.exports = {
|
||||
setPwd: require('./set-pwd'),
|
||||
updatePwd: require('./update-pwd'),
|
||||
resetPwdBySms: require('./reset-pwd-by-sms'),
|
||||
resetPwdByEmail: require('./reset-pwd-by-email'),
|
||||
closeAccount: require('./close-account'),
|
||||
getAccountInfo: require('./get-account-info'),
|
||||
getRealNameInfo: require('./get-realname-info')
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
const {
|
||||
ERROR
|
||||
} = require('../../common/error')
|
||||
const {
|
||||
getNeedCaptcha,
|
||||
verifyCaptcha
|
||||
} = require('../../lib/utils/captcha')
|
||||
const {
|
||||
verifyEmailCode
|
||||
} = require('../../lib/utils/verify-code')
|
||||
const {
|
||||
userCollection,
|
||||
EMAIL_SCENE,
|
||||
CAPTCHA_SCENE,
|
||||
LOG_TYPE
|
||||
} = require('../../common/constants')
|
||||
const {
|
||||
findUser
|
||||
} = require('../../lib/utils/account')
|
||||
const PasswordUtils = require('../../lib/utils/password')
|
||||
|
||||
/**
|
||||
* 通过邮箱验证码重置密码
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#reset-pwd-by-email
|
||||
* @param {object} params
|
||||
* @param {string} params.email 邮箱
|
||||
* @param {string} params.code 邮箱验证码
|
||||
* @param {string} params.password 密码
|
||||
* @param {string} params.captcha 图形验证码
|
||||
* @returns {object}
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
email: 'email',
|
||||
code: 'string',
|
||||
password: 'password',
|
||||
captcha: {
|
||||
required: false,
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
const {
|
||||
email,
|
||||
code,
|
||||
password,
|
||||
captcha
|
||||
} = params
|
||||
|
||||
const needCaptcha = await getNeedCaptcha.call(this, {
|
||||
email,
|
||||
type: LOG_TYPE.RESET_PWD_BY_EMAIL
|
||||
})
|
||||
if (needCaptcha) {
|
||||
await verifyCaptcha.call(this, {
|
||||
captcha,
|
||||
scene: CAPTCHA_SCENE.RESET_PWD_BY_EMAIL
|
||||
})
|
||||
}
|
||||
try {
|
||||
// 验证手机号验证码,验证不通过时写入失败日志
|
||||
await verifyEmailCode({
|
||||
email,
|
||||
code,
|
||||
scene: EMAIL_SCENE.RESET_PWD_BY_EMAIL
|
||||
})
|
||||
} catch (error) {
|
||||
await this.middleware.uniIdLog({
|
||||
data: {
|
||||
email
|
||||
},
|
||||
type: LOG_TYPE.RESET_PWD_BY_EMAIL,
|
||||
success: false
|
||||
})
|
||||
throw error
|
||||
}
|
||||
// 根据手机号查找匹配的用户
|
||||
const {
|
||||
total,
|
||||
userMatched
|
||||
} = await findUser.call(this, {
|
||||
userQuery: {
|
||||
email
|
||||
},
|
||||
authorizedApp: [this.getUniversalClientInfo().appId]
|
||||
})
|
||||
if (userMatched.length === 0) {
|
||||
if (total > 0) {
|
||||
throw {
|
||||
errCode: ERROR.ACCOUNT_NOT_EXISTS_IN_CURRENT_APP
|
||||
}
|
||||
}
|
||||
throw {
|
||||
errCode: ERROR.ACCOUNT_NOT_EXISTS
|
||||
}
|
||||
} else if (userMatched.length > 1) {
|
||||
throw {
|
||||
errCode: ERROR.ACCOUNT_CONFLICT
|
||||
}
|
||||
}
|
||||
const { _id: uid } = userMatched[0]
|
||||
const {
|
||||
passwordHash,
|
||||
version
|
||||
} = new PasswordUtils({
|
||||
clientInfo: this.getUniversalClientInfo(),
|
||||
passwordSecret: this.config.passwordSecret
|
||||
}).generatePasswordHash({
|
||||
password
|
||||
})
|
||||
// 更新用户密码
|
||||
await userCollection.doc(uid).update({
|
||||
password: passwordHash,
|
||||
password_secret_version: version,
|
||||
valid_token_date: Date.now()
|
||||
})
|
||||
|
||||
// 写入成功日志
|
||||
await this.middleware.uniIdLog({
|
||||
data: {
|
||||
email
|
||||
},
|
||||
type: LOG_TYPE.RESET_PWD_BY_SMS
|
||||
})
|
||||
return {
|
||||
errCode: 0
|
||||
}
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
const {
|
||||
ERROR
|
||||
} = require('../../common/error')
|
||||
const {
|
||||
getNeedCaptcha,
|
||||
verifyCaptcha
|
||||
} = require('../../lib/utils/captcha')
|
||||
const {
|
||||
verifyMobileCode
|
||||
} = require('../../lib/utils/verify-code')
|
||||
const {
|
||||
userCollection,
|
||||
SMS_SCENE,
|
||||
CAPTCHA_SCENE,
|
||||
LOG_TYPE
|
||||
} = require('../../common/constants')
|
||||
const {
|
||||
findUser
|
||||
} = require('../../lib/utils/account')
|
||||
const PasswordUtils = require('../../lib/utils/password')
|
||||
|
||||
/**
|
||||
* 通过短信验证码重置密码
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#reset-pwd-by-sms
|
||||
* @param {object} params
|
||||
* @param {string} params.mobile 手机号
|
||||
* @param {string} params.mobile 短信验证码
|
||||
* @param {string} params.password 密码
|
||||
* @param {string} params.captcha 图形验证码
|
||||
* @returns {object}
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
mobile: 'mobile',
|
||||
code: 'string',
|
||||
password: 'password',
|
||||
captcha: {
|
||||
required: false,
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
const {
|
||||
mobile,
|
||||
code,
|
||||
password,
|
||||
captcha
|
||||
} = params
|
||||
|
||||
const needCaptcha = await getNeedCaptcha.call(this, {
|
||||
mobile,
|
||||
type: LOG_TYPE.RESET_PWD_BY_SMS
|
||||
})
|
||||
if (needCaptcha) {
|
||||
await verifyCaptcha.call(this, {
|
||||
captcha,
|
||||
scene: CAPTCHA_SCENE.RESET_PWD_BY_SMS
|
||||
})
|
||||
}
|
||||
try {
|
||||
// 验证手机号验证码,验证不通过时写入失败日志
|
||||
await verifyMobileCode({
|
||||
mobile,
|
||||
code,
|
||||
scene: SMS_SCENE.RESET_PWD_BY_SMS
|
||||
})
|
||||
} catch (error) {
|
||||
await this.middleware.uniIdLog({
|
||||
data: {
|
||||
mobile
|
||||
},
|
||||
type: LOG_TYPE.RESET_PWD_BY_SMS,
|
||||
success: false
|
||||
})
|
||||
throw error
|
||||
}
|
||||
// 根据手机号查找匹配的用户
|
||||
const {
|
||||
total,
|
||||
userMatched
|
||||
} = await findUser.call(this, {
|
||||
userQuery: {
|
||||
mobile
|
||||
},
|
||||
authorizedApp: [this.getUniversalClientInfo().appId]
|
||||
})
|
||||
if (userMatched.length === 0) {
|
||||
if (total > 0) {
|
||||
throw {
|
||||
errCode: ERROR.ACCOUNT_NOT_EXISTS_IN_CURRENT_APP
|
||||
}
|
||||
}
|
||||
throw {
|
||||
errCode: ERROR.ACCOUNT_NOT_EXISTS
|
||||
}
|
||||
} else if (userMatched.length > 1) {
|
||||
throw {
|
||||
errCode: ERROR.ACCOUNT_CONFLICT
|
||||
}
|
||||
}
|
||||
const { _id: uid } = userMatched[0]
|
||||
const {
|
||||
passwordHash,
|
||||
version
|
||||
} = new PasswordUtils({
|
||||
clientInfo: this.getUniversalClientInfo(),
|
||||
passwordSecret: this.config.passwordSecret
|
||||
}).generatePasswordHash({
|
||||
password
|
||||
})
|
||||
// 更新用户密码
|
||||
await userCollection.doc(uid).update({
|
||||
password: passwordHash,
|
||||
password_secret_version: version,
|
||||
valid_token_date: Date.now()
|
||||
})
|
||||
|
||||
// 写入成功日志
|
||||
await this.middleware.uniIdLog({
|
||||
data: {
|
||||
mobile
|
||||
},
|
||||
type: LOG_TYPE.RESET_PWD_BY_SMS
|
||||
})
|
||||
return {
|
||||
errCode: 0
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
const { userCollection, SMS_SCENE, LOG_TYPE, CAPTCHA_SCENE } = require('../../common/constants')
|
||||
const { ERROR } = require('../../common/error')
|
||||
const { verifyMobileCode } = require('../../lib/utils/verify-code')
|
||||
const PasswordUtils = require('../../lib/utils/password')
|
||||
const { getNeedCaptcha, verifyCaptcha } = require('../../lib/utils/captcha')
|
||||
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
password: 'password',
|
||||
code: 'string',
|
||||
captcha: {
|
||||
required: false,
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
|
||||
const { password, code, captcha } = params
|
||||
const uid = this.authInfo.uid
|
||||
const getUserRes = await userCollection.doc(uid).get()
|
||||
const userRecord = getUserRes.data[0]
|
||||
if (!userRecord) {
|
||||
throw {
|
||||
errCode: ERROR.ACCOUNT_NOT_EXISTS
|
||||
}
|
||||
}
|
||||
|
||||
const needCaptcha = await getNeedCaptcha.call(this, {
|
||||
mobile: userRecord.mobile
|
||||
})
|
||||
|
||||
if (needCaptcha) {
|
||||
await verifyCaptcha.call(this, {
|
||||
captcha,
|
||||
scene: CAPTCHA_SCENE.SET_PWD_BY_SMS
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
// 验证手机号验证码,验证不通过时写入失败日志
|
||||
await verifyMobileCode({
|
||||
mobile: userRecord.mobile,
|
||||
code,
|
||||
scene: SMS_SCENE.SET_PWD_BY_SMS
|
||||
})
|
||||
} catch (error) {
|
||||
await this.middleware.uniIdLog({
|
||||
data: {
|
||||
mobile: userRecord.mobile
|
||||
},
|
||||
type: LOG_TYPE.SET_PWD_BY_SMS,
|
||||
success: false
|
||||
})
|
||||
throw error
|
||||
}
|
||||
|
||||
const {
|
||||
passwordHash,
|
||||
version
|
||||
} = new PasswordUtils({
|
||||
clientInfo: this.getUniversalClientInfo(),
|
||||
passwordSecret: this.config.passwordSecret
|
||||
}).generatePasswordHash({
|
||||
password
|
||||
})
|
||||
|
||||
// 更新用户密码
|
||||
await userCollection.doc(uid).update({
|
||||
password: passwordHash,
|
||||
password_secret_version: version
|
||||
})
|
||||
|
||||
await this.middleware.uniIdLog({
|
||||
data: {
|
||||
mobile: userRecord.mobile
|
||||
},
|
||||
type: LOG_TYPE.SET_PWD_BY_SMS
|
||||
})
|
||||
|
||||
return {
|
||||
errCode: 0
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
const {
|
||||
userCollection
|
||||
} = require('../../common/constants')
|
||||
const {
|
||||
ERROR
|
||||
} = require('../../common/error')
|
||||
const PasswordUtils = require('../../lib/utils/password')
|
||||
/**
|
||||
* 更新密码
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#update-pwd
|
||||
* @param {object} params
|
||||
* @param {string} params.oldPassword 旧密码
|
||||
* @param {string} params.newPassword 新密码
|
||||
* @returns {object}
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
oldPassword: 'string', // 防止密码规则调整导致旧密码无法更新
|
||||
newPassword: 'password'
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
const uid = this.authInfo.uid
|
||||
const getUserRes = await userCollection.doc(uid).get()
|
||||
const userRecord = getUserRes.data[0]
|
||||
if (!userRecord) {
|
||||
throw {
|
||||
errCode: ERROR.ACCOUNT_NOT_EXISTS
|
||||
}
|
||||
}
|
||||
const {
|
||||
oldPassword,
|
||||
newPassword
|
||||
} = params
|
||||
const passwordUtils = new PasswordUtils({
|
||||
userRecord,
|
||||
clientInfo: this.getUniversalClientInfo(),
|
||||
passwordSecret: this.config.passwordSecret
|
||||
})
|
||||
|
||||
const {
|
||||
success: checkPasswordSuccess
|
||||
} = passwordUtils.checkUserPassword({
|
||||
password: oldPassword,
|
||||
autoRefresh: false
|
||||
})
|
||||
|
||||
if (!checkPasswordSuccess) {
|
||||
throw {
|
||||
errCode: ERROR.PASSWORD_ERROR
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
passwordHash,
|
||||
version
|
||||
} = passwordUtils.generatePasswordHash({
|
||||
password: newPassword
|
||||
})
|
||||
|
||||
await userCollection.doc(uid).update({
|
||||
password: passwordHash,
|
||||
password_secret_version: version,
|
||||
valid_token_date: Date.now() // refreshToken时会校验,如果创建token时间在此时间点之前,则拒绝下发新token,返回token失效错误码
|
||||
})
|
||||
// 执行更新密码操作后客户端应将用户退出重新登录
|
||||
return {
|
||||
errCode: 0
|
||||
}
|
||||
}
|
@ -0,0 +1,131 @@
|
||||
const {
|
||||
findUser
|
||||
} = require('../../lib/utils/account')
|
||||
const {
|
||||
ERROR
|
||||
} = require('../../common/error')
|
||||
const {
|
||||
userCollection
|
||||
} = require('../../common/constants')
|
||||
const PasswordUtils = require('../../lib/utils/password')
|
||||
|
||||
/**
|
||||
* 新增用户
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#add-user
|
||||
* @param {Object} params
|
||||
* @param {String} params.username 用户名
|
||||
* @param {String} params.password 密码
|
||||
* @param {String} params.nickname 昵称
|
||||
* @param {Array} params.authorizedApp 允许登录的AppID列表
|
||||
* @param {Array} params.role 用户角色列表
|
||||
* @param {String} params.mobile 手机号
|
||||
* @param {String} params.email 邮箱
|
||||
* @param {Array} params.tags 用户标签
|
||||
* @param {Number} params.status 用户状态
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
username: 'username',
|
||||
password: 'password',
|
||||
authorizedApp: {
|
||||
required: false,
|
||||
type: 'array<string>'
|
||||
}, // 指定允许登录的app,传空数组或不传时表示可以不可以在任何端登录
|
||||
nickname: {
|
||||
required: false,
|
||||
type: 'nickname'
|
||||
},
|
||||
role: {
|
||||
require: false,
|
||||
type: 'array<string>'
|
||||
},
|
||||
mobile: {
|
||||
required: false,
|
||||
type: 'mobile'
|
||||
},
|
||||
email: {
|
||||
required: false,
|
||||
type: 'email'
|
||||
},
|
||||
tags: {
|
||||
required: false,
|
||||
type: 'array<string>'
|
||||
},
|
||||
status: {
|
||||
required: false,
|
||||
type: 'number'
|
||||
}
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
const {
|
||||
username,
|
||||
password,
|
||||
authorizedApp,
|
||||
nickname,
|
||||
role,
|
||||
mobile,
|
||||
email,
|
||||
tags,
|
||||
status
|
||||
} = params
|
||||
const {
|
||||
userMatched
|
||||
} = await findUser({
|
||||
userQuery: {
|
||||
username,
|
||||
mobile,
|
||||
email
|
||||
},
|
||||
authorizedApp
|
||||
})
|
||||
if (userMatched.length) {
|
||||
throw {
|
||||
errCode: ERROR.ACCOUNT_EXISTS
|
||||
}
|
||||
}
|
||||
const passwordUtils = new PasswordUtils({
|
||||
clientInfo: this.getUniversalClientInfo(),
|
||||
passwordSecret: this.config.passwordSecret
|
||||
})
|
||||
const {
|
||||
passwordHash,
|
||||
version
|
||||
} = passwordUtils.generatePasswordHash({
|
||||
password
|
||||
})
|
||||
const data = {
|
||||
username,
|
||||
password: passwordHash,
|
||||
password_secret_version: version,
|
||||
dcloud_appid: authorizedApp || [],
|
||||
nickname,
|
||||
role: role || [],
|
||||
mobile,
|
||||
email,
|
||||
tags: tags || [],
|
||||
status
|
||||
}
|
||||
if (email) {
|
||||
data.email_confirmed = 1
|
||||
}
|
||||
if (mobile) {
|
||||
data.mobile_confirmed = 1
|
||||
}
|
||||
|
||||
// 触发 beforeRegister 钩子
|
||||
const beforeRegister = this.hooks.beforeRegister
|
||||
let userRecord = data
|
||||
if (beforeRegister) {
|
||||
userRecord = await beforeRegister({
|
||||
userRecord,
|
||||
clientInfo: this.getUniversalClientInfo()
|
||||
})
|
||||
}
|
||||
|
||||
await userCollection.add(userRecord)
|
||||
return {
|
||||
errCode: 0,
|
||||
errMsg: ''
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
addUser: require('./add-user'),
|
||||
updateUser: require('./update-user')
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
const {
|
||||
findUser
|
||||
} = require('../../lib/utils/account')
|
||||
const {
|
||||
ERROR
|
||||
} = require('../../common/error')
|
||||
const {
|
||||
userCollection
|
||||
} = require('../../common/constants')
|
||||
const PasswordUtils = require('../../lib/utils/password')
|
||||
|
||||
/**
|
||||
* 修改用户
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#update-user
|
||||
* @param {Object} params
|
||||
* @param {String} params.uid 要更新的用户id
|
||||
* @param {String} params.username 用户名
|
||||
* @param {String} params.password 密码
|
||||
* @param {String} params.nickname 昵称
|
||||
* @param {Array} params.authorizedApp 允许登录的AppID列表
|
||||
* @param {Array} params.role 用户角色列表
|
||||
* @param {String} params.mobile 手机号
|
||||
* @param {String} params.email 邮箱
|
||||
* @param {Array} params.tags 用户标签
|
||||
* @param {Number} params.status 用户状态
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
uid: 'string',
|
||||
username: 'username',
|
||||
password: {
|
||||
required: false,
|
||||
type: 'password'
|
||||
},
|
||||
authorizedApp: {
|
||||
required: false,
|
||||
type: 'array<string>'
|
||||
}, // 指定允许登录的app,传空数组或不传时表示可以不可以在任何端登录
|
||||
nickname: {
|
||||
required: false,
|
||||
type: 'nickname'
|
||||
},
|
||||
role: {
|
||||
require: false,
|
||||
type: 'array<string>'
|
||||
},
|
||||
mobile: {
|
||||
required: false,
|
||||
type: 'mobile'
|
||||
},
|
||||
email: {
|
||||
required: false,
|
||||
type: 'email'
|
||||
},
|
||||
tags: {
|
||||
required: false,
|
||||
type: 'array<string>'
|
||||
},
|
||||
status: {
|
||||
required: false,
|
||||
type: 'number'
|
||||
}
|
||||
}
|
||||
|
||||
this.middleware.validate(params, schema)
|
||||
|
||||
const {
|
||||
uid,
|
||||
username,
|
||||
password,
|
||||
authorizedApp,
|
||||
nickname,
|
||||
role,
|
||||
mobile,
|
||||
email,
|
||||
tags,
|
||||
status
|
||||
} = params
|
||||
|
||||
// 更新的用户数据字段
|
||||
const data = {
|
||||
username,
|
||||
dcloud_appid: authorizedApp,
|
||||
nickname,
|
||||
role,
|
||||
mobile,
|
||||
email,
|
||||
tags,
|
||||
status
|
||||
}
|
||||
|
||||
const realData = Object.keys(data).reduce((res, key) => {
|
||||
const item = data[key]
|
||||
if (item !== undefined) {
|
||||
res[key] = item
|
||||
}
|
||||
return res
|
||||
}, {})
|
||||
|
||||
// 更新用户名时验证用户名是否重新
|
||||
if (username) {
|
||||
const {
|
||||
userMatched
|
||||
} = await findUser({
|
||||
userQuery: {
|
||||
username
|
||||
},
|
||||
authorizedApp
|
||||
})
|
||||
if (userMatched.filter(user => user._id !== uid).length) {
|
||||
throw {
|
||||
errCode: ERROR.ACCOUNT_EXISTS
|
||||
}
|
||||
}
|
||||
}
|
||||
if (password) {
|
||||
const passwordUtils = new PasswordUtils({
|
||||
clientInfo: this.getUniversalClientInfo(),
|
||||
passwordSecret: this.config.passwordSecret
|
||||
})
|
||||
const {
|
||||
passwordHash,
|
||||
version
|
||||
} = passwordUtils.generatePasswordHash({
|
||||
password
|
||||
})
|
||||
|
||||
realData.password = passwordHash
|
||||
realData.password_secret_version = version
|
||||
}
|
||||
|
||||
await userCollection.doc(uid).update(realData)
|
||||
|
||||
return {
|
||||
errCode: 0
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
function isMobileCodeSupported () {
|
||||
const config = this.config
|
||||
return !!(config.service && config.service.sms && config.service.sms.smsKey)
|
||||
}
|
||||
|
||||
function isUniverifySupport () {
|
||||
return true
|
||||
}
|
||||
|
||||
function isWeixinSupported () {
|
||||
this.configUtils.getOauthConfig({
|
||||
provider: 'weixin'
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
function isQQSupported () {
|
||||
this.configUtils.getOauthConfig({
|
||||
provider: 'qq'
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
function isAppleSupported () {
|
||||
this.configUtils.getOauthConfig({
|
||||
provider: 'apple'
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
function isAlipaySupported () {
|
||||
this.configUtils.getOauthConfig({
|
||||
provider: 'alipay'
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
const loginTypeTester = {
|
||||
'mobile-code': isMobileCodeSupported,
|
||||
univerify: isUniverifySupport,
|
||||
weixin: isWeixinSupported,
|
||||
qq: isQQSupported,
|
||||
apple: isAppleSupported,
|
||||
alipay: isAlipaySupported
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取支持的登录方式
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-supported-login-type
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function () {
|
||||
const supportedLoginType = [
|
||||
'username-password',
|
||||
'mobile-password',
|
||||
'email-password'
|
||||
]
|
||||
for (const type in loginTypeTester) {
|
||||
try {
|
||||
if (loginTypeTester[type].call(this)) {
|
||||
supportedLoginType.push(type)
|
||||
}
|
||||
} catch (error) { }
|
||||
}
|
||||
return {
|
||||
errCode: 0,
|
||||
errMsg: '',
|
||||
supportedLoginType
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
getSupportedLoginType: require('./get-supported-login-type')
|
||||
}
|
5
uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/index.js
vendored
Normal file
5
uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/index.js
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
externalRegister: require('./register'),
|
||||
externalLogin: require('./login'),
|
||||
updateUserInfoByExternal: require('./update-user-info')
|
||||
}
|
68
uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/login.js
vendored
Normal file
68
uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/login.js
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
const { preLogin, postLogin } = require('../../lib/utils/login')
|
||||
const { EXTERNAL_DIRECT_CONNECT_PROVIDER } = require('../../common/constants')
|
||||
const { ERROR } = require('../../common/error')
|
||||
|
||||
/**
|
||||
* 外部用户登录
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#external-login
|
||||
* @param {object} params
|
||||
* @param {string} params.uid uni-id体系用户id
|
||||
* @param {string} params.externalUid 业务系统的用户id
|
||||
* @returns {object}
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
uid: {
|
||||
required: false,
|
||||
type: 'string'
|
||||
},
|
||||
externalUid: {
|
||||
required: false,
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
|
||||
this.middleware.validate(params, schema)
|
||||
|
||||
const {
|
||||
uid,
|
||||
externalUid
|
||||
} = params
|
||||
|
||||
if (!uid && !externalUid) {
|
||||
throw {
|
||||
errCode: ERROR.PARAM_REQUIRED,
|
||||
errMsgValue: {
|
||||
param: 'uid or externalUid'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let query
|
||||
if (uid) {
|
||||
query = {
|
||||
_id: uid
|
||||
}
|
||||
} else {
|
||||
query = {
|
||||
identities: {
|
||||
provider: EXTERNAL_DIRECT_CONNECT_PROVIDER,
|
||||
uid: externalUid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const user = await preLogin.call(this, {
|
||||
user: query
|
||||
})
|
||||
|
||||
const result = await postLogin.call(this, {
|
||||
user
|
||||
})
|
||||
|
||||
return {
|
||||
errCode: result.errCode,
|
||||
newToken: result.newToken,
|
||||
uid: result.uid
|
||||
}
|
||||
}
|
93
uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/register.js
vendored
Normal file
93
uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/register.js
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
const url = require('url')
|
||||
const { preRegister, postRegister } = require('../../lib/utils/register')
|
||||
const { EXTERNAL_DIRECT_CONNECT_PROVIDER } = require('../../common/constants')
|
||||
|
||||
/**
|
||||
* 外部注册用户
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#external-register
|
||||
* @param {object} params
|
||||
* @param {string} params.externalUid 业务系统的用户id
|
||||
* @param {string} params.nickname 昵称
|
||||
* @param {number} params.gender 性别
|
||||
* @param {string} params.avatar 头像
|
||||
* @returns {object}
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
externalUid: 'string',
|
||||
nickname: {
|
||||
required: false,
|
||||
type: 'nickname'
|
||||
},
|
||||
gender: {
|
||||
required: false,
|
||||
type: 'number'
|
||||
},
|
||||
avatar: {
|
||||
required: false,
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
|
||||
this.middleware.validate(params, schema)
|
||||
|
||||
const {
|
||||
externalUid,
|
||||
avatar,
|
||||
gender,
|
||||
nickname
|
||||
} = params
|
||||
|
||||
await preRegister.call(this, {
|
||||
user: {
|
||||
identities: {
|
||||
provider: EXTERNAL_DIRECT_CONNECT_PROVIDER,
|
||||
uid: externalUid
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const extraData = {}
|
||||
|
||||
if (avatar) {
|
||||
// eslint-disable-next-line n/no-deprecated-api
|
||||
const avatarPath = url.parse(avatar).pathname
|
||||
const extName = avatarPath.indexOf('.') > -1 ? avatarPath.split('.').pop() : ''
|
||||
|
||||
extraData.avatar_file = {
|
||||
name: avatarPath,
|
||||
extname: extName,
|
||||
url: avatar
|
||||
}
|
||||
}
|
||||
|
||||
const result = await postRegister.call(this, {
|
||||
user: {
|
||||
avatar,
|
||||
gender,
|
||||
nickname,
|
||||
identities: [
|
||||
{
|
||||
provider: EXTERNAL_DIRECT_CONNECT_PROVIDER,
|
||||
userInfo: {
|
||||
avatar,
|
||||
gender,
|
||||
nickname
|
||||
},
|
||||
uid: externalUid
|
||||
}
|
||||
]
|
||||
},
|
||||
extraData
|
||||
})
|
||||
|
||||
return {
|
||||
errCode: result.errCode,
|
||||
newToken: result.newToken,
|
||||
externalUid,
|
||||
avatar,
|
||||
gender,
|
||||
nickname,
|
||||
uid: result.uid
|
||||
}
|
||||
}
|
208
uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/update-user-info.js
vendored
Normal file
208
uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/update-user-info.js
vendored
Normal file
@ -0,0 +1,208 @@
|
||||
const url = require('url')
|
||||
const { userCollection, EXTERNAL_DIRECT_CONNECT_PROVIDER } = require('../../common/constants')
|
||||
const { ERROR } = require('../../common/error')
|
||||
const { findUser } = require('../../lib/utils/account')
|
||||
const PasswordUtils = require('../../lib/utils/password')
|
||||
|
||||
/**
|
||||
* 使用 uid 或 externalUid 获取用户信息
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#external-update-userinfo
|
||||
* @param {object} params
|
||||
* @param {string} params.uid uni-id体系的用户id
|
||||
* @param {string} params.externalUid 业务系统的用户id
|
||||
* @param {string} params.nickname 昵称
|
||||
* @param {string} params.gender 性别
|
||||
* @param {string} params.avatar 头像
|
||||
* @returns {object}
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
uid: {
|
||||
required: false,
|
||||
type: 'string'
|
||||
},
|
||||
externalUid: {
|
||||
required: false,
|
||||
type: 'string'
|
||||
},
|
||||
username: {
|
||||
required: false,
|
||||
type: 'string'
|
||||
},
|
||||
password: {
|
||||
required: false,
|
||||
type: 'password'
|
||||
},
|
||||
authorizedApp: {
|
||||
required: false,
|
||||
type: 'array<string>'
|
||||
}, // 指定允许登录的app,传空数组或不传时表示可以不可以在任何端登录
|
||||
nickname: {
|
||||
required: false,
|
||||
type: 'nickname'
|
||||
},
|
||||
role: {
|
||||
require: false,
|
||||
type: 'array<string>'
|
||||
},
|
||||
mobile: {
|
||||
required: false,
|
||||
type: 'mobile'
|
||||
},
|
||||
email: {
|
||||
required: false,
|
||||
type: 'email'
|
||||
},
|
||||
tags: {
|
||||
required: false,
|
||||
type: 'array<string>'
|
||||
},
|
||||
status: {
|
||||
required: false,
|
||||
type: 'number'
|
||||
},
|
||||
gender: {
|
||||
required: false,
|
||||
type: 'number'
|
||||
},
|
||||
avatar: {
|
||||
required: false,
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
|
||||
this.middleware.validate(params, schema)
|
||||
|
||||
const {
|
||||
uid,
|
||||
externalUid,
|
||||
username,
|
||||
password,
|
||||
authorizedApp,
|
||||
nickname,
|
||||
role,
|
||||
mobile,
|
||||
email,
|
||||
tags,
|
||||
status,
|
||||
avatar,
|
||||
gender
|
||||
} = params
|
||||
|
||||
if (!uid && !externalUid) {
|
||||
throw {
|
||||
errCode: ERROR.PARAM_REQUIRED,
|
||||
errMsgValue: {
|
||||
param: 'uid or externalUid'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let query
|
||||
if (uid) {
|
||||
query = {
|
||||
_id: uid
|
||||
}
|
||||
} else {
|
||||
query = {
|
||||
identities: {
|
||||
provider: EXTERNAL_DIRECT_CONNECT_PROVIDER,
|
||||
uid: externalUid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const users = await userCollection.where(query).get()
|
||||
const user = users.data && users.data[0]
|
||||
if (!user) {
|
||||
throw {
|
||||
errCode: ERROR.ACCOUNT_NOT_EXISTS
|
||||
}
|
||||
}
|
||||
|
||||
// 更新的用户数据字段
|
||||
const data = {
|
||||
username,
|
||||
dcloud_appid: authorizedApp,
|
||||
nickname,
|
||||
role,
|
||||
mobile,
|
||||
email,
|
||||
tags,
|
||||
status,
|
||||
avatar,
|
||||
gender
|
||||
}
|
||||
|
||||
const realData = Object.keys(data).reduce((res, key) => {
|
||||
const item = data[key]
|
||||
if (item !== undefined) {
|
||||
res[key] = item
|
||||
}
|
||||
return res
|
||||
}, {})
|
||||
|
||||
// 更新用户名时验证用户名是否重新
|
||||
if (username) {
|
||||
const {
|
||||
userMatched
|
||||
} = await findUser({
|
||||
userQuery: {
|
||||
username
|
||||
},
|
||||
authorizedApp
|
||||
})
|
||||
if (userMatched.filter(user => user._id !== uid).length) {
|
||||
throw {
|
||||
errCode: ERROR.ACCOUNT_EXISTS
|
||||
}
|
||||
}
|
||||
}
|
||||
if (password) {
|
||||
const passwordUtils = new PasswordUtils({
|
||||
clientInfo: this.getUniversalClientInfo(),
|
||||
passwordSecret: this.config.passwordSecret
|
||||
})
|
||||
const {
|
||||
passwordHash,
|
||||
version
|
||||
} = passwordUtils.generatePasswordHash({
|
||||
password
|
||||
})
|
||||
|
||||
realData.password = passwordHash
|
||||
realData.password_secret_version = version
|
||||
}
|
||||
|
||||
if (avatar) {
|
||||
// eslint-disable-next-line n/no-deprecated-api
|
||||
const avatarPath = url.parse(avatar).pathname
|
||||
const extName = avatarPath.indexOf('.') > -1 ? avatarPath.split('.').pop() : ''
|
||||
|
||||
realData.avatar_file = {
|
||||
name: avatarPath,
|
||||
extname: extName,
|
||||
url: avatar
|
||||
}
|
||||
}
|
||||
|
||||
if (user.identities.length) {
|
||||
const identity = user.identities.find(item => item.provider === EXTERNAL_DIRECT_CONNECT_PROVIDER)
|
||||
|
||||
if (identity) {
|
||||
identity.userInfo = {
|
||||
avatar,
|
||||
gender,
|
||||
nickname
|
||||
}
|
||||
}
|
||||
|
||||
realData.identities = user.identities
|
||||
}
|
||||
|
||||
await userCollection.where(query).update(realData)
|
||||
|
||||
return {
|
||||
errCode: 0
|
||||
}
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
const { userCollection, REAL_NAME_STATUS, frvLogsCollection } = require('../../common/constants')
|
||||
const { dataDesensitization, catchAwait } = require('../../common/utils')
|
||||
const { encryptData, decryptData } = require('../../common/sensitive-aes-cipher')
|
||||
const { ERROR } = require('../../common/error')
|
||||
|
||||
/**
|
||||
* 查询认证结果
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-frv-auth-result
|
||||
* @param {Object} params
|
||||
* @param {String} params.certifyId 认证ID
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params) {
|
||||
const schema = {
|
||||
certifyId: 'string'
|
||||
}
|
||||
|
||||
this.middleware.validate(params, schema)
|
||||
|
||||
const { uid } = this.authInfo // 从authInfo中取出uid属性
|
||||
const { certifyId } = params // 从params中取出certifyId属性
|
||||
|
||||
const user = await userCollection.doc(uid).get() // 根据uid查询用户信息
|
||||
const userInfo = user.data && user.data[0] // 从查询结果中获取userInfo对象
|
||||
|
||||
// 如果用户不存在,抛出账户不存在的错误
|
||||
if (!userInfo) {
|
||||
throw {
|
||||
errCode: ERROR.ACCOUNT_NOT_EXISTS
|
||||
}
|
||||
}
|
||||
|
||||
const { realname_auth: realNameAuth = {} } = userInfo
|
||||
|
||||
// 如果用户已经实名认证,抛出已实名认证的错误
|
||||
if (realNameAuth.auth_status === REAL_NAME_STATUS.CERTIFIED) {
|
||||
throw {
|
||||
errCode: ERROR.REAL_NAME_VERIFIED
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化实人认证服务
|
||||
const frvManager = uniCloud.getFacialRecognitionVerifyManager({
|
||||
requestId: this.getUniCloudRequestId()
|
||||
})
|
||||
|
||||
// 调用frvManager的getAuthResult方法,获取认证结果
|
||||
const [error, res] = await catchAwait(frvManager.getAuthResult({
|
||||
certifyId
|
||||
}))
|
||||
|
||||
// 如果出现错误,抛出未知错误并打印日志
|
||||
if (error) {
|
||||
console.log(ERROR.UNKNOWN_ERROR, 'error: ', error)
|
||||
throw error
|
||||
}
|
||||
|
||||
// 如果认证状态为“PROCESSING”,抛出认证正在处理中的错误
|
||||
if (res.authState === 'PROCESSING') {
|
||||
throw {
|
||||
errCode: ERROR.FRV_PROCESSING
|
||||
}
|
||||
}
|
||||
|
||||
// 如果认证状态为“FAIL”,更新认证日志的状态并抛出认证失败的错误
|
||||
if (res.authState === 'FAIL') {
|
||||
await frvLogsCollection.where({
|
||||
certify_id: certifyId
|
||||
}).update({
|
||||
status: REAL_NAME_STATUS.CERTIFY_FAILED
|
||||
})
|
||||
|
||||
console.log(ERROR.FRV_FAIL, 'error: ', res)
|
||||
throw {
|
||||
errCode: ERROR.FRV_FAIL
|
||||
}
|
||||
}
|
||||
|
||||
// 如果认证状态不为“SUCCESS”,抛出未知错误并打印日志
|
||||
if (res.authState !== 'SUCCESS') {
|
||||
console.log(ERROR.UNKNOWN_ERROR, 'source res: ', res)
|
||||
throw {
|
||||
errCode: ERROR.UNKNOWN_ERROR
|
||||
}
|
||||
}
|
||||
|
||||
// 根据certifyId查询认证记录
|
||||
const frvLogs = await frvLogsCollection.where({
|
||||
certify_id: certifyId
|
||||
}).get()
|
||||
|
||||
const log = frvLogs.data && frvLogs.data[0]
|
||||
|
||||
const updateData = {
|
||||
realname_auth: {
|
||||
auth_status: REAL_NAME_STATUS.CERTIFIED,
|
||||
real_name: log.real_name,
|
||||
identity: log.identity,
|
||||
auth_date: Date.now(),
|
||||
type: 0
|
||||
}
|
||||
}
|
||||
|
||||
// 如果获取到了认证照片的地址,则会对其进行下载,并使用uniCloud.uploadFile方法将其上传到云存储,并将上传后的fileID保存起来。
|
||||
if (res.pictureUrl) {
|
||||
const pictureRes = await uniCloud.httpclient.request(res.pictureUrl)
|
||||
if (pictureRes.status < 400) {
|
||||
const {
|
||||
fileID
|
||||
} = await uniCloud.uploadFile({
|
||||
cloudPath: `user/id-card/${uid}.b64`,
|
||||
cloudPathAsRealPath: true,
|
||||
fileContent: Buffer.from(encryptData.call(this, pictureRes.data.toString('base64')))
|
||||
})
|
||||
updateData.realname_auth.in_hand = fileID
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all([
|
||||
// 更新用户认证状态
|
||||
userCollection.doc(uid).update(updateData),
|
||||
// 更新实人认证记录状态
|
||||
frvLogsCollection.where({
|
||||
certify_id: certifyId
|
||||
}).update({
|
||||
status: REAL_NAME_STATUS.CERTIFIED
|
||||
})
|
||||
])
|
||||
|
||||
return {
|
||||
errCode: 0,
|
||||
authStatus: REAL_NAME_STATUS.CERTIFIED,
|
||||
realName: dataDesensitization(decryptData.call(this, log.real_name), { onlyLast: true }), // 对姓名进行脱敏处理
|
||||
identity: dataDesensitization(decryptData.call(this, log.identity)) // 对身份证号进行脱敏处理
|
||||
}
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
const { userCollection, REAL_NAME_STATUS, frvLogsCollection, dbCmd } = require('../../common/constants')
|
||||
const { ERROR } = require('../../common/error')
|
||||
const { encryptData } = require('../../common/sensitive-aes-cipher')
|
||||
const { getCurrentDateTimestamp } = require('../../common/utils')
|
||||
|
||||
// const CertifyIdExpired = 25 * 60 * 1000 // certifyId 过期时间为30分钟,在25分时置为过期
|
||||
|
||||
/**
|
||||
* 获取认证ID
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-frv-certify-id
|
||||
* @param {Object} params
|
||||
* @param {String} params.realName 真实姓名
|
||||
* @param {String} params.idCard 身份证号码
|
||||
* @param {String} params.metaInfo 客户端初始化时返回的metaInfo
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params) {
|
||||
const schema = {
|
||||
realName: 'realName',
|
||||
idCard: 'idCard',
|
||||
metaInfo: 'string'
|
||||
}
|
||||
|
||||
this.middleware.validate(params, schema)
|
||||
|
||||
const { realName: originalRealName, idCard: originalIdCard, metaInfo } = params // 解构出传入参数的真实姓名、身份证号码、其他元数据
|
||||
const realName = encryptData.call(this, originalRealName) // 对真实姓名进行加密处理
|
||||
const idCard = encryptData.call(this, originalIdCard) // 对身份证号码进行加密处理
|
||||
|
||||
const { uid } = this.authInfo // 获取当前用户的 ID
|
||||
const idCardCertifyLimit = this.config.idCardCertifyLimit || 1 // 获取身份证认证限制次数,默认为1次
|
||||
const realNameCertifyLimit = this.config.realNameCertifyLimit || 5 // 获取实名认证限制次数,默认为5次
|
||||
const frvNeedAlivePhoto = this.config.frvNeedAlivePhoto || false // 是否需要拍摄活体照片,默认为 false
|
||||
|
||||
const user = await userCollection.doc(uid).get() // 获取用户信息
|
||||
const userInfo = user.data && user.data[0] // 获取用户信息对象中的实名认证信息
|
||||
const { realname_auth: realNameAuth = {} } = userInfo // 解构出实名认证信息中的认证状态对象,默认为空对象
|
||||
|
||||
// 如果用户已经实名认证过,不能再次认证
|
||||
if (realNameAuth.auth_status === REAL_NAME_STATUS.CERTIFIED) {
|
||||
throw {
|
||||
errCode: ERROR.REAL_NAME_VERIFIED
|
||||
}
|
||||
}
|
||||
|
||||
// 查询已经使用同一个身份证认证的账号数量,如果超过限制则不能认证
|
||||
const idCardAccount = await userCollection.where({
|
||||
realname_auth: {
|
||||
type: 0, // 用户认证状态是个人
|
||||
auth_status: REAL_NAME_STATUS.CERTIFIED, // 认证状态为已认证
|
||||
identity: idCard // 身份证号码和传入参数的身份证号码相同
|
||||
}
|
||||
}).get()
|
||||
if (idCardAccount.data.length >= idCardCertifyLimit) {
|
||||
throw {
|
||||
errCode: ERROR.ID_CARD_EXISTS
|
||||
}
|
||||
}
|
||||
|
||||
// 查询用户今天已经进行的实名认证次数,如果超过限制则不能认证
|
||||
const userFrvLogs = await frvLogsCollection.where({
|
||||
user_id: uid,
|
||||
created_date: dbCmd.gt(getCurrentDateTimestamp()) // 查询今天的认证记录
|
||||
}).get()
|
||||
|
||||
// 限制用户每日认证次数
|
||||
if (userFrvLogs.data && userFrvLogs.data.length >= realNameCertifyLimit) {
|
||||
throw {
|
||||
errCode: ERROR.REAL_NAME_VERIFY_UPPER_LIMIT
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化实人认证服务
|
||||
const frvManager = uniCloud.getFacialRecognitionVerifyManager({
|
||||
requestId: this.getUniCloudRequestId() // 获取当前
|
||||
})
|
||||
// 调用实人认证服务,获取认证 ID
|
||||
const res = await frvManager.getCertifyId({
|
||||
realName: originalRealName,
|
||||
idCard: originalIdCard,
|
||||
needPicture: frvNeedAlivePhoto,
|
||||
metaInfo
|
||||
})
|
||||
|
||||
// 将认证记录插入到实名认证日志中
|
||||
await frvLogsCollection.add({
|
||||
user_id: uid,
|
||||
certify_id: res.certifyId,
|
||||
real_name: realName,
|
||||
identity: idCard,
|
||||
status: REAL_NAME_STATUS.WAITING_CERTIFIED,
|
||||
created_date: Date.now()
|
||||
})
|
||||
|
||||
// 返回认证ID
|
||||
return {
|
||||
certifyId: res.certifyId
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
getFrvCertifyId: require('./get-certify-id'),
|
||||
getFrvAuthResult: require('./get-auth-result')
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
const {
|
||||
acceptInvite
|
||||
} = require('../../lib/utils/fission')
|
||||
|
||||
/**
|
||||
* 接受邀请
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#accept-invite
|
||||
* @param {Object} params
|
||||
* @param {String} params.inviteCode 邀请码
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
inviteCode: 'string'
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
const {
|
||||
inviteCode
|
||||
} = params
|
||||
const uid = this.authInfo.uid
|
||||
return acceptInvite({
|
||||
uid,
|
||||
inviteCode
|
||||
})
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
const {
|
||||
userCollection
|
||||
} = require('../../common/constants')
|
||||
const {
|
||||
coverMobile
|
||||
} = require('../../common/utils')
|
||||
|
||||
/**
|
||||
* 获取受邀用户
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-invited-user
|
||||
* @param {Object} params
|
||||
* @param {Number} params.level 获取受邀用户的级数,1表示直接邀请的用户
|
||||
* @param {Number} params.limit 返回数据大小
|
||||
* @param {Number} params.offset 返回数据偏移
|
||||
* @param {Boolean} params.needTotal 是否需要返回总数
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
level: 'number',
|
||||
limit: {
|
||||
required: false,
|
||||
type: 'number'
|
||||
},
|
||||
offset: {
|
||||
required: false,
|
||||
type: 'number'
|
||||
},
|
||||
needTotal: {
|
||||
required: false,
|
||||
type: 'boolean'
|
||||
}
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
const {
|
||||
level,
|
||||
limit = 20,
|
||||
offset = 0,
|
||||
needTotal = false
|
||||
} = params
|
||||
const uid = this.authInfo.uid
|
||||
const query = {
|
||||
[`inviter_uid.${level - 1}`]: uid
|
||||
}
|
||||
const getUserRes = await userCollection.where(query)
|
||||
.field({
|
||||
_id: true,
|
||||
avatar: true,
|
||||
avatar_file: true,
|
||||
username: true,
|
||||
nickname: true,
|
||||
mobile: true,
|
||||
invite_time: true
|
||||
})
|
||||
.orderBy('invite_time', 'desc')
|
||||
.skip(offset)
|
||||
.limit(limit)
|
||||
.get()
|
||||
|
||||
const invitedUser = getUserRes.data.map(item => {
|
||||
return {
|
||||
uid: item._id,
|
||||
username: item.username,
|
||||
nickname: item.nickname,
|
||||
mobile: coverMobile(item.mobile),
|
||||
inviteTime: item.invite_time,
|
||||
avatar: item.avatar,
|
||||
avatarFile: item.avatar_file
|
||||
}
|
||||
})
|
||||
const result = {
|
||||
errCode: 0,
|
||||
invitedUser
|
||||
}
|
||||
if (needTotal) {
|
||||
const getTotalRes = await userCollection.where(query).count()
|
||||
result.total = getTotalRes.total
|
||||
}
|
||||
return result
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
acceptInvite: require('./accept-invite'),
|
||||
getInvitedUser: require('./get-invited-user')
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
module.exports = {
|
||||
login: require('./login'),
|
||||
loginBySms: require('./login-by-sms'),
|
||||
loginByUniverify: require('./login-by-univerify'),
|
||||
loginByWeixin: require('./login-by-weixin'),
|
||||
loginByAlipay: require('./login-by-alipay'),
|
||||
loginByQQ: require('./login-by-qq'),
|
||||
loginByApple: require('./login-by-apple'),
|
||||
loginByBaidu: require('./login-by-baidu'),
|
||||
loginByDingtalk: require('./login-by-dingtalk'),
|
||||
loginByToutiao: require('./login-by-toutiao'),
|
||||
loginByDouyin: require('./login-by-douyin'),
|
||||
loginByWeibo: require('./login-by-weibo'),
|
||||
loginByTaobao: require('./login-by-taobao'),
|
||||
loginByEmailLink: require('./login-by-email-link'),
|
||||
loginByEmailCode: require('./login-by-email-code'),
|
||||
loginByFacebook: require('./login-by-facebook'),
|
||||
loginByGoogle: require('./login-by-google'),
|
||||
loginByWeixinMobile: require('./login-by-weixin-mobile')
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
const {
|
||||
initAlipay
|
||||
} = require('../../lib/third-party/index')
|
||||
const {
|
||||
ERROR
|
||||
} = require('../../common/error')
|
||||
const {
|
||||
preUnifiedLogin,
|
||||
postUnifiedLogin
|
||||
} = require('../../lib/utils/unified-login')
|
||||
const {
|
||||
LOG_TYPE
|
||||
} = require('../../common/constants')
|
||||
|
||||
/**
|
||||
* 支付宝登录
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-alipay
|
||||
* @param {Object} params
|
||||
* @param {String} params.code 支付宝小程序客户端登录返回的code
|
||||
* @param {String} params.inviteCode 邀请码
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
code: 'string',
|
||||
inviteCode: {
|
||||
type: 'string',
|
||||
required: false
|
||||
}
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
const {
|
||||
code,
|
||||
inviteCode
|
||||
} = params
|
||||
const alipayApi = initAlipay.call(this)
|
||||
let getAlipayAccountResult
|
||||
try {
|
||||
getAlipayAccountResult = await alipayApi.code2Session(code)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
await this.middleware.uniIdLog({
|
||||
success: false,
|
||||
type: LOG_TYPE.LOGIN
|
||||
})
|
||||
throw {
|
||||
errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
openid
|
||||
} = getAlipayAccountResult
|
||||
|
||||
const {
|
||||
type,
|
||||
user
|
||||
} = await preUnifiedLogin.call(this, {
|
||||
user: {
|
||||
ali_openid: openid
|
||||
}
|
||||
})
|
||||
return postUnifiedLogin.call(this, {
|
||||
user,
|
||||
extraData: {},
|
||||
isThirdParty: true,
|
||||
type,
|
||||
inviteCode
|
||||
})
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
const {
|
||||
initApple
|
||||
} = require('../../lib/third-party/index')
|
||||
const {
|
||||
ERROR
|
||||
} = require('../../common/error')
|
||||
const {
|
||||
preUnifiedLogin,
|
||||
postUnifiedLogin
|
||||
} = require('../../lib/utils/unified-login')
|
||||
const {
|
||||
LOG_TYPE
|
||||
} = require('../../common/constants')
|
||||
|
||||
/**
|
||||
* 苹果登录
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-apple
|
||||
* @param {Object} params
|
||||
* @param {String} params.identityToken 苹果登录返回的identityToken
|
||||
* @param {String} params.nickname 用户昵称
|
||||
* @param {String} params.inviteCode 邀请码
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
identityToken: 'string',
|
||||
nickname: {
|
||||
required: false,
|
||||
type: 'nickname'
|
||||
},
|
||||
inviteCode: {
|
||||
required: false,
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
const {
|
||||
identityToken,
|
||||
nickname,
|
||||
inviteCode
|
||||
} = params
|
||||
const appleApi = initApple.call(this)
|
||||
let verifyResult
|
||||
try {
|
||||
verifyResult = await appleApi.verifyIdentityToken(identityToken)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
await this.middleware.uniIdLog({
|
||||
success: false,
|
||||
type: LOG_TYPE.LOGIN
|
||||
})
|
||||
throw {
|
||||
errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED
|
||||
}
|
||||
}
|
||||
const {
|
||||
openid
|
||||
} = verifyResult
|
||||
|
||||
const {
|
||||
type,
|
||||
user
|
||||
} = await preUnifiedLogin.call(this, {
|
||||
user: {
|
||||
apple_openid: openid
|
||||
}
|
||||
})
|
||||
return postUnifiedLogin.call(this, {
|
||||
user,
|
||||
extraData: {
|
||||
nickname
|
||||
},
|
||||
isThirdParty: true,
|
||||
type,
|
||||
inviteCode
|
||||
})
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
/**
|
||||
* 百度登录
|
||||
* @param {Object} params
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
// 此接口暂未实现,欢迎向我们提交pr
|
||||
throw new Error('api[loginByBaidu] is not yet implemented')
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
/**
|
||||
* 钉钉登录
|
||||
* @param {Object} params
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
// 此接口暂未实现,欢迎向我们提交pr
|
||||
throw new Error('api[loginByDingtalk] is not yet implemented')
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
/**
|
||||
* 抖音登录
|
||||
* @param {Object} params
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
// 此接口暂未实现,欢迎向我们提交pr
|
||||
throw new Error('api[loginByDouyin] is not yet implemented')
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
/**
|
||||
* 邮箱验证码登录
|
||||
* @param {Object} params
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
// 此接口暂未实现,欢迎向我们提交pr
|
||||
throw new Error('api[loginByEmailCode] is not yet implemented')
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
/**
|
||||
* 邮箱点击链接登录
|
||||
* @param {Object} params
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
// 此接口暂未实现,欢迎向我们提交pr
|
||||
throw new Error('api[loginByEmailLink] is not yet implemented')
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Facebook登录
|
||||
* @param {Object} params
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
// 此接口暂未实现,欢迎向我们提交pr
|
||||
throw new Error('api[loginByFacebook] is not yet implemented')
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Google登录
|
||||
* @param {Object} params
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
// 此接口暂未实现,欢迎向我们提交pr
|
||||
throw new Error('api[loginByGoogle] is not yet implemented')
|
||||
}
|
@ -0,0 +1,167 @@
|
||||
const {
|
||||
initQQ
|
||||
} = require('../../lib/third-party/index')
|
||||
const {
|
||||
ERROR
|
||||
} = require('../../common/error')
|
||||
const {
|
||||
preUnifiedLogin,
|
||||
postUnifiedLogin
|
||||
} = require('../../lib/utils/unified-login')
|
||||
const {
|
||||
LOG_TYPE
|
||||
} = require('../../common/constants')
|
||||
const {
|
||||
getQQPlatform,
|
||||
generateQQCache,
|
||||
saveQQUserKey
|
||||
} = require('../../lib/utils/qq')
|
||||
const url = require('url')
|
||||
|
||||
/**
|
||||
* QQ登录
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-qq
|
||||
* @param {Object} params
|
||||
* @param {String} params.code QQ小程序登录返回的code参数
|
||||
* @param {String} params.accessToken App端QQ登录返回的accessToken参数
|
||||
* @param {String} params.accessTokenExpired accessToken过期时间,由App端QQ登录返回的expires_in参数计算而来,单位:毫秒
|
||||
* @param {String} params.inviteCode 邀请码
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
code: {
|
||||
type: 'string',
|
||||
required: false
|
||||
},
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: false
|
||||
},
|
||||
accessTokenExpired: {
|
||||
type: 'number',
|
||||
required: false
|
||||
},
|
||||
inviteCode: {
|
||||
type: 'string',
|
||||
required: false
|
||||
}
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
const {
|
||||
code,
|
||||
accessToken,
|
||||
accessTokenExpired,
|
||||
inviteCode
|
||||
} = params
|
||||
const {
|
||||
appId
|
||||
} = this.getUniversalClientInfo()
|
||||
const qqApi = initQQ.call(this)
|
||||
const qqPlatform = getQQPlatform.call(this)
|
||||
let apiName
|
||||
switch (qqPlatform) {
|
||||
case 'mp':
|
||||
apiName = 'code2Session'
|
||||
break
|
||||
case 'app':
|
||||
apiName = 'getOpenidByToken'
|
||||
break
|
||||
default:
|
||||
throw new Error('Unsupported qq platform')
|
||||
}
|
||||
let getQQAccountResult
|
||||
try {
|
||||
getQQAccountResult = await qqApi[apiName]({
|
||||
code,
|
||||
accessToken
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
await this.middleware.uniIdLog({
|
||||
success: false,
|
||||
type: LOG_TYPE.LOGIN
|
||||
})
|
||||
throw {
|
||||
errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
openid,
|
||||
unionid,
|
||||
// 保存下面的字段
|
||||
sessionKey // QQ小程序用户sessionKey
|
||||
} = getQQAccountResult
|
||||
|
||||
const {
|
||||
type,
|
||||
user
|
||||
} = await preUnifiedLogin.call(this, {
|
||||
user: {
|
||||
qq_openid: {
|
||||
[qqPlatform]: openid
|
||||
},
|
||||
qq_unionid: unionid
|
||||
}
|
||||
})
|
||||
const extraData = {
|
||||
qq_openid: {
|
||||
[`${qqPlatform}_${appId}`]: openid
|
||||
},
|
||||
qq_unionid: unionid
|
||||
}
|
||||
if (type === 'register' && qqPlatform !== 'mp') {
|
||||
const {
|
||||
nickname,
|
||||
avatar
|
||||
} = await qqApi.getUserInfo({
|
||||
accessToken,
|
||||
openid
|
||||
})
|
||||
if (avatar) {
|
||||
// eslint-disable-next-line n/no-deprecated-api
|
||||
const extName = url.parse(avatar).pathname.split('.').pop()
|
||||
const cloudPath = `user/avatar/${openid.slice(-8) + Date.now()}-avatar.${extName}`
|
||||
const getAvatarRes = await uniCloud.httpclient.request(avatar)
|
||||
if (getAvatarRes.status >= 400) {
|
||||
throw {
|
||||
errCode: ERROR.GET_THIRD_PARTY_USER_INFO_FAILED
|
||||
}
|
||||
}
|
||||
const {
|
||||
fileID
|
||||
} = await uniCloud.uploadFile({
|
||||
cloudPath,
|
||||
fileContent: getAvatarRes.data
|
||||
})
|
||||
extraData.avatar_file = {
|
||||
name: cloudPath,
|
||||
extname: extName,
|
||||
url: fileID
|
||||
}
|
||||
}
|
||||
extraData.nickname = nickname
|
||||
}
|
||||
await saveQQUserKey.call(this, {
|
||||
openid,
|
||||
sessionKey,
|
||||
accessToken,
|
||||
accessTokenExpired
|
||||
})
|
||||
return postUnifiedLogin.call(this, {
|
||||
user,
|
||||
extraData: {
|
||||
...extraData,
|
||||
...generateQQCache.call(this, {
|
||||
openid,
|
||||
sessionKey, // QQ小程序用户sessionKey
|
||||
accessToken, // App端QQ用户accessToken
|
||||
accessTokenExpired // App端QQ用户accessToken过期时间
|
||||
})
|
||||
},
|
||||
isThirdParty: true,
|
||||
type,
|
||||
inviteCode
|
||||
})
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
const {
|
||||
getNeedCaptcha,
|
||||
verifyCaptcha
|
||||
} = require('../../lib/utils/captcha')
|
||||
const {
|
||||
verifyMobileCode
|
||||
} = require('../../lib/utils/verify-code')
|
||||
const {
|
||||
preUnifiedLogin,
|
||||
postUnifiedLogin
|
||||
} = require('../../lib/utils/unified-login')
|
||||
const {
|
||||
CAPTCHA_SCENE,
|
||||
SMS_SCENE,
|
||||
LOG_TYPE
|
||||
} = require('../../common/constants')
|
||||
|
||||
/**
|
||||
* 短信验证码登录
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-sms
|
||||
* @param {Object} params
|
||||
* @param {String} params.mobile 手机号
|
||||
* @param {String} params.code 短信验证码
|
||||
* @param {String} params.captcha 图形验证码
|
||||
* @param {String} params.inviteCode 邀请码
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
mobile: 'mobile',
|
||||
code: 'string',
|
||||
captcha: {
|
||||
required: false,
|
||||
type: 'string'
|
||||
},
|
||||
inviteCode: {
|
||||
required: false,
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
const {
|
||||
mobile,
|
||||
code,
|
||||
captcha,
|
||||
inviteCode
|
||||
} = params
|
||||
|
||||
const needCaptcha = await getNeedCaptcha.call(this, {
|
||||
mobile
|
||||
})
|
||||
|
||||
if (needCaptcha) {
|
||||
await verifyCaptcha.call(this, {
|
||||
captcha,
|
||||
scene: CAPTCHA_SCENE.LOGIN_BY_SMS
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
await verifyMobileCode({
|
||||
mobile,
|
||||
code,
|
||||
scene: SMS_SCENE.LOGIN_BY_SMS
|
||||
})
|
||||
} catch (error) {
|
||||
console.log(error, {
|
||||
mobile,
|
||||
code,
|
||||
type: SMS_SCENE.LOGIN_BY_SMS
|
||||
})
|
||||
await this.middleware.uniIdLog({
|
||||
success: false,
|
||||
data: {
|
||||
mobile
|
||||
},
|
||||
type: LOG_TYPE.LOGIN
|
||||
})
|
||||
throw error
|
||||
}
|
||||
|
||||
const {
|
||||
type,
|
||||
user
|
||||
} = await preUnifiedLogin.call(this, {
|
||||
user: {
|
||||
mobile
|
||||
}
|
||||
})
|
||||
return postUnifiedLogin.call(this, {
|
||||
user,
|
||||
extraData: {
|
||||
mobile_confirmed: 1
|
||||
},
|
||||
isThirdParty: false,
|
||||
type,
|
||||
inviteCode
|
||||
})
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
/**
|
||||
* 淘宝登录
|
||||
* @param {Object} params
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
// 此接口暂未实现,欢迎向我们提交pr
|
||||
throw new Error('api[loginByTaobao] is not yet implemented')
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
/**
|
||||
* 头条登录
|
||||
* @param {Object} params
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
// 此接口暂未实现,欢迎向我们提交pr
|
||||
throw new Error('api[loginByToutiao] is not yet implemented')
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
const {
|
||||
getPhoneNumber
|
||||
} = require('../../lib/utils/univerify')
|
||||
const {
|
||||
preUnifiedLogin,
|
||||
postUnifiedLogin
|
||||
} = require('../../lib/utils/unified-login')
|
||||
const {
|
||||
LOG_TYPE
|
||||
} = require('../../common/constants')
|
||||
|
||||
/**
|
||||
* App端一键登录
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-univerify
|
||||
* @param {Object} params
|
||||
* @param {String} params.access_token APP端一键登录返回的access_token
|
||||
* @param {String} params.openid APP端一键登录返回的openid
|
||||
* @param {String} params.inviteCode 邀请码
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
access_token: 'string',
|
||||
openid: 'string',
|
||||
inviteCode: {
|
||||
required: false,
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
const {
|
||||
// eslint-disable-next-line camelcase
|
||||
access_token,
|
||||
openid,
|
||||
inviteCode
|
||||
} = params
|
||||
|
||||
let mobile
|
||||
try {
|
||||
const phoneInfo = await getPhoneNumber.call(this, {
|
||||
// eslint-disable-next-line camelcase
|
||||
access_token,
|
||||
openid
|
||||
})
|
||||
mobile = phoneInfo.phoneNumber
|
||||
} catch (error) {
|
||||
await this.middleware.uniIdLog({
|
||||
success: false,
|
||||
type: LOG_TYPE.LOGIN
|
||||
})
|
||||
throw error
|
||||
}
|
||||
const {
|
||||
user,
|
||||
type
|
||||
} = await preUnifiedLogin.call(this, {
|
||||
user: {
|
||||
mobile
|
||||
}
|
||||
})
|
||||
return postUnifiedLogin.call(this, {
|
||||
user,
|
||||
extraData: {
|
||||
mobile_confirmed: 1
|
||||
},
|
||||
type,
|
||||
inviteCode
|
||||
})
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
/**
|
||||
* 微博登录
|
||||
* @param {Object} params
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
// 此接口暂未实现,欢迎向我们提交pr
|
||||
throw new Error('api[loginByWeibo] is not yet implemented')
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
const {
|
||||
initWeixin
|
||||
} = require('../../lib/third-party/index')
|
||||
const {
|
||||
getWeixinAccessToken
|
||||
} = require('../../lib/utils/weixin')
|
||||
const {
|
||||
ERROR
|
||||
} = require('../../common/error')
|
||||
const {
|
||||
preUnifiedLogin,
|
||||
postUnifiedLogin
|
||||
} = require('../../lib/utils/unified-login')
|
||||
const {
|
||||
LOG_TYPE
|
||||
} = require('../../common/constants')
|
||||
const {
|
||||
preBind,
|
||||
postBind
|
||||
} = require('../../lib/utils/relate')
|
||||
|
||||
/**
|
||||
* 微信授权手机号登录
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-weixin-mobile
|
||||
* @param {Object} params
|
||||
* @param {String} params.phoneCode 微信手机号返回的code
|
||||
* @param {String} params.inviteCode 邀请码
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
phoneCode: 'string',
|
||||
inviteCode: {
|
||||
type: 'string',
|
||||
required: false
|
||||
}
|
||||
}
|
||||
|
||||
this.middleware.validate(params, schema)
|
||||
|
||||
const { phoneCode, inviteCode } = params
|
||||
|
||||
const weixinApi = initWeixin.call(this)
|
||||
let mobile
|
||||
|
||||
try {
|
||||
const accessToken = await getWeixinAccessToken.call(this)
|
||||
const mobileRes = await weixinApi.getPhoneNumber(accessToken, phoneCode)
|
||||
mobile = mobileRes.purePhoneNumber
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
await this.middleware.uniIdLog({
|
||||
success: false,
|
||||
type: LOG_TYPE.LOGIN
|
||||
})
|
||||
throw {
|
||||
errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED
|
||||
}
|
||||
}
|
||||
|
||||
const { type, user } = await preUnifiedLogin.call(this, {
|
||||
user: {
|
||||
mobile
|
||||
}
|
||||
})
|
||||
|
||||
let extraData = {
|
||||
mobile_confirmed: 1
|
||||
}
|
||||
|
||||
if (type === 'login') {
|
||||
// 绑定手机号
|
||||
if (!user.mobile_confirmed) {
|
||||
const bindAccount = {
|
||||
mobile
|
||||
}
|
||||
await preBind.call(this, {
|
||||
uid: user._id,
|
||||
bindAccount,
|
||||
logType: LOG_TYPE.BIND_MOBILE
|
||||
})
|
||||
await postBind.call(this, {
|
||||
uid: user._id,
|
||||
bindAccount,
|
||||
extraData: {
|
||||
mobile_confirmed: 1
|
||||
},
|
||||
logType: LOG_TYPE.BIND_MOBILE
|
||||
})
|
||||
extraData = {
|
||||
...extraData,
|
||||
...bindAccount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return postUnifiedLogin.call(this, {
|
||||
user,
|
||||
extraData: {
|
||||
...extraData
|
||||
},
|
||||
isThirdParty: false,
|
||||
type,
|
||||
inviteCode
|
||||
})
|
||||
}
|
@ -0,0 +1,176 @@
|
||||
const {
|
||||
initWeixin
|
||||
} = require('../../lib/third-party/index')
|
||||
const {
|
||||
ERROR
|
||||
} = require('../../common/error')
|
||||
const {
|
||||
preUnifiedLogin,
|
||||
postUnifiedLogin
|
||||
} = require('../../lib/utils/unified-login')
|
||||
const {
|
||||
generateWeixinCache,
|
||||
getWeixinPlatform,
|
||||
saveWeixinUserKey,
|
||||
saveSecureNetworkCache
|
||||
} = require('../../lib/utils/weixin')
|
||||
const {
|
||||
LOG_TYPE
|
||||
} = require('../../common/constants')
|
||||
const url = require('url')
|
||||
|
||||
/**
|
||||
* 微信登录
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-weixin
|
||||
* @param {Object} params
|
||||
* @param {String} params.code 微信登录返回的code
|
||||
* @param {String} params.inviteCode 邀请码
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
code: 'string',
|
||||
inviteCode: {
|
||||
type: 'string',
|
||||
required: false
|
||||
}
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
const {
|
||||
code,
|
||||
inviteCode,
|
||||
// 内部参数,暂不暴露
|
||||
secureNetworkCache = false
|
||||
} = params
|
||||
const {
|
||||
appId
|
||||
} = this.getUniversalClientInfo()
|
||||
const weixinApi = initWeixin.call(this)
|
||||
const weixinPlatform = getWeixinPlatform.call(this)
|
||||
let apiName
|
||||
switch (weixinPlatform) {
|
||||
case 'mp':
|
||||
apiName = 'code2Session'
|
||||
break
|
||||
case 'app':
|
||||
case 'h5':
|
||||
case 'web':
|
||||
apiName = 'getOauthAccessToken'
|
||||
break
|
||||
default:
|
||||
throw new Error('Unsupported weixin platform')
|
||||
}
|
||||
let getWeixinAccountResult
|
||||
try {
|
||||
getWeixinAccountResult = await weixinApi[apiName](code)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
await this.middleware.uniIdLog({
|
||||
success: false,
|
||||
type: LOG_TYPE.LOGIN
|
||||
})
|
||||
throw {
|
||||
errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
openid,
|
||||
unionid,
|
||||
// 保存下面四个字段
|
||||
sessionKey, // 微信小程序用户sessionKey
|
||||
accessToken, // App端微信用户accessToken
|
||||
refreshToken, // App端微信用户refreshToken
|
||||
expired: accessTokenExpired // App端微信用户accessToken过期时间
|
||||
} = getWeixinAccountResult
|
||||
|
||||
if (secureNetworkCache) {
|
||||
if (weixinPlatform !== 'mp') {
|
||||
throw new Error('Unsupported weixin platform, expect mp-weixin')
|
||||
}
|
||||
await saveSecureNetworkCache.call(this, {
|
||||
code,
|
||||
openid,
|
||||
unionid,
|
||||
sessionKey
|
||||
})
|
||||
}
|
||||
|
||||
const {
|
||||
type,
|
||||
user
|
||||
} = await preUnifiedLogin.call(this, {
|
||||
user: {
|
||||
wx_openid: {
|
||||
[weixinPlatform]: openid
|
||||
},
|
||||
wx_unionid: unionid
|
||||
}
|
||||
})
|
||||
const extraData = {
|
||||
wx_openid: {
|
||||
[`${weixinPlatform}_${appId}`]: openid
|
||||
},
|
||||
wx_unionid: unionid
|
||||
}
|
||||
if (type === 'register' && weixinPlatform !== 'mp') {
|
||||
const {
|
||||
nickname,
|
||||
avatar
|
||||
} = await weixinApi.getUserInfo({
|
||||
accessToken,
|
||||
openid
|
||||
})
|
||||
|
||||
if (avatar) {
|
||||
// eslint-disable-next-line n/no-deprecated-api
|
||||
const avatarPath = url.parse(avatar).pathname
|
||||
const extName = avatarPath.indexOf('.') > -1 ? url.parse(avatar).pathname.split('.').pop() : 'jpg'
|
||||
const cloudPath = `user/avatar/${openid.slice(-8) + Date.now()}-avatar.${extName}`
|
||||
const getAvatarRes = await uniCloud.httpclient.request(avatar)
|
||||
if (getAvatarRes.status >= 400) {
|
||||
throw {
|
||||
errCode: ERROR.GET_THIRD_PARTY_USER_INFO_FAILED
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
fileID
|
||||
} = await uniCloud.uploadFile({
|
||||
cloudPath,
|
||||
fileContent: getAvatarRes.data
|
||||
})
|
||||
|
||||
extraData.avatar_file = {
|
||||
name: cloudPath,
|
||||
extname: extName,
|
||||
url: fileID
|
||||
}
|
||||
}
|
||||
|
||||
extraData.nickname = nickname
|
||||
}
|
||||
await saveWeixinUserKey.call(this, {
|
||||
openid,
|
||||
sessionKey,
|
||||
accessToken,
|
||||
refreshToken,
|
||||
accessTokenExpired
|
||||
})
|
||||
return postUnifiedLogin.call(this, {
|
||||
user,
|
||||
extraData: {
|
||||
...extraData,
|
||||
...generateWeixinCache.call(this, {
|
||||
openid,
|
||||
sessionKey, // 微信小程序用户sessionKey
|
||||
accessToken, // App端微信用户accessToken
|
||||
refreshToken, // App端微信用户refreshToken
|
||||
accessTokenExpired // App端微信用户accessToken过期时间
|
||||
})
|
||||
},
|
||||
isThirdParty: true,
|
||||
type,
|
||||
inviteCode
|
||||
})
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
const {
|
||||
preLoginWithPassword,
|
||||
postLogin
|
||||
} = require('../../lib/utils/login')
|
||||
const {
|
||||
getNeedCaptcha,
|
||||
verifyCaptcha
|
||||
} = require('../../lib/utils/captcha')
|
||||
const {
|
||||
CAPTCHA_SCENE
|
||||
} = require('../../common/constants')
|
||||
const {
|
||||
ERROR
|
||||
} = require('../../common/error')
|
||||
|
||||
/**
|
||||
* 用户名密码登录
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login
|
||||
* @param {Object} params
|
||||
* @param {String} params.username 用户名
|
||||
* @param {String} params.mobile 手机号
|
||||
* @param {String} params.email 邮箱
|
||||
* @param {String} params.password 密码
|
||||
* @param {String} params.captcha 图形验证码
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
username: {
|
||||
required: false,
|
||||
type: 'username'
|
||||
},
|
||||
mobile: {
|
||||
required: false,
|
||||
type: 'mobile'
|
||||
},
|
||||
email: {
|
||||
required: false,
|
||||
type: 'email'
|
||||
},
|
||||
password: 'password',
|
||||
captcha: {
|
||||
required: false,
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
const {
|
||||
username,
|
||||
mobile,
|
||||
email,
|
||||
password,
|
||||
captcha
|
||||
} = params
|
||||
if (!username && !mobile && !email) {
|
||||
throw {
|
||||
errCode: ERROR.INVALID_USERNAME
|
||||
}
|
||||
} else if (
|
||||
(username && email) ||
|
||||
(username && mobile) ||
|
||||
(email && mobile)
|
||||
) {
|
||||
throw {
|
||||
errCode: ERROR.INVALID_PARAM
|
||||
}
|
||||
}
|
||||
const needCaptcha = await getNeedCaptcha.call(this, {
|
||||
username,
|
||||
mobile,
|
||||
email
|
||||
})
|
||||
if (needCaptcha) {
|
||||
await verifyCaptcha.call(this, {
|
||||
captcha,
|
||||
scene: CAPTCHA_SCENE.LOGIN_BY_PWD
|
||||
})
|
||||
}
|
||||
const {
|
||||
user,
|
||||
extraData
|
||||
} = await preLoginWithPassword.call(this, {
|
||||
user: {
|
||||
username,
|
||||
mobile,
|
||||
email
|
||||
},
|
||||
password
|
||||
})
|
||||
return postLogin.call(this, {
|
||||
user,
|
||||
extraData
|
||||
})
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
logout: require('./logout')
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
const {
|
||||
logout
|
||||
} = require('../../lib/utils/logout')
|
||||
|
||||
/**
|
||||
* 用户退出登录
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#logout
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function () {
|
||||
await logout.call(this)
|
||||
return {
|
||||
errCode: 0
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
const {
|
||||
isAuthorizeApproved
|
||||
} = require('./utils')
|
||||
const {
|
||||
dbCmd,
|
||||
userCollection
|
||||
} = require('../../common/constants')
|
||||
|
||||
/**
|
||||
* 授权用户登录应用
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#authorize-app-login
|
||||
* @param {Object} params
|
||||
* @param {String} params.uid 用户id
|
||||
* @param {String} params.appId 授权的应用的AppId
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
uid: 'string',
|
||||
appId: 'string'
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
const {
|
||||
uid,
|
||||
appId
|
||||
} = params
|
||||
await isAuthorizeApproved({
|
||||
uid,
|
||||
appIdList: [appId]
|
||||
})
|
||||
await userCollection.doc(uid).update({
|
||||
dcloud_appid: dbCmd.push(appId)
|
||||
})
|
||||
return {
|
||||
errCode: 0
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
authorizeAppLogin: require('./authorize-app-login'),
|
||||
removeAuthorizedApp: require('./remove-authorized-app'),
|
||||
setAuthorizedApp: require('./set-authorized-app')
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
const {
|
||||
dbCmd,
|
||||
userCollection
|
||||
} = require('../../common/constants')
|
||||
|
||||
/**
|
||||
* 移除用户登录授权
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#remove-authorized-app
|
||||
* @param {Object} params
|
||||
* @param {String} params.uid 用户id
|
||||
* @param {String} params.appId 取消授权的应用的AppId
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
uid: 'string',
|
||||
appId: 'string'
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
const {
|
||||
uid,
|
||||
appId
|
||||
} = params
|
||||
await userCollection.doc(uid).update({
|
||||
dcloud_appid: dbCmd.pull(appId)
|
||||
})
|
||||
return {
|
||||
errCode: 0
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
const {
|
||||
isAuthorizeApproved
|
||||
} = require('./utils')
|
||||
const {
|
||||
userCollection
|
||||
} = require('../../common/constants')
|
||||
|
||||
/**
|
||||
* 设置用户允许登录的应用列表
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#set-authorized-app
|
||||
* @param {Object} params
|
||||
* @param {String} params.uid 用户id
|
||||
* @param {Array} params.appIdList 允许登录的应用AppId列表
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
uid: 'string',
|
||||
appIdList: 'array<string>'
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
const {
|
||||
uid,
|
||||
appIdList
|
||||
} = params
|
||||
await isAuthorizeApproved({
|
||||
uid,
|
||||
appIdList
|
||||
})
|
||||
await userCollection.doc(uid).update({
|
||||
dcloud_appid: appIdList
|
||||
})
|
||||
return {
|
||||
errCode: 0
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
const {
|
||||
userCollection
|
||||
} = require('../../common/constants')
|
||||
const {
|
||||
ERROR
|
||||
} = require('../../common/error')
|
||||
const {
|
||||
findUser
|
||||
} = require('../../lib/utils/account')
|
||||
|
||||
async function isAuthorizeApproved ({
|
||||
uid,
|
||||
appIdList
|
||||
} = {}) {
|
||||
const getUserRes = await userCollection.doc(uid).get()
|
||||
const userRecord = getUserRes.data[0]
|
||||
if (!userRecord) {
|
||||
throw {
|
||||
errCode: ERROR.ACCOUNT_NOT_EXISTS
|
||||
}
|
||||
}
|
||||
const {
|
||||
userMatched
|
||||
} = await findUser({
|
||||
userQuery: userRecord,
|
||||
authorizedApp: appIdList
|
||||
})
|
||||
|
||||
if (userMatched.some(item => item._id !== uid)) {
|
||||
throw {
|
||||
errCode: ERROR.ACCOUNT_CONFLICT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
isAuthorizeApproved
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
registerUser: require('./register-user'),
|
||||
registerAdmin: require('./register-admin'),
|
||||
registerUserByEmail: require('./register-user-by-email')
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
const {
|
||||
userCollection
|
||||
} = require('../../common/constants')
|
||||
const {
|
||||
ERROR
|
||||
} = require('../../common/error')
|
||||
const {
|
||||
preRegisterWithPassword,
|
||||
postRegister
|
||||
} = require('../../lib/utils/register')
|
||||
|
||||
/**
|
||||
* 注册管理员
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#register-admin
|
||||
* @param {Object} params
|
||||
* @param {String} params.username 用户名
|
||||
* @param {String} params.password 密码
|
||||
* @param {String} params.nickname 昵称
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
username: 'username',
|
||||
password: 'password',
|
||||
nickname: {
|
||||
type: 'nickname',
|
||||
required: false
|
||||
}
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
const {
|
||||
username,
|
||||
password,
|
||||
nickname
|
||||
} = params
|
||||
const getAdminRes = await userCollection.where({
|
||||
role: 'admin'
|
||||
}).limit(1).get()
|
||||
if (getAdminRes.data.length > 0) {
|
||||
const [admin] = getAdminRes.data
|
||||
const appId = this.getUniversalClientInfo().appId
|
||||
|
||||
if (!admin.dcloud_appid || (admin.dcloud_appid && admin.dcloud_appid.includes(appId))) {
|
||||
return {
|
||||
errCode: ERROR.ADMIN_EXISTS,
|
||||
errMsg: this.t('uni-id-admin-exists')
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
errCode: ERROR.ADMIN_EXISTS,
|
||||
errMsg: this.t('uni-id-admin-exist-in-other-apps')
|
||||
}
|
||||
}
|
||||
}
|
||||
const {
|
||||
user,
|
||||
extraData
|
||||
} = await preRegisterWithPassword.call(this, {
|
||||
user: {
|
||||
username
|
||||
},
|
||||
password
|
||||
})
|
||||
return postRegister.call(this, {
|
||||
user,
|
||||
extraData: {
|
||||
...extraData,
|
||||
nickname,
|
||||
role: ['admin']
|
||||
}
|
||||
})
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
const {
|
||||
postRegister,
|
||||
preRegisterWithPassword
|
||||
} = require('../../lib/utils/register')
|
||||
const {
|
||||
verifyCaptcha
|
||||
} = require('../../lib/utils/captcha')
|
||||
const {
|
||||
CAPTCHA_SCENE,
|
||||
EMAIL_SCENE,
|
||||
LOG_TYPE
|
||||
} = require('../../common/constants')
|
||||
const {
|
||||
verifyEmailCode
|
||||
} = require('../../lib/utils/verify-code')
|
||||
|
||||
/**
|
||||
* 通过邮箱+验证码注册普通用户
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#register-user-by-email
|
||||
* @param {Object} params
|
||||
* @param {String} params.email 邮箱
|
||||
* @param {String} params.password 密码
|
||||
* @param {String} params.nickname 昵称
|
||||
* @param {String} params.code 邮箱验证码
|
||||
* @param {String} params.inviteCode 邀请码
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
email: 'email',
|
||||
password: 'password',
|
||||
nickname: {
|
||||
required: false,
|
||||
type: 'nickname'
|
||||
},
|
||||
code: 'string',
|
||||
inviteCode: {
|
||||
required: false,
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
const {
|
||||
email,
|
||||
password,
|
||||
nickname,
|
||||
code,
|
||||
inviteCode
|
||||
} = params
|
||||
|
||||
try {
|
||||
// 验证邮箱验证码,验证不通过时写入失败日志
|
||||
await verifyEmailCode({
|
||||
email,
|
||||
code,
|
||||
scene: EMAIL_SCENE.REGISTER
|
||||
})
|
||||
} catch (error) {
|
||||
await this.middleware.uniIdLog({
|
||||
data: {
|
||||
email
|
||||
},
|
||||
type: LOG_TYPE.REGISTER,
|
||||
success: false
|
||||
})
|
||||
throw error
|
||||
}
|
||||
|
||||
const {
|
||||
user,
|
||||
extraData
|
||||
} = await preRegisterWithPassword.call(this, {
|
||||
user: {
|
||||
email
|
||||
},
|
||||
password
|
||||
})
|
||||
return postRegister.call(this, {
|
||||
user,
|
||||
extraData: {
|
||||
...extraData,
|
||||
nickname,
|
||||
email_confirmed: 1
|
||||
},
|
||||
inviteCode
|
||||
})
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
const {
|
||||
postRegister,
|
||||
preRegisterWithPassword
|
||||
} = require('../../lib/utils/register')
|
||||
const {
|
||||
verifyCaptcha
|
||||
} = require('../../lib/utils/captcha')
|
||||
const {
|
||||
CAPTCHA_SCENE
|
||||
} = require('../../common/constants')
|
||||
|
||||
/**
|
||||
* 注册普通用户
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#register-user
|
||||
* @param {Object} params
|
||||
* @param {String} params.username 用户名
|
||||
* @param {String} params.password 密码
|
||||
* @param {String} params.captcha 图形验证码
|
||||
* @param {String} params.nickname 昵称
|
||||
* @param {String} params.inviteCode 邀请码
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
username: 'username',
|
||||
password: 'password',
|
||||
captcha: 'string',
|
||||
nickname: {
|
||||
required: false,
|
||||
type: 'nickname'
|
||||
},
|
||||
inviteCode: {
|
||||
required: false,
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
const {
|
||||
username,
|
||||
password,
|
||||
nickname,
|
||||
captcha,
|
||||
inviteCode
|
||||
} = params
|
||||
|
||||
await verifyCaptcha.call(this, {
|
||||
captcha,
|
||||
scene: CAPTCHA_SCENE.REGISTER
|
||||
})
|
||||
|
||||
const {
|
||||
user,
|
||||
extraData
|
||||
} = await preRegisterWithPassword.call(this, {
|
||||
user: {
|
||||
username
|
||||
},
|
||||
password
|
||||
})
|
||||
return postRegister.call(this, {
|
||||
user,
|
||||
extraData: {
|
||||
...extraData,
|
||||
nickname
|
||||
},
|
||||
inviteCode
|
||||
})
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
const {
|
||||
preBind,
|
||||
postBind
|
||||
} = require('../../lib/utils/relate')
|
||||
const {
|
||||
LOG_TYPE
|
||||
} = require('../../common/constants')
|
||||
const {
|
||||
ERROR
|
||||
} = require('../../common/error')
|
||||
const {
|
||||
initAlipay
|
||||
} = require('../../lib/third-party/index')
|
||||
|
||||
/**
|
||||
* 绑定支付宝账号
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-alipay
|
||||
* @param {Object} params
|
||||
* @param {String} params.code 支付宝小程序登录返回的code参数
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
code: 'string'
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
const uid = this.authInfo.uid
|
||||
const {
|
||||
code
|
||||
} = params
|
||||
const alipayApi = initAlipay.call(this)
|
||||
let getAlipayAccountResult
|
||||
try {
|
||||
getAlipayAccountResult = await alipayApi().code2Session(code)
|
||||
} catch (error) {
|
||||
await this.middleware.uniIdLog({
|
||||
success: false,
|
||||
type: LOG_TYPE.BIND_ALIPAY
|
||||
})
|
||||
throw {
|
||||
errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
openid
|
||||
} = getAlipayAccountResult
|
||||
|
||||
const bindAccount = {
|
||||
ali_openid: openid
|
||||
}
|
||||
await preBind.call(this, {
|
||||
uid,
|
||||
bindAccount,
|
||||
logType: LOG_TYPE.BIND_APPLE
|
||||
})
|
||||
return postBind.call(this, {
|
||||
uid,
|
||||
bindAccount,
|
||||
extraData: {},
|
||||
logType: LOG_TYPE.BIND_APPLE
|
||||
})
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
const {
|
||||
preBind,
|
||||
postBind
|
||||
} = require('../../lib/utils/relate')
|
||||
const {
|
||||
LOG_TYPE
|
||||
} = require('../../common/constants')
|
||||
const {
|
||||
ERROR
|
||||
} = require('../../common/error')
|
||||
const {
|
||||
initApple
|
||||
} = require('../../lib/third-party/index')
|
||||
|
||||
/**
|
||||
* 绑定苹果账号
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-apple
|
||||
* @param {Object} params
|
||||
* @param {String} params.identityToken 苹果登录返回identityToken
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
identityToken: 'string'
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
const uid = this.authInfo.uid
|
||||
const {
|
||||
identityToken
|
||||
} = params
|
||||
const appleApi = initApple.call(this)
|
||||
let verifyResult
|
||||
try {
|
||||
verifyResult = await appleApi.verifyIdentityToken(identityToken)
|
||||
} catch (error) {
|
||||
await this.middleware.uniIdLog({
|
||||
success: false,
|
||||
type: LOG_TYPE.BIND_APPLE
|
||||
})
|
||||
throw {
|
||||
errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED
|
||||
}
|
||||
}
|
||||
const {
|
||||
openid
|
||||
} = verifyResult
|
||||
|
||||
const bindAccount = {
|
||||
apple_openid: openid
|
||||
}
|
||||
await preBind.call(this, {
|
||||
uid,
|
||||
bindAccount,
|
||||
logType: LOG_TYPE.BIND_APPLE
|
||||
})
|
||||
return postBind.call(this, {
|
||||
uid,
|
||||
bindAccount,
|
||||
extraData: {},
|
||||
logType: LOG_TYPE.BIND_APPLE
|
||||
})
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
const {
|
||||
preBind,
|
||||
postBind
|
||||
} = require('../../lib/utils/relate')
|
||||
const {
|
||||
LOG_TYPE
|
||||
} = require('../../common/constants')
|
||||
const {
|
||||
decryptWeixinData,
|
||||
getWeixinCache, getWeixinAccessToken
|
||||
} = require('../../lib/utils/weixin')
|
||||
const { initWeixin } = require('../../lib/third-party')
|
||||
const { ERROR } = require('../../common/error')
|
||||
|
||||
/**
|
||||
* 通过微信绑定手机号
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-mobile-by-mp-weixin
|
||||
* @param {Object} params
|
||||
* @param {String} params.encryptedData 微信获取手机号返回的加密信息
|
||||
* @param {String} params.iv 微信获取手机号返回的初始向量
|
||||
* @param {String} params.code 微信获取手机号返回的code
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
/**
|
||||
* 微信小程序的规则是客户端应先使用checkSession接口检测上次获取的sessionKey是否仍有效
|
||||
* 如果有效则直接使用上次存储的sessionKey即可
|
||||
* 如果无效应重新调用login接口再次刷新sessionKey
|
||||
* 因此此接口不应直接使用客户端login获取的code,只能使用缓存的sessionKey
|
||||
*/
|
||||
const schema = {
|
||||
encryptedData: {
|
||||
required: false,
|
||||
type: 'string'
|
||||
},
|
||||
iv: {
|
||||
required: false,
|
||||
type: 'string'
|
||||
},
|
||||
code: {
|
||||
required: false,
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
const {
|
||||
encryptedData,
|
||||
iv,
|
||||
code
|
||||
} = params
|
||||
this.middleware.validate(params, schema)
|
||||
|
||||
if ((!encryptedData && !iv) && !code) {
|
||||
return {
|
||||
errCode: ERROR.INVALID_PARAM
|
||||
}
|
||||
}
|
||||
|
||||
const uid = this.authInfo.uid
|
||||
|
||||
let mobile
|
||||
if (code) {
|
||||
// 区分客户端类型 小程序还是App
|
||||
const accessToken = await getWeixinAccessToken.call(this)
|
||||
const weixinApi = initWeixin.call(this)
|
||||
const res = await weixinApi.getPhoneNumber(accessToken, code)
|
||||
|
||||
mobile = res.purePhoneNumber
|
||||
} else {
|
||||
const sessionKey = await getWeixinCache.call(this, {
|
||||
uid,
|
||||
key: 'session_key'
|
||||
})
|
||||
if (!sessionKey) {
|
||||
throw new Error('Session key not found')
|
||||
}
|
||||
const res = decryptWeixinData.call(this, {
|
||||
encryptedData,
|
||||
sessionKey,
|
||||
iv
|
||||
})
|
||||
|
||||
mobile = res.purePhoneNumber
|
||||
}
|
||||
|
||||
const bindAccount = {
|
||||
mobile
|
||||
}
|
||||
await preBind.call(this, {
|
||||
uid,
|
||||
bindAccount,
|
||||
logType: LOG_TYPE.BIND_MOBILE
|
||||
})
|
||||
await postBind.call(this, {
|
||||
uid,
|
||||
bindAccount,
|
||||
extraData: {
|
||||
mobile_confirmed: 1
|
||||
},
|
||||
logType: LOG_TYPE.BIND_MOBILE
|
||||
})
|
||||
return {
|
||||
errCode: 0
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
const {
|
||||
getNeedCaptcha,
|
||||
verifyCaptcha
|
||||
} = require('../../lib/utils/captcha')
|
||||
const {
|
||||
LOG_TYPE,
|
||||
SMS_SCENE,
|
||||
CAPTCHA_SCENE
|
||||
} = require('../../common/constants')
|
||||
const {
|
||||
verifyMobileCode
|
||||
} = require('../../lib/utils/verify-code')
|
||||
const {
|
||||
preBind,
|
||||
postBind
|
||||
} = require('../../lib/utils/relate')
|
||||
|
||||
/**
|
||||
* 通过短信验证码绑定手机号
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-mobile-by-sms
|
||||
* @param {Object} params
|
||||
* @param {String} params.mobile 手机号
|
||||
* @param {String} params.code 短信验证码
|
||||
* @param {String} params.captcha 图形验证码
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
mobile: 'mobile',
|
||||
code: 'string',
|
||||
captcha: {
|
||||
type: 'string',
|
||||
required: false
|
||||
}
|
||||
}
|
||||
const {
|
||||
mobile,
|
||||
code,
|
||||
captcha
|
||||
} = params
|
||||
this.middleware.validate(params, schema)
|
||||
const uid = this.authInfo.uid
|
||||
|
||||
// 判断是否需要验证码
|
||||
const needCaptcha = await getNeedCaptcha.call(this, {
|
||||
uid,
|
||||
type: LOG_TYPE.BIND_MOBILE
|
||||
})
|
||||
if (needCaptcha) {
|
||||
await verifyCaptcha.call(this, {
|
||||
captcha,
|
||||
scene: CAPTCHA_SCENE.BIND_MOBILE_BY_SMS
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
// 验证手机号验证码,验证不通过时写入失败日志
|
||||
await verifyMobileCode({
|
||||
mobile,
|
||||
code,
|
||||
scene: SMS_SCENE.BIND_MOBILE_BY_SMS
|
||||
})
|
||||
} catch (error) {
|
||||
await this.middleware.uniIdLog({
|
||||
data: {
|
||||
user_id: uid
|
||||
},
|
||||
type: LOG_TYPE.BIND_MOBILE,
|
||||
success: false
|
||||
})
|
||||
throw error
|
||||
}
|
||||
const bindAccount = {
|
||||
mobile
|
||||
}
|
||||
await preBind.call(this, {
|
||||
uid,
|
||||
bindAccount,
|
||||
logType: LOG_TYPE.BIND_MOBILE
|
||||
})
|
||||
await postBind.call(this, {
|
||||
uid,
|
||||
bindAccount,
|
||||
extraData: {
|
||||
mobile_confirmed: 1
|
||||
},
|
||||
logType: LOG_TYPE.BIND_MOBILE
|
||||
})
|
||||
return {
|
||||
errCode: 0
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
const {
|
||||
getPhoneNumber
|
||||
} = require('../../lib/utils/univerify')
|
||||
const {
|
||||
LOG_TYPE
|
||||
} = require('../../common/constants')
|
||||
const {
|
||||
preBind,
|
||||
postBind
|
||||
} = require('../../lib/utils/relate')
|
||||
|
||||
/**
|
||||
* 通过一键登录绑定手机号
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-mobile-by-univerify
|
||||
* @param {Object} params
|
||||
* @param {String} params.openid APP端一键登录返回的openid
|
||||
* @param {String} params.access_token APP端一键登录返回的access_token
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
openid: 'string',
|
||||
access_token: 'string'
|
||||
}
|
||||
const {
|
||||
openid,
|
||||
// eslint-disable-next-line camelcase
|
||||
access_token
|
||||
} = params
|
||||
this.middleware.validate(params, schema)
|
||||
const uid = this.authInfo.uid
|
||||
let mobile
|
||||
try {
|
||||
const phoneInfo = await getPhoneNumber.call(this, {
|
||||
// eslint-disable-next-line camelcase
|
||||
access_token,
|
||||
openid
|
||||
})
|
||||
mobile = phoneInfo.phoneNumber
|
||||
} catch (error) {
|
||||
await this.middleware.uniIdLog({
|
||||
success: false,
|
||||
data: {
|
||||
user_id: uid
|
||||
},
|
||||
type: LOG_TYPE.BIND_MOBILE
|
||||
})
|
||||
throw error
|
||||
}
|
||||
|
||||
const bindAccount = {
|
||||
mobile
|
||||
}
|
||||
await preBind.call(this, {
|
||||
uid,
|
||||
bindAccount,
|
||||
logType: LOG_TYPE.BIND_MOBILE
|
||||
})
|
||||
await postBind.call(this, {
|
||||
uid,
|
||||
bindAccount,
|
||||
extraData: {
|
||||
mobile_confirmed: 1
|
||||
},
|
||||
logType: LOG_TYPE.BIND_MOBILE
|
||||
})
|
||||
return {
|
||||
errCode: 0
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
const {
|
||||
preBind,
|
||||
postBind
|
||||
} = require('../../lib/utils/relate')
|
||||
const {
|
||||
LOG_TYPE
|
||||
} = require('../../common/constants')
|
||||
const {
|
||||
ERROR
|
||||
} = require('../../common/error')
|
||||
const {
|
||||
initQQ
|
||||
} = require('../../lib/third-party/index')
|
||||
const {
|
||||
generateQQCache,
|
||||
getQQPlatform,
|
||||
saveQQUserKey
|
||||
} = require('../../lib/utils/qq')
|
||||
|
||||
/**
|
||||
* 绑定QQ
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-qq
|
||||
* @param {Object} params
|
||||
* @param {String} params.code 小程序端QQ登录返回的code
|
||||
* @param {String} params.accessToken APP端QQ登录返回的accessToken
|
||||
* @param {String} params.accessTokenExpired accessToken过期时间,由App端QQ登录返回的expires_in参数计算而来,单位:毫秒
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
code: {
|
||||
type: 'string',
|
||||
required: false
|
||||
},
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: false
|
||||
},
|
||||
accessTokenExpired: {
|
||||
type: 'number',
|
||||
required: false
|
||||
}
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
const uid = this.authInfo.uid
|
||||
const {
|
||||
code,
|
||||
accessToken,
|
||||
accessTokenExpired
|
||||
} = params
|
||||
const qqPlatform = getQQPlatform.call(this)
|
||||
const appId = this.getUniversalClientInfo().appId
|
||||
const qqApi = initQQ.call(this)
|
||||
const clientPlatform = this.clientPlatform
|
||||
const apiName = clientPlatform === 'mp-qq' ? 'code2Session' : 'getOpenidByToken'
|
||||
let getQQAccountResult
|
||||
try {
|
||||
getQQAccountResult = await qqApi[apiName]({
|
||||
code,
|
||||
accessToken
|
||||
})
|
||||
} catch (error) {
|
||||
await this.middleware.uniIdLog({
|
||||
success: false,
|
||||
type: LOG_TYPE.BIND_QQ
|
||||
})
|
||||
throw {
|
||||
errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
openid,
|
||||
unionid,
|
||||
// 保存下面四个字段
|
||||
sessionKey // 微信小程序用户sessionKey
|
||||
} = getQQAccountResult
|
||||
|
||||
const bindAccount = {
|
||||
qq_openid: {
|
||||
[qqPlatform]: openid
|
||||
},
|
||||
qq_unionid: unionid
|
||||
}
|
||||
await preBind.call(this, {
|
||||
uid,
|
||||
bindAccount,
|
||||
logType: LOG_TYPE.BIND_QQ
|
||||
})
|
||||
await saveQQUserKey.call(this, {
|
||||
openid,
|
||||
sessionKey,
|
||||
accessToken,
|
||||
accessTokenExpired
|
||||
})
|
||||
return postBind.call(this, {
|
||||
uid,
|
||||
bindAccount,
|
||||
extraData: {
|
||||
qq_openid: {
|
||||
[`${qqPlatform}_${appId}`]: openid
|
||||
},
|
||||
...generateQQCache.call(this, {
|
||||
openid,
|
||||
sessionKey
|
||||
})
|
||||
},
|
||||
logType: LOG_TYPE.BIND_QQ
|
||||
})
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
const {
|
||||
preBind,
|
||||
postBind
|
||||
} = require('../../lib/utils/relate')
|
||||
const {
|
||||
LOG_TYPE
|
||||
} = require('../../common/constants')
|
||||
const {
|
||||
generateWeixinCache,
|
||||
saveWeixinUserKey,
|
||||
getWeixinPlatform
|
||||
} = require('../../lib/utils/weixin')
|
||||
const {
|
||||
initWeixin
|
||||
} = require('../../lib/third-party/index')
|
||||
const {
|
||||
ERROR
|
||||
} = require('../../common/error')
|
||||
|
||||
/**
|
||||
* 绑定微信
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-weixin
|
||||
* @param {Object} params
|
||||
* @param {String} params.code 微信登录返回的code
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
code: 'string'
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
const uid = this.authInfo.uid
|
||||
const {
|
||||
code
|
||||
} = params
|
||||
const weixinPlatform = getWeixinPlatform.call(this)
|
||||
const appId = this.getUniversalClientInfo().appId
|
||||
|
||||
const weixinApi = initWeixin.call(this)
|
||||
const clientPlatform = this.clientPlatform
|
||||
const apiName = clientPlatform === 'mp-weixin' ? 'code2Session' : 'getOauthAccessToken'
|
||||
let getWeixinAccountResult
|
||||
try {
|
||||
getWeixinAccountResult = await weixinApi[apiName](code)
|
||||
} catch (error) {
|
||||
await this.middleware.uniIdLog({
|
||||
success: false,
|
||||
type: LOG_TYPE.BIND_WEIXIN
|
||||
})
|
||||
throw {
|
||||
errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
openid,
|
||||
unionid,
|
||||
// 保存下面四个字段
|
||||
sessionKey, // 微信小程序用户sessionKey
|
||||
accessToken, // App端微信用户accessToken
|
||||
refreshToken, // App端微信用户refreshToken
|
||||
expired: accessTokenExpired // App端微信用户accessToken过期时间
|
||||
} = getWeixinAccountResult
|
||||
|
||||
const bindAccount = {
|
||||
wx_openid: {
|
||||
[weixinPlatform]: openid
|
||||
},
|
||||
wx_unionid: unionid
|
||||
}
|
||||
await preBind.call(this, {
|
||||
uid,
|
||||
bindAccount,
|
||||
logType: LOG_TYPE.BIND_WEIXIN
|
||||
})
|
||||
await saveWeixinUserKey.call(this, {
|
||||
openid,
|
||||
sessionKey,
|
||||
accessToken,
|
||||
refreshToken,
|
||||
accessTokenExpired
|
||||
})
|
||||
return postBind.call(this, {
|
||||
uid,
|
||||
bindAccount,
|
||||
extraData: {
|
||||
wx_openid: {
|
||||
[`${weixinPlatform}_${appId}`]: openid
|
||||
},
|
||||
...generateWeixinCache.call(this, {
|
||||
openid,
|
||||
sessionKey, // 微信小程序用户sessionKey
|
||||
accessToken, // App端微信用户accessToken
|
||||
refreshToken, // App端微信用户refreshToken
|
||||
accessTokenExpired // App端微信用户accessToken过期时间
|
||||
})
|
||||
},
|
||||
logType: LOG_TYPE.BIND_WEIXIN
|
||||
})
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
module.exports = {
|
||||
bindMobileBySms: require('./bind-mobile-by-sms'),
|
||||
bindMobileByUniverify: require('./bind-mobile-by-univerify'),
|
||||
bindMobileByMpWeixin: require('./bind-mobile-by-mp-weixin'),
|
||||
bindAlipay: require('./bind-alipay'),
|
||||
bindApple: require('./bind-apple'),
|
||||
bindQQ: require('./bind-qq'),
|
||||
bindWeixin: require('./bind-weixin'),
|
||||
unbindWeixin: require('./unbind-weixin'),
|
||||
unbindAlipay: require('./unbind-alipay'),
|
||||
unbindQQ: require('./unbind-qq'),
|
||||
unbindApple: require('./unbind-apple')
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
const {
|
||||
preUnBind,
|
||||
postUnBind
|
||||
} = require('../../lib/utils/relate')
|
||||
const {
|
||||
LOG_TYPE, dbCmd
|
||||
} = require('../../common/constants')
|
||||
|
||||
/**
|
||||
* 解绑支付宝
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#unbind-alipay
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function () {
|
||||
const { uid } = this.authInfo
|
||||
|
||||
await preUnBind.call(this, {
|
||||
uid,
|
||||
unBindAccount: {
|
||||
ali_openid: dbCmd.exists(true)
|
||||
},
|
||||
logType: LOG_TYPE.UNBIND_ALIPAY
|
||||
})
|
||||
|
||||
return await postUnBind.call(this, {
|
||||
uid,
|
||||
unBindAccount: {
|
||||
ali_openid: dbCmd.remove()
|
||||
},
|
||||
logType: LOG_TYPE.UNBIND_ALIPAY
|
||||
})
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
const {
|
||||
preUnBind,
|
||||
postUnBind
|
||||
} = require('../../lib/utils/relate')
|
||||
const {
|
||||
LOG_TYPE, dbCmd
|
||||
} = require('../../common/constants')
|
||||
|
||||
/**
|
||||
* 解绑apple
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#unbind-apple
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function () {
|
||||
const { uid } = this.authInfo
|
||||
|
||||
await preUnBind.call(this, {
|
||||
uid,
|
||||
unBindAccount: {
|
||||
apple_openid: dbCmd.exists(true)
|
||||
},
|
||||
logType: LOG_TYPE.UNBIND_APPLE
|
||||
})
|
||||
|
||||
return await postUnBind.call(this, {
|
||||
uid,
|
||||
unBindAccount: {
|
||||
apple_openid: dbCmd.remove()
|
||||
},
|
||||
logType: LOG_TYPE.UNBIND_APPLE
|
||||
})
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
const {
|
||||
preUnBind,
|
||||
postUnBind
|
||||
} = require('../../lib/utils/relate')
|
||||
const {
|
||||
LOG_TYPE, dbCmd
|
||||
} = require('../../common/constants')
|
||||
/**
|
||||
* 解绑QQ
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#unbind-qq
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function () {
|
||||
const { uid } = this.authInfo
|
||||
|
||||
await preUnBind.call(this, {
|
||||
uid,
|
||||
unBindAccount: {
|
||||
qq_openid: dbCmd.exists(true),
|
||||
qq_unionid: dbCmd.exists(true)
|
||||
},
|
||||
logType: LOG_TYPE.UNBIND_QQ
|
||||
})
|
||||
|
||||
return await postUnBind.call(this, {
|
||||
uid,
|
||||
unBindAccount: {
|
||||
qq_openid: dbCmd.remove(),
|
||||
qq_unionid: dbCmd.remove()
|
||||
},
|
||||
logType: LOG_TYPE.UNBIND_QQ
|
||||
})
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
const {
|
||||
preUnBind,
|
||||
postUnBind
|
||||
} = require('../../lib/utils/relate')
|
||||
const {
|
||||
LOG_TYPE, dbCmd
|
||||
} = require('../../common/constants')
|
||||
const {
|
||||
getWeixinPlatform
|
||||
} = require('../../lib/utils/weixin')
|
||||
|
||||
/**
|
||||
* 解绑微信
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#unbind-weixin
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function () {
|
||||
const { uid } = this.authInfo
|
||||
// const weixinPlatform = getWeixinPlatform.call(this)
|
||||
|
||||
await preUnBind.call(this, {
|
||||
uid,
|
||||
unBindAccount: {
|
||||
wx_openid: dbCmd.exists(true),
|
||||
wx_unionid: dbCmd.exists(true)
|
||||
},
|
||||
logType: LOG_TYPE.UNBIND_WEIXIN
|
||||
})
|
||||
|
||||
return await postUnBind.call(this, {
|
||||
uid,
|
||||
unBindAccount: {
|
||||
wx_openid: dbCmd.remove(),
|
||||
wx_unionid: dbCmd.remove()
|
||||
},
|
||||
logType: LOG_TYPE.UNBIND_WEIXIN
|
||||
})
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
refreshToken: require('./refresh-token'),
|
||||
setPushCid: require('./set-push-cid'),
|
||||
secureNetworkHandshakeByWeixin: require('./secure-network-handshake-by-weixin')
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 刷新token
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#refresh-token
|
||||
*/
|
||||
module.exports = async function () {
|
||||
const refreshTokenRes = await this.uniIdCommon.refreshToken({
|
||||
token: this.getUniversalUniIdToken()
|
||||
})
|
||||
const {
|
||||
errCode,
|
||||
token,
|
||||
tokenExpired
|
||||
} = refreshTokenRes
|
||||
if (errCode) {
|
||||
throw refreshTokenRes
|
||||
}
|
||||
return {
|
||||
errCode: 0,
|
||||
newToken: {
|
||||
token,
|
||||
tokenExpired
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
const {
|
||||
ERROR
|
||||
} = require('../../common/error')
|
||||
const {
|
||||
initWeixin
|
||||
} = require('../../lib/third-party/index')
|
||||
const {
|
||||
saveWeixinUserKey,
|
||||
saveSecureNetworkCache
|
||||
} = require('../../lib/utils/weixin')
|
||||
const loginByWeixin = require('../login/login-by-weixin')
|
||||
/**
|
||||
* 微信安全网络握手
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#set-push-cid
|
||||
* @param {object} params
|
||||
* @param {string} params.code 微信登录返回的code
|
||||
* @param {boolean} params.callLoginByWeixin 是否同时调用一次微信登录
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
code: 'string',
|
||||
callLoginByWeixin: {
|
||||
type: 'boolean',
|
||||
required: false
|
||||
}
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
let platform = this.clientPlatform
|
||||
if (platform !== 'mp-weixin') {
|
||||
throw new Error(`[secureNetworkHandshake] platform ${platform} is not supported`)
|
||||
}
|
||||
const {
|
||||
code,
|
||||
callLoginByWeixin = false
|
||||
} = params
|
||||
if (callLoginByWeixin) {
|
||||
return loginByWeixin.call(this, {
|
||||
code,
|
||||
secureNetworkCache: true
|
||||
})
|
||||
}
|
||||
|
||||
const weixinApi = initWeixin.call(this)
|
||||
let getWeixinAccountResult
|
||||
try {
|
||||
getWeixinAccountResult = await weixinApi.code2Session(code)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
throw {
|
||||
errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED
|
||||
}
|
||||
}
|
||||
const {
|
||||
openid,
|
||||
unionid,
|
||||
sessionKey // 微信小程序用户sessionKey
|
||||
} = getWeixinAccountResult
|
||||
await saveSecureNetworkCache.call(this, {
|
||||
code,
|
||||
openid,
|
||||
unionid,
|
||||
sessionKey
|
||||
})
|
||||
await saveWeixinUserKey.call(this, {
|
||||
openid,
|
||||
sessionKey
|
||||
})
|
||||
|
||||
return {
|
||||
errCode: 0
|
||||
}
|
||||
}
|
@ -0,0 +1,132 @@
|
||||
const {
|
||||
deviceCollection
|
||||
} = require('../../common/constants')
|
||||
const {
|
||||
ERROR
|
||||
} = require('../../common/error')
|
||||
|
||||
async function setOpendbDevice ({
|
||||
pushClientId
|
||||
} = {}) {
|
||||
// 仅新增,如果存在进行更新操作
|
||||
const {
|
||||
appId,
|
||||
deviceId,
|
||||
deviceBrand,
|
||||
deviceModel,
|
||||
osName,
|
||||
osVersion,
|
||||
osLanguage,
|
||||
osTheme,
|
||||
devicePixelRatio,
|
||||
windowWidth,
|
||||
windowHeight,
|
||||
screenWidth,
|
||||
screenHeight,
|
||||
romName,
|
||||
romVersion
|
||||
} = this.getUniversalClientInfo()
|
||||
const platform = this.clientPlatform
|
||||
const now = Date.now()
|
||||
|
||||
const db = uniCloud.database()
|
||||
const opendbDeviceCollection = db.collection('opendb-device')
|
||||
const getDeviceRes = await opendbDeviceCollection.where({
|
||||
device_id: deviceId
|
||||
}).get()
|
||||
const data = {
|
||||
appid: appId,
|
||||
device_id: deviceId,
|
||||
vendor: deviceBrand,
|
||||
model: deviceModel,
|
||||
uni_platform: platform,
|
||||
os_name: osName,
|
||||
os_version: osVersion,
|
||||
os_language: osLanguage,
|
||||
os_theme: osTheme,
|
||||
pixel_ratio: devicePixelRatio,
|
||||
window_width: windowWidth,
|
||||
window_height: windowHeight,
|
||||
screen_width: screenWidth,
|
||||
screen_height: screenHeight,
|
||||
rom_name: romName,
|
||||
rom_version: romVersion,
|
||||
last_update_date: now,
|
||||
push_clientid: pushClientId
|
||||
}
|
||||
if (getDeviceRes.data.length > 0) {
|
||||
await opendbDeviceCollection.where({
|
||||
device_id: deviceId
|
||||
}).update(data)
|
||||
return
|
||||
}
|
||||
data.create_date = now
|
||||
await opendbDeviceCollection.add(data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新device表的push_clien_id
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#set-push-cid
|
||||
* @param {object} params
|
||||
* @param {string} params.pushClientId 客户端pushClientId
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
pushClientId: 'string'
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
const {
|
||||
deviceId,
|
||||
appId,
|
||||
osName
|
||||
} = this.getUniversalClientInfo()
|
||||
let platform = this.clientPlatform
|
||||
if (platform === 'app') {
|
||||
platform += osName
|
||||
}
|
||||
|
||||
const {
|
||||
uid,
|
||||
exp
|
||||
} = this.authInfo
|
||||
const { pushClientId } = params
|
||||
const tokenExpired = exp * 1000
|
||||
const getDeviceRes = await deviceCollection.where({
|
||||
device_id: deviceId
|
||||
}).get()
|
||||
// console.log(getDeviceRes)
|
||||
if (getDeviceRes.data.length > 1) {
|
||||
return {
|
||||
errCode: ERROR.SYSTEM_ERROR
|
||||
}
|
||||
}
|
||||
const deviceRecord = getDeviceRes.data[0]
|
||||
await setOpendbDevice.call(this, {
|
||||
pushClientId
|
||||
})
|
||||
if (!deviceRecord) {
|
||||
await deviceCollection.add({
|
||||
user_id: uid,
|
||||
device_id: deviceId,
|
||||
token_expired: tokenExpired,
|
||||
push_clientid: pushClientId,
|
||||
appid: appId
|
||||
})
|
||||
return {
|
||||
errCode: 0
|
||||
}
|
||||
}
|
||||
|
||||
await deviceCollection.where({
|
||||
device_id: deviceId
|
||||
}).update({
|
||||
user_id: uid,
|
||||
token_expired: tokenExpired,
|
||||
push_clientid: pushClientId,
|
||||
appid: appId
|
||||
})
|
||||
return {
|
||||
errCode: 0
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
const {
|
||||
CAPTCHA_SCENE
|
||||
} = require('../../common/constants')
|
||||
const {
|
||||
ERROR
|
||||
} = require('../../common/error')
|
||||
|
||||
/**
|
||||
* 创建图形验证码
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#create-captcha
|
||||
* @param {Object} params
|
||||
* @param {String} params.scene 图形验证码使用场景
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
scene: 'string'
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
|
||||
const { deviceId, platform } = this.getUniversalClientInfo()
|
||||
const {
|
||||
scene
|
||||
} = params
|
||||
if (!(Object.values(CAPTCHA_SCENE).includes(scene))) {
|
||||
throw {
|
||||
errCode: ERROR.INVALID_PARAM
|
||||
}
|
||||
}
|
||||
return this.uniCaptcha.create({
|
||||
deviceId,
|
||||
scene,
|
||||
uniPlatform: platform
|
||||
})
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
createCaptcha: require('./create-captcha'),
|
||||
refreshCaptcha: require('./refresh-captcha'),
|
||||
sendSmsCode: require('./send-sms-code'),
|
||||
sendEmailLink: require('./send-email-link'),
|
||||
sendEmailCode: require('./send-email-code')
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
const {
|
||||
CAPTCHA_SCENE
|
||||
} = require('../../common/constants')
|
||||
const {
|
||||
ERROR
|
||||
} = require('../../common/error')
|
||||
|
||||
/**
|
||||
* 刷新图形验证码
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#refresh-captcha
|
||||
* @param {Object} params
|
||||
* @param {String} params.scene 图形验证码使用场景
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
scene: 'string'
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
|
||||
const { deviceId, platform } = this.getUniversalClientInfo()
|
||||
|
||||
const {
|
||||
scene
|
||||
} = params
|
||||
if (!(Object.values(CAPTCHA_SCENE).includes(scene))) {
|
||||
throw {
|
||||
errCode: ERROR.INVALID_PARAM
|
||||
}
|
||||
}
|
||||
return this.uniCaptcha.refresh({
|
||||
deviceId,
|
||||
scene,
|
||||
uniPlatform: platform
|
||||
})
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
const {
|
||||
verifyCaptcha
|
||||
} = require('../../lib/utils/captcha')
|
||||
const {
|
||||
EMAIL_SCENE
|
||||
} = require('../../common/constants')
|
||||
const {
|
||||
ERROR
|
||||
} = require('../../common/error')
|
||||
/**
|
||||
* 发送邮箱验证码,可用于登录、注册、绑定邮箱、修改密码等操作
|
||||
* @tutorial
|
||||
* @param {Object} params
|
||||
* @param {String} params.email 邮箱
|
||||
* @param {String} params.captcha 图形验证码
|
||||
* @param {String} params.scene 使用场景
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
email: 'email',
|
||||
captcha: 'string',
|
||||
scene: 'string'
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
|
||||
const {
|
||||
email,
|
||||
captcha,
|
||||
scene
|
||||
} = params
|
||||
|
||||
if (!(Object.values(EMAIL_SCENE).includes(scene))) {
|
||||
throw {
|
||||
errCode: ERROR.INVALID_PARAM
|
||||
}
|
||||
}
|
||||
|
||||
await verifyCaptcha.call(this, {
|
||||
scene: 'send-email-code',
|
||||
captcha
|
||||
})
|
||||
|
||||
// -- 测试代码
|
||||
await require('../../lib/utils/verify-code')
|
||||
.setEmailVerifyCode.call(this, {
|
||||
email,
|
||||
code: '123456',
|
||||
expiresIn: 180,
|
||||
scene
|
||||
})
|
||||
return {
|
||||
errCode: 'uni-id-invalid-mail-template',
|
||||
errMsg: `已启动测试模式,直接使用:123456作为邮箱验证码即可。\n如果是正式项目,需自行实现发送邮件的相关功能`
|
||||
}
|
||||
// -- 测试代码
|
||||
|
||||
|
||||
//发送邮件--需自行实现
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
/**
|
||||
* 发送邮箱链接,可用于登录、注册、绑定邮箱、修改密码等操作
|
||||
* @tutorial
|
||||
* @param {Object} params
|
||||
* @param {String} params.email 邮箱
|
||||
* @param {String} params.scene 使用场景
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
// 此接口暂未实现,欢迎向我们提交pr
|
||||
throw new Error('api[sendEmailLink] is not yet implemented')
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
const {
|
||||
sendSmsCode
|
||||
} = require('../../lib/utils/sms')
|
||||
const {
|
||||
verifyCaptcha
|
||||
} = require('../../lib/utils/captcha')
|
||||
const {
|
||||
SMS_SCENE
|
||||
} = require('../../common/constants')
|
||||
const {
|
||||
ERROR
|
||||
} = require('../../common/error')
|
||||
|
||||
/**
|
||||
* 发送短信验证码
|
||||
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#send-sms-code
|
||||
* @param {Object} params
|
||||
* @param {String} params.mobile 手机号
|
||||
* @param {String} params.captcha 图形验证码
|
||||
* @param {String} params.scene 短信验证码使用场景
|
||||
* @returns
|
||||
*/
|
||||
module.exports = async function (params = {}) {
|
||||
const schema = {
|
||||
mobile: 'mobile',
|
||||
captcha: 'string',
|
||||
scene: 'string'
|
||||
}
|
||||
this.middleware.validate(params, schema)
|
||||
const {
|
||||
mobile,
|
||||
captcha,
|
||||
scene
|
||||
} = params
|
||||
if (!(Object.values(SMS_SCENE).includes(scene))) {
|
||||
throw {
|
||||
errCode: ERROR.INVALID_PARAM
|
||||
}
|
||||
}
|
||||
await verifyCaptcha.call(this, {
|
||||
scene: 'send-sms-code',
|
||||
captcha
|
||||
})
|
||||
|
||||
// -- 测试代码
|
||||
const {
|
||||
templateId
|
||||
} = (this.config.service &&
|
||||
this.config.service.sms &&
|
||||
this.config.service.sms.scene &&
|
||||
this.config.service.sms.scene[scene]) || {}
|
||||
if (!templateId || !templateId.replace(/[^0-9a-zA-Z]/g, '')) {
|
||||
await require('../../lib/utils/verify-code')
|
||||
.setMobileVerifyCode.call(this, {
|
||||
mobile: params.mobile,
|
||||
code: '123456',
|
||||
expiresIn: 180,
|
||||
scene
|
||||
})
|
||||
return {
|
||||
errCode: 'uni-id-invalid-sms-template-id',
|
||||
errMsg: `未找到scene=${scene},的短信模版templateId。\n已启动测试模式,直接使用:123456作为短信验证码即可。\n如果是正式项目,请在路径:/common/uni-config-center/uni-id/config.json中service->sms中配置密钥等信息\n更多详情:https://uniapp.dcloud.io/uniCloud/uni-id.html#config`
|
||||
}
|
||||
}
|
||||
// -- 测试代码
|
||||
|
||||
return sendSmsCode.call(this, {
|
||||
mobile,
|
||||
scene
|
||||
})
|
||||
}
|
Reference in New Issue
Block a user