同步操作将从 DCloud/uni-id 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
99%的应用,都要开发用户注册、登录、发送短信验证码、密码加密保存、修改密码、token管理等功能,从前端到后端都需要。
为什么不能有一个开源的通用项目,避免大家的重复开发呢?
uni-id
应需而生。
uni-id
为uniCloud
开发者提供了简单、统一、可扩展的用户管理能力封装。
uni-id
包括如下组成部分:
主表为 uni-id-users
表,保存用户的基本信息。
扩展字段有很多,如实名认证数据、工作履历数据,开发者可以自由扩展。
提供一个名为uni-id
的公共模块,该模块封装了一系列API,包括注册、登录、修改密码、设置头像等。
示例工程中还提供了一个user-center
的云函数,演示在云函数中如何调用uni-id
公共模块。示例工程地址
前端示例通过callfunction调用云函数user-center
,在注册和登录时保存token。
uniCloud框架底层,会自动在callfunction时传递uni-id
的token(uni-app 2.7.13+版本)。在云函数的event中可直接拿到uni-id
的token。也就是说开发者无需自己管理token了。
2.7.14版本使用的时候token持久化存储时需要存储为uniIdToken,之后的版本虽然也兼容uniIdToken,但是推荐存储为uni_id_token
关于第三点,着重强调下。
一个应用,往往需要集成多个功能模块。比如一个电商应用,需要一个基本电商模板,还需要客服聊天模板,甚至还需要用户交流社区。
在插件市场,每类模板插件都能找到,但他们如果不是基于同一套用户体系设计,就很难整合。
DCloud推荐所有uniCloud的应用,都基于uni-id
来做。
有了统一的账户规范,并且围绕这套账户规范,有各种各样插件,那么开发者可以随意整合这些插件,让数据连同。
规范,还可以让上下游充分协同。插件市场会出现各种数据迁移插件,比如把从discuz里把用户迁移到uni-id
中的插件,相信围绕这套规范的产业链会非常活跃。
uni-id
已完整的内容:
关于还缺少的部分,哪些DCloud在完善,哪些希望开发者给共同完善开源项目,计划与边界公布如下:
DCloud暂无计划开发百度、头条、QQ等小程序的登录,以及Apple ID、微博、QQ等App端的登录。欢迎其他开发者在开源项目上提交pr,共同完善uni-id
。
手机号一键认证sdk,目前插件市场里已经有不少相关插件,未来DCloud会整合到uni-id
中。邮箱验证,DCloud暂无计划开发,有需求的开发者欢迎提供pr。
目前插件市场里已经有不少相关插件,未来DCloud会整合到uni-id
中。
这部分欢迎开发者参与完善。
其他方面,各种常见开源项目如discuz、wordPress、ecshop的用户导入插件,不属于uni-id
主工程,欢迎开发者单独提交插件到插件市场。
对于uni-id
还未封装的能力,欢迎大家在开源项目上提交 pr,共同完善这个开源项目。
uni-id 作为公用模块导入 common 目录,然后在云函数中调用,示例代码:
'use strict';
const uniID = require('uni-id')
exports.main = async (event) => {
let params = event.params
let res = {}
let payload = {}
// 不需要uid的方法
let noTokenActions = ['register', 'login', 'loginByWeixin']
if(!!event.uniIdToken && noTokenActions.indexOf(event.action) >= 0){
payload = await uniID.checkToken(event.uniIdToken)
if (payload.code && payload.code > 0) {
return payload
}
if(!!params){
params.uid = payload.uid
}
}
switch (event.action) {
case 'register':
res = await uniID.register(event.params);
break;
case 'login':
res = await uniID.login(event.params);
break;
case 'loginByWeixin':
res = await uniID.loginByWeixin(event.code);
break;
case 'logout':
res = await uniID.logout(payload.uid);
break;
case 'updatePassword':
res = await uniID.updatePwd(params);
break;
case 'resetPwd':
res = await uniID.resetPwd(params);
break;
case 'setAvatar':
res = await uniID.setAvatar(params);
break;
case 'bindMobile':
res = await uniID.bindMobile(params);
break;
case 'bindEmail':
res = await uniID.bindEmail(params);
break;
case 'bindWeixin':
res = await uniID.bindWeixin(payload.uid, event.code);
break;
case 'unbindWeixin':
res = await uniID.unbindWeixin(payload.uid);
break;
case 'bindWeixin':
res = await uniID.bindEmail(params);
break;
case 'updateUser':
res = await uniID.updateUser(params);
break;
case 'setVerifyCode':
//mobile email提供一个即可。验证码需要调用方发送给用户
let code = '1234';
//send verify code
res = await uniID.setVerifyCode({
mobile: params.mobile,
email: params.email,
code,
expiresIn: params.expiresIn,
type: params.type
});
break;
case 'loginBySms':
// 需要先调用sendSmsCode发送验证码或者setVerifyCode设置验证码
res = await uniID.loginBySms(params);
break;
default:
res = {
code: 403,
msg: '非法访问'
}
break;
}
//返回数据给客户端
return res
};
表名:uni-id-users
字段 | 类型 | 必填 | 描述 |
---|---|---|---|
_id | Object ID | 是 | 存储文档 ID(用户 ID),系统自动生成 |
username | String | 是 | 用户名,不允许重复 |
password | String | 否 | 密码,加密存储 |
nickname | String | 否 | 用户昵称 |
gender | Integer | 否 | 用户性别:0 未知 1 男性 2 女性 |
status | Integer | 是 | 用户状态:0 正常 1 禁用 2 审核中 3 审核拒绝 |
mobile | String | 否 | 手机号码 |
mobile_confirmed | Integer | 否 | 手机号验证状态:0 未验证 1 已验证 |
String | 否 | 邮箱地址 | |
email_confirmed | Integer | 否 | 邮箱验证状态:0 未验证 1 已验证 |
avatar | String | 否 | 头像地址 |
wx_unionid | String | 否 | 微信unionid |
wx_openid | Object | 否 | 微信各个平台openid |
ali_openid | String | 否 | 支付宝平台openid |
comment | String | 否 | 备注 |
realname_auth | Object | 否 | 实名认证信息 |
register_date | Timestamp | 否 | 注册时间 |
register_ip | String | 否 | 注册时 IP 地址 |
last_login_date | Timestamp | 否 | 最后登录时间 |
last_login_ip | String | 否 | 最后登录时 IP 地址 |
login_ip_limit | Array | 否 | 登录 IP 限制 |
inviter_uid | Array | 否 | 邀请人uid,按层级从下往上排列的uid数组,即第一个是直接上级 |
my_invite_code | String | 否 | 用户自己的邀请码 |
score | Integer | 否 | 用户积分 |
realname_auth字段定义
字段 | 类型 | 必填 | 描述 |
---|---|---|---|
type | Integer | 是 | 用户类型:0 个人用户 1 企业用户 |
auth_status | Integer | 是 | 认证状态:0 未认证 1 等待认证 2 认证通过 3 认证失败 |
auth_date | Timestamp | 否 | 认证通过时间 |
real_name | String | 否 | 真实姓名/企业名称 |
identity | String | 否 | 身份证号码/营业执照号码 |
id_card_front | String | 否 | 身份证正面照 URL |
id_card_back | String | 否 | 身份证反面照 URL |
id_card_in_hand | String | 否 | 手持身份证照片 URL |
license | String | 否 | 营业执照 URL |
contact_person | String | 否 | 联系人姓名 |
contact_mobile | String | 否 | 联系人手机号码 |
contact_email | String | 否 | 联系人邮箱 |
login_ip_limit字段定义
字段 | 类型 | 必填 | 描述 |
---|---|---|---|
ip | String | 是 | ip地址 |
error_times | Integer | 是 | 密码错误次数 |
last_error_time | Timestamp | 是 | 上次密码错误时间 |
wx_openid字段定义
字段 | 类型 | 必填 | 描述 |
---|---|---|---|
app-plus | String | 否 | app平台微信openid |
mp-weixin | String | 否 | 微信小程序平台openid |
job 字段定义
字段 | 类型 | 必填 | 描述 |
---|---|---|---|
company | String | 否 | 公司名称 |
title | String | 否 | 职位 |
用户集合示例:
{
"_id": "f2a60d815ee1da3900823d45541bb162",
"username": "姓名"
"password": "503005d4dd16dd7771b2d0a47aaef927e9dba89e",
"status":0,//用户状态:0正常 1禁用 2审核中 3审核拒绝
"mobile":"",
"mobile_confirmed":0, //手机号是否验证,0为未验证,1为已验证
"email":"amdin@domain.com",
"email_confirmed":0, //邮箱是否验证,0为未验证,1为已验证
"avatar":"https://cdn.domain.com/avatar.png"
"register_ip": "123.120.11.128", //注册IP
"last_login_ip": "123.120.11.128", //最后登录IP
}
表名:uni-verify
字段 | 类型 | 必填 | 描述 |
---|---|---|---|
_id | Object ID | 是 | 存储文档 ID(验证码 ID),系统自动生成 |
mobile | String | 是 | 手机号,和邮箱二选一 |
String | 是 | 邮箱,和手机号二选一 | |
code | String | 是 | 验证码 |
type | String | 是 | 验证类型:login, register, bind, unbind, pay |
state | Integer | 是 | 验证状态:0 未验证 1 已验证 2 已作废 |
ip | String | 否 | 请求时 IP 地址 |
created_at | Timestamp | 否 | 创建时间 |
expired_at | Timestamp | 否 | 验证码过期时间 |
api(xxx)
形式,否则使用api({xxx:xxx,xxx:xxx})
形式方便后续扩充模块 | 模块码 | 错误代码 | 错误信息 |
---|---|---|---|
登录通用模块 | 100 | 01 | 账号已禁用 |
账号、邮箱、手机+密码登录 | 101 | 01 | 用户不存在 |
02 | 密码错误 | ||
03 | 密码错误次数过多 | ||
手机号验证码登录/注册 | 102 | 01 | 手机号已存在(传入type='register'且手机号已注册时触发) |
102 | 02 | 此手机号尚未注册(传入type='login'且手机号未注册时触发) | |
102 | 03 | 邀请码无效(邀请码存在且唯一时才算有效) | |
邮箱验证码登录/注册 | 103 | 01 | 此邮箱已注册(传入type='register'且邮箱已注册时触发) |
103 | 02 | 此邮箱尚未注册(传入type='login'且邮箱未注册时触发) | |
微信登录/注册 | 104 | 01 | 获取openid失败 |
支付宝登录/注册 | 105 | 01 | 获取openid失败 |
注册通用模块 | 200 | - | - |
账号、邮箱、手机+密码注册 | 201 | 01 | 用户名、邮箱、手机号必填一项 |
02 | 用户名、邮箱、手机号冲突 | ||
Token类 | 300 | - | - |
生成Token | 301 | - | - |
验证Token | 302 | 01 | 设备特征校验未通过 |
02 | 云端以不包含此token | ||
03 | token已过期 | ||
04 | token校验未通过 | ||
账号安全类 | 400 | - | - |
登出 | 401 | - | - |
修改密码 | 402 | 01 | 用户不存在 |
02 | 旧密码错误 | ||
重置密码 | 403 | - | - |
验证类 | 500 | - | - |
设置验证码 | 501 | 01 | 参数错误 |
校验验证码 | 502 | 01 | 参数错误 |
02 | 验证码错误或已失效 | ||
发送短信验证码 | 503 | 01 | 验证码发送失败,一般msg内有描述 |
绑定账号 | 600 | - | - |
绑定手机号 | 601 | 01 | 此手机号已被绑定 |
绑定邮箱 | 602 | 01 | 此邮箱已被绑定 |
绑定微信 | 603 | 01 | 获取openid失败 |
02 | 此账号已被绑定 | ||
绑定支付宝 | 604 | 01 | 获取openid失败 |
02 | 此账号已被绑定 | ||
解绑账号 | 700 | - | - |
解绑手机号 | 701 | 01 | 解绑失败,可能已经解绑或者账号不匹配 |
解绑邮箱 | 702 | 01 | 解绑失败,可能已经解绑或者账号不匹配 |
解绑微信 | 703 | 01 | 解绑失败,可能已经解绑 |
解绑支付宝 | 704 | 01 | 解绑失败,可能已经解绑 |
基础功能 | 800 | - | - |
更新用户信息 | 801 | 01 | 参数错误 |
设置头像 | 802 | - | - |
获取用户信息 | 803 | 01 | 未查询到用户信息 |
设置用户自己的邀请码 | 804 | 01 | 邀请码设置失败,验证码重复或自动设置重试多次依然重复 |
02 | 邀请码重试多次依然重复 | ||
填写邀请人邀请码 | 805 | 01 | 邀请码无效(邀请码存在且唯一时才算有效) |
02 | uid错误,用户不存在 | ||
03 | 邀请码不可修改 | ||
获取微信openid | 806 | 01 | 未能获取openid |
02 | 调用获取openid接口失败 | ||
获取支付宝openid | 807 | 01 | 未能获取openid |
02 | 调用获取openid接口失败 | ||
公用码 | 900 | 01 | 数据库读写异常 |
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。