简体中文
uni-id-co是uni-id-pages的核心云对象,包含了诸多用户相关的接口。作为uni-id体系的一部分,uni-id-co也使用uni-id的配置文件(cloudfunctions/common/uni-config-center/uni-id/config.json
)。目前此云对象依赖了一些客户端信息,不支持被其他云函数/云对象调用。已支持url化调用,参考:uni-id-co url化
前端调用云对象uni-id-co
内的方法前应先获取云对象的引用,代码如下
const uniIdCo = uniCloud.importObject('uni-id-co')
如调用uni-id-co方法时出现找不到lodash.merge
模块的错误,请手动在uni-id-co云对象目录执行npm install
。如果是运行客户端的话uniCloud插件会自动给uni-id-co安装缺失的依赖。
├─common // 公用逻辑
├─config // 配置
│ └─permission.js // 调用接口所需的权限配置
├─lang // 国际化目录
├─lib // 基础功能,不建议修改此目录下文件
│ ├─third-party // 三方平台接口
│ └─utils // 基础功能
├─middleware // 中间件
└─module // 分模块存放的云对象方法
uni-id-co
所有api返回值均满足uniCloud响应体规范
返回值示例
{
errCode: 0, // 错误码,详见错误码列表
errMsg: '', // 错误信息,uni-id-co会自动根据客户端语言对错误信息进行国际化
newToken: { // 注册、登录、刷新token等接口会自动返回新token,uniCloud客户端sdk会自动将新token及过期时间存储在storage内(需要HBuilderX 3.4.13及以上版本)
token,
tokenExpired
},
// ...其余参数
}
注意
自uni-id-pages@1.0.29
版本起支持URL化 什么是URL化
调用规范:
Content-Type
必须为application/json
,请求方法必须是POST
, 如不满足条件将会返回 uni-id-unsupported-request
错误码{
"clientInfo": {},
"uniIdToken": "",
"params": {}
}
字段说明
字段 | 说明 |
---|---|
clientInfo | 客户端信息; uni.getSystemInfo返回的字段 |
uniIdToken | 用户Token; 用户登录后必填 |
params | API接口参数字段 |
如果是在 uni-app 之外的应用中调用 URL 化接口,请确保clientInfo中存在以下字段:
字段 | 说明 |
---|---|
uniPlatform | 应用运行平台,与条件编译平台相同。详见 |
appId | manifest 中应用appid,即DCloud appid。如没有请手动指定一个,需确保唯一性。 |
deviceId | 设备 id;通过uni.getSystemInfo获取 |
假设已在uniCloud 控制台已设置URL化域名PATH,以PATH为/http/uni-id-co
为例,演示登录示例:
uni.request({
url: 'https://{云函数Url化域名}/http/uni-id-co/login',
method: 'POST',
data: {
clientInfo: uni.getSystemInfoSync(),
uniIdToken: '用户Token',
params: {
username:"username",
password:"password"
}
},
header: {
'Content-Type': 'application/json'
},
success: (res) => {
// 返回值
}
})
注意
请不要添加 Query 参数,URL化后将忽略 Query 参数
API | 描述 |
---|---|
uniIdCo.registerAdmin() | 注册管理员 详情 |
uniIdCo.addUser() | 新增用户 详情 |
uniIdCo.authorizeAppLogin() | 授权用户登录应用 详情 |
uniIdCo.removeAuthorizedApp() | 移除用户登录授权 详情 |
uniIdCo.setAuthorizedApp() | 设置用户允许登录的应用列表 详情 |
uniIdCo.registerUser() | 注册普通用户 详情 |
uniIdCo.registerUserByEmail() | 通过邮箱验证码注册普通用户 详情 |
uniIdCo.login() | 用户名密码登录 详情 |
uniIdCo.loginBySms() | 短信验证码登录 详情 |
uniIdCo.loginByUniverify() | App端一键登录 详情 |
uniIdCo.loginByWeixin() | 微信登录 详情 |
uniIdCo.loginByAlipay() | 支付宝登录 详情 |
uniIdCo.loginByQQ() | QQ登录 详情 |
uniIdCo.loginByApple() | 苹果登录 详情 |
uniIdCo.logout() | 用户退出登录 详情 |
uniIdCo.bindMobileBySms() | 通过短信验证码绑定手机号 详情 |
uniIdCo.bindMobileByUniverify() | 通过一键登录绑定手机号 详情 |
uniIdCo.bindMobileByMpWeixin() | 通过微信绑定手机号 详情 |
uniIdCo.bindWeixin() | 绑定微信 详情 |
uniIdCo.bindQQ() | 绑定QQ 详情 |
uniIdCo.bindAlipay() | 绑定支付宝账号 详情 |
uniIdCo.bindApple() | 绑定苹果账号 详情 |
uniIdCo.updatePwd() | 更新密码 详情 |
uniIdCo.resetPwdBySms() | 通过短信验证码重置密码 详情 |
uniIdCo.resetPwdByEmail() | 通过邮箱验证码重置密码 详情 |
uniIdCo.closeAccount() | 注销账户 详情 |
uniIdCo.getAccountInfo() | 获取账户账户简略信息 详情 |
uniIdCo.createCaptcha() | 创建图形验证码 详情 |
uniIdCo.refreshCaptcha() | 刷新图形验证码 详情 |
uniIdCo.sendSmsCode() | 发送短信验证码 详情 |
uniIdCo.sendEmailCode() | 发送邮箱验证码 详情 |
uniIdCo.refreshToken() | 刷新token 详情 |
uniIdCo.acceptInvite() | 接受邀请 详情 |
uniIdCo.getInvitedUser() | 获取受邀用户 详情 |
uniIdCo.setPushCid() | 更新device表的push_clien_id 详情 |
uniIdCo.getSupportedLoginType() | 获取支持的登录方式 详情 |
接口名:registerAdmin
接口形式
await uniIdCo.registerAdmin({
username,
password,
nickname
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
username | string | 是 | 超级管理员用户名 |
password | string | 是 | 超级管理员密码 |
nickname | string | 否 | 超级管理员昵称 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
注意
接口名:registerUser
接口形式
await uniIdCo.registerUser({
username,
password,
captcha,
nickname,
inviteCode
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
username | string | 是 | 用户名 |
password | string | 是 | 密码 |
captcha | string | 是 | 图形验证码 |
nickname | string | 否 | 昵称 |
inviteCode | string | 否 | 邀请码 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
接口名:registerUserByEmail
接口形式
await uniIdCo.registerUserByEmail({
email,
password,
code,
nickname,
inviteCode
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
string | 是 | 邮箱 | |
password | string | 是 | 密码 |
code | string | 是 | 邮箱验证码 |
nickname | string | 否 | 昵称 |
inviteCode | string | 否 | 邀请码 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
接口名:login
接口形式
await uniIdCo.login({
username,
password,
captcha
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
username | string | 和mobile、email三选一 | 用户名 |
mobile | string | 和username、email三选一 | 手机号 |
string | 和username、mobile三选一 | 邮箱 | |
password | string | 是 | 密码 |
captcha | string | 否(此操作错误3次以上为必填) | 图形验证码 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
手机号已存在时登录,否则注册
接口名:loginBySms
接口形式
await uniIdCo.loginBySms({
mobile,
code,
captcha,
inviteCode
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
mobile | string | 是 | 手机号 |
code | string | 是 | 短信验证码 |
captcha | string | 否(此操作错误3次以上为必填) | 图形验证码 |
inviteCode | string | 否 | 邀请码,仅注册时生效 |
两小时内登录失败3次的用户必填图形验证码,如果客户端没有使用uni-id-pages,可以参考uni-id-pages验证码登录页面的相关逻辑。
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
接口名:loginByWeixinMobile
接口形式
await uniIdCo.loginByWeixinMobile({
phoneCode,
inviteCode
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
phoneCode | string | 是 | getPhoneNumber 事件回调获取到动态令牌code |
inviteCode | string | 否 | 邀请码,仅注册时生效 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
注意
手机号已存在时登录,否则注册
接口名:loginByUniverify
接口形式
await uniIdCo.loginByUniverify({
access_token,
openid,
inviteCode
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
access_token | string | 是 | 一键登录客户端返回的access_token |
openid | string | 是 | 一键登录客户端返回的openid |
inviteCode | string | 否 | 邀请码,仅注册时生效 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
微信账号已存在时登录,否则注册
接口名:loginByWeixin
接口形式
await uniIdCo.loginByWeixin({
code,
inviteCode
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
code | string | 是 | uni.login 接口返回的code参数 |
inviteCode | string | 否 | 邀请码,仅注册时生效 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
注意
uni-id-pages 1.0.8
及更高版本在存储openid时会同时存储一份以当前应用的Appid(manifest.json内的DCloud AppId)为key的openid,见下方关于openid的说明。uni-id-pages 1.0.8
及以上版本会使用uni-open-bridge-common保存session_key
(微信小程序登录)、access_token
(微信公众号登录、微信App登录)这些信息,但是为了兼容旧版逻辑仍在用户表存储了一份副本。详细说明参考:自动保存用户sessionKey、accessToken等信息uni-id-pages 1.0.7
及之前的版本会将微信的openid存为如下格式
{
"_id": "xx",
"wx_openid": {
"mp": "weixin-openid-demo"
}
}
可以看到如果存在多个微信小程序应用连接一个uniCloud后台且关联同一个账号,此时只能存储一个小程序的openid。
在uni-id-pages 1.0.8
版本对此进行了调整修正,多个DCloud Appid可以对应不同的微信openid。以Appid__UNI_123456
为例,openid会在数据库内存储为以下形式:
{
"_id": "xx",
"wx_openid": {
"mp": "weixin-openid-demo",
"mp___UNI_123456": "weixin-openid-demo",
}
}
QQ账号已存在时登录,否则注册
接口名:loginByQQ
接口形式
await uniIdCo.loginByQQ({
code,
accessToken,
inviteCode
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
code | string | 否 | QQ小程序uni.login 返回的code参数 |
accessToken | string | 否 | APP端QQ登录返回的accessToken参数 |
accessTokenExpired | number | 否 | accessToken过期时间,由APP端QQ登录返回的expires_in参数 |
inviteCode | string | 否 | 邀请码,仅注册时生效 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
注意
uni-id-pages 1.0.8
及更高版本在存储openid时会同时存储一份以当前应用的Appid(manifest.json内的DCloud AppId)为key的openid,见下方关于openid的说明。uni-id-pages 1.0.8
及以上版本会使用uni-open-bridge-common保存session_key(QQ小程序登录)、access_token(QQ App登录)这些信息,但是为了兼容旧版逻辑仍在用户表存储了一份副本。详细说明参考:自动保存用户sessionKey、accessToken等信息关于openid的说明
uni-id-pages 1.0.7
及之前的版本会将QQ的openid以以下形式存储
{
"_id": "xx",
"qq_openid": {
"mp": "weixin-openid-demo"
}
}
可以看到如果存在多个QQ小程序关联同一个账号,这时候只能存储一个小程序的openid,在uni-id-pages 1.0.8
版本对此进行了调整以Appid__UNI_123456
为例,openid会在数据库内存储为以下形式
{
"_id": "xx",
"qq_openid": {
"mp": "weixin-openid-demo",
"mp___UNI_123456": "weixin-openid-demo",
}
}
支付宝账号已存在时登录,否则注册
接口名:loginByAlipay
接口形式
await uniIdCo.loginByAlipay({
code,
inviteCode
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
code | string | 是 | 支付宝小程序uni.login 返回的code参数 |
inviteCode | string | 否 | 邀请码,仅注册时生效 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
苹果账号已存在时登录,否则注册
接口名:loginByApple
接口形式
await uniIdCo.loginByApple({
identityToken,
nickname,
inviteCode
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
identityToken | string | 是 | App端苹果登录返回的identityTokenc参数 |
nickname | string | 否 | 昵称 |
inviteCode | string | 否 | 邀请码,仅注册时生效 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
接口名:logout
接口形式
await uniIdCo.logout()
参数说明
无
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
调用此接口后用户status将会设置为注销状态,需要注意的是目前token不会自动失效,后续会引入redis解决此问题。如果不需要此功能建议手动修改代码。
接口名:closeAccount
接口形式
await uniIdCo.closeAccount()
参数说明
无
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
接口名:getSupportedLoginType
接口形式
await uniIdCo.getSupportedLoginType()
参数说明
无
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
supportedLoginType | array | 支持的登录方式列表,见下方说明 |
supportedLoginType
登录方式 | 说明 |
---|---|
username-password | 用户名密码登录 |
mobile-password | 手机号密码登录 |
email-password | 邮箱密码登录 |
mobile-code | 手机号验证码登录 |
univerify | App一键登录 |
weixin | 微信登录 |
QQ登录 | |
apple | 苹果登录 |
alipay | 支付宝登录 |
接口名:bindMobileBySms
接口形式
await uniIdCo.bindMobileBySms({
mobile,
code,
captcha
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
mobile | string | 是 | 手机号码 |
code | string | 是 | 短信验证码 |
captcha | string | 否(此操作错误3次以上为必填) | 图形验证码 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
注意
接口名:bindMobileByUniverify
接口形式
await uniIdCo.bindMobileByUniverify({
openid,
access_token
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
openid | string | 是 | 客户端一键登录返回的openid参数 |
access_token | string | 是 | 客户端一键登录返回的access_token参数 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
注意
使用此接口时务必注意
微信小程序对获取手机号的接口进行了安全升级,自 uni-id-co@1.0.25
以上版本开始,支持getPhoneNumber事件回调的动态口令code
,同时为了向下兼容保留encryptedData
与 iv
参数,建议开发者升级,以增强小程序安全性。
微信小程序的规则是客户端应先使用checkSession接口检测上次获取的sessionKey是否仍有效。
如果有效则直接使用上次存储的sessionKey即可,如果无效应重新调用login接口再次刷新sessionKey。
微信小程序登录、绑定小程序微信账号时会自动更新用户的sessionKey。
接口名:bindMobileByMpWeixin
接口形式
// uni-id-co >= 1.0.25
await uniIdCo.bindMobileByMpWeixin({
code
})
// uni-id-co < 1.0.25
await uniIdCo.bindMobileByMpWeixin({
encryptedData,
iv
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
encryptedData | string | 是 | 微信小程序获取手机号返回的encryptedData参数 |
iv | string | 是 | 微信小程序获取手机号返回的iv参数 |
code | string | 是 | 微信小程序获取手机号返回的code参数; uni-id-co >= 1.0.25支持 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
注意
接口名:bindWeixin
接口形式
await uniIdCo.bindWeixin({
code
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
code | string | 是 | 微信登录返回的code参数 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
注意
接口名:bindQQ
接口形式
await uniIdCo.bindQQ({
code,
accessToken
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
code | string | 否 | QQ小程序登录返回的code参数 |
accessToken | string | 否 | App端QQ登录返回的accessToken参数 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
注意
接口名:bindAlipay
接口形式
await uniIdCo.bindAlipay({
code
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
code | string | 是 | 支付宝小程序登录返回的code参数 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
注意
接口名:bindApple
接口形式
await uniIdCo.bindApple({
identityToken
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
identityToken | string | 是 | 苹果登录返回的identityToken参数 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
注意
如账号只有一个第三方登录方式时,需绑定手机号后在解绑。
接口名:unbindWeixin
接口形式
await uniIdCo.unbindWeixin()
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
接口名:unbindQQ 接口形式
await uniIdCo.unbindQQ()
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
接口名:unbindAlipay 接口形式
await uniIdCo.unbindAlipay()
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
接口名:unbindApple 接口形式
await uniIdCo.unbindApple()
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
接口名:setPwd
接口形式
await uniIdCo.setPwd({
code,
captcha,
password
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
code | string | 是 | 手机验证码 |
captcha | string | 否(此操作错误3次以上为必填) | 图形验证码 |
password | string | 是 | 密码 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
接口名:updatePwd
接口形式
await uniIdCo.updatePwd({
oldPassword,
newPassword
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
oldPassword | string | 是 | 旧密码 |
newPassword | string | 是 | 新密码 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
注意
接口名:resetPwdBySms
接口形式
await uniIdCo.resetPwdBySms({
mobile,
code,
password,
captcha
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
mobile | string | 是 | 手机号 |
code | string | 是 | 短信验证码 |
password | string | 是 | 密码 |
captcha | string | 否(此操作错误3次以上为必填) | 图形验证码 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
接口名:resetPwdByEmail
接口形式
await uniIdCo.resetPwdByEmail({
email,
code,
password,
captcha
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
string | 是 | 邮箱 | |
code | string | 是 | 邮箱验证码 |
password | string | 是 | 密码 |
captcha | string | 否(此操作错误3次以上为必填) | 图形验证码 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
接口名:getAccountInfo
接口形式
await uniIdCo.getAccountInfo()
参数说明
无
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
isUsernameSet | boolean | 是否已有用户名 |
isNicknameSet | boolean | 是否已有昵称 |
isPasswordSet | boolean | 是否已设置密码 |
isMobileBound | boolean | 手机号是否已绑定 |
isEmailBound | boolean | 邮箱是否已绑定 |
isWeixinBound | boolean | 微信是否已绑定 |
isQQBound | boolean | QQ是否已绑定 |
isAlipayBound | boolean | 支付宝是否已绑定 |
isAppleBound | boolean | 苹果账号是否已绑定 |
接口名:acceptInvite
接口形式
await uniIdCo.acceptInvite({
inviteCode
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
inviteCode | string | 是 | 邀请码 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
注意
接口名:getInvitedUser
接口形式
await uniIdCo.getInvitedUser({
level,
limit,
offset,
needTotal
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
level | number | 是 | 邀请用户层级,例,值为1时表示自己直接邀请的用户 |
limit | number | 否 | 本次请求返回的数量,默认:20 |
offset | number | 否 | 列表偏移数值,默认:0,通过和limit结合进行分页 |
needTotal | boolean | 否 | 是否返回总数,默认:false |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
注意
接口名:getRealNameInfo
接口形式
await uniIdCo.getRealNameInfo({
decryptData
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
decryptData | boolean | 否 | 是否解密数据;默认:true |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
type | number | 用户类型:0 个人用户 1 企业用户 |
authStatus | number | 认证状态:0 未认证 1 等待认证 2 认证通过 3 认证失败 |
realName | string | 姓名(脱敏);用户类型为 0 时返回 |
identity | string | 身份证号码(脱敏);用户类型为 0 时返回 |
注意
在uni-id-pages中默认启用敏感数据加解密,如果开发者没有使用uni-id提供的敏感信息加密功能,请将decryptData
参数改为false
,返回原始信息
接口名:createCaptcha
接口形式
await uniIdCo.createCaptcha({
scene
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
scene | string | 是 | 图形验证码使用场景,务必确保使用验证码的场景和生成验证码时传的场景参数相匹配,否则会校验不通过,参考:图形验证码场景 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
captchaBase64 | string | 验证码:base64 格式 |
接口名:refreshCaptcha
接口形式
await uniIdCo.refreshCaptcha({
scene
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
scene | string | 是 | 图形验证码使用场景,参考:图形验证码场景 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
captchaBase64 | string | 验证码:base64 格式 |
发送短信功能需要以下前置工作
接口名:sendSmsCode
接口形式
await uniIdCo.sendSmsCode({
mobile,
captcha,
scene
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
mobile | string | 是 | 手机号码 |
captcha | string | 是 | 图形验证码 |
scene | string | 是 | 短信验证码使用场景,务必确保使用验证码的场景和发送验证码时传的场景参数相匹配,否则会校验不通过,参考:短信验证码使用场景 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
接口名:sendEmailCode
接口形式
await uniIdCo.sendEmailCode({
email,
captcha,
scene
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
string | 是 | 邮箱 | |
captcha | string | 是 | 图形验证码 |
scene | string | 是 | 使用场景,参考:手机、邮箱验证码使用场景 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
接口名:refreshToken
接口形式
await uniIdCo.refreshToken()
参数说明
无
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
如未使用uni-push 2.0
无需关注此接口。此接口用于更新uni-id-device表的unipush_clientid字段,用于按客户端、用户等维度推送消息
接口名:setPushCid
接口形式
await uniIdCo.setPushCid({
pushClientId
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
pushClientId | string | 是 | 客户端获取的uni-push对应的clientId |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
此接口用于微信小程序端安全网络的握手,安全网络相关文档请参考:安全网络
一般无需通过uniCloud.importObject方式调用,在客户端调用uniCloud.initSecureNetworkByWeixin()
时会通过此接口获取会话相关信息。
此接口会将会话信息存储在opendb-open-data
表内,如果在initSecureNetworkByWeixin
方法内传递了callLoginByWeixin: true
会在存储会话信息的同时执行一次uni-id-co的loginByWeixin
方法
接口名:addUser
接口形式
await uniIdCo.addUser({
username,
password,
authorizedApp,
nickname,
role
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
username | string | 是 | 用户名 |
password | string | 是 | 密码 |
authorizedApp | Array<string> | 否 | 允许登录的app列表 |
nickname | string | 否 | 昵称 |
role | Array<string> | 否 | 用户角色 |
mobile | string | 否 | 手机号 |
string | 否 | 邮箱 | |
tags | array | 否 | 用户标签 |
status | number | 否 | 用户状态,参考:用户状态 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
接口名:updateUser
接口形式
await uniIdCo.updateUser({
uid,
username,
password,
nickname,
authorizedApp,
role,
mobile,
email,
tags,
status
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
uid | string | 是 | 要更新的用户id |
username | string | 是 | 用户名 |
password | string | 否 | 密码 |
nickname | string | 否 | 昵称 |
authorizedApp | Array<string> | 否 | 允许登录的app列表 |
role | Array<string> | 否 | 用户角色 |
mobile | string | 否 | 手机号 |
string | 否 | 邮箱 | |
tags | array | 否 | 用户标签 |
status | number | 否 | 用户状态,参考:用户状态 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
接口名:authorizeAppLogin
接口形式
await uniIdCo.authorizeAppLogin({
uid,
appId
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
uid | string | 是 | 用户id |
appId | string | 是 | 允许登录应用的DCloud AppId |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
注意
接口名:removeAuthorizedApp
接口形式
await uniIdCo.removeAuthorizedApp({
uid,
appId
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
uid | string | 是 | 用户id |
appId | string | 是 | 禁止登录的应用的DCloud AppId |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
注意
接口名:setAuthorizedApp
接口形式
await uniIdCo.setAuthorizedApp({
uid,
appIdList
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
uid | string | 是 | 用户id |
appIdList | Array<String> | 是 | 允许登录的应用对应的DCloud AppId列表 |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
注意
适合自己有用户系统,同时需要使用依赖UniId的业务,将自身系统的用户账号导入uniId,为其创建一个对应uniId的账号,使得该账号可以使用依赖uniId的系统及功能。 由于此方案的接口不需要密码验证,开发者务必要保证接口只能在服务端调用,同时要求在请求时计算签名来保证安全。
联登相关接口只支持HTTP方式调用,调用时需要携带鉴权签名值,查看URL化请求鉴权签名计算
外部用户注册,注册成功后,uni-id 返回 uid 与 用户 token ,请务必在自身系统中维护好 uid 与 token。
接口地址
POST /your-uni-id-co-path/externalRegister
HTTP 示例
POST /your-uni-id-co-path/externalRegister HTTP/1.1
Host: xxx.com
uni-id-nonce: xxxxxxx
uni-id-timestamp: 1676882808550
uni-id-signature: 11c965267a4a02c6978949c7135215b0a75aea22b2b84ed491e792365c8269efa
Content-Type: application/json
Cache-Control: no-cache
{"externalUid": "test externalUid", "nickname": "张三", "avatar": "xxxxxxx", "gender": 0}
注意
Request Body 说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
externalUid | string | 是 | 自身系统的用户id,必须保证唯一性。 |
nickname | string | 否 | 用户昵称 |
avatar | string | 否 | 用户头像 |
gender | number | 否 | 用户性别;0 未知 1 男性 2 女性 |
Response Body 说明
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
externalUid | string | 自身系统的用户id |
uid | string | uni-id体系的用户Id |
nickname | string | 用户昵称 |
avatar | string | 用户头像 |
gender | string | 用户性别;0 未知 1 男性 2 女性 |
外部用户登录,用于获取用户token
接口地址
POST /your-uni-id-co-path/externalLogin
HTTP 示例
POST /your-uni-id-co-path/externalLogin HTTP/1.1
Host: xxx.com
uni-id-nonce: xxxxxxx
uni-id-timestamp: 1676882808550
uni-id-signature: 11c965267a4a02c6978949c7135215b0a75aea22b2b84ed491e792365c8269efa
Content-Type: application/json
Cache-Control: no-cache
{"externalUid": "test externalUid"}
注意
Request Body 说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
uid | string | 否 | uni-id体系的用户Id;与externalUid 二选一 |
externalUid | string | 否 | 自身系统的用户id;与 uid 二选一 |
Response Body 说明
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
newToken | object | token信息 |
|- token | string | token |
|- tokenExpired | string | token过期时间 |
uid | string | uni-id体系的用户Id |
外部用户修改账号信息,如用户在自身系统内修改了用户信息后,通过此接口同步修改uni-id中用户信息。
接口地址
POST /your-uni-id-co-path/updateUserInfoByExternal
HTTP 示例
POST /your-uni-id-co-path/updateUserInfoByExternal HTTP/1.1
Host: xxx.com
uni-id-nonce: xxxxxxx
uni-id-timestamp: 1676882808550
uni-id-signature: 11c965267a4a02c6978949c7135215b0a75aea22b2b84ed491e792365c8269efa
Content-Type: application/json
Cache-Control: no-cache
{"externalUid": "test externalUid", "nickname": "张三"}
注意
Request Body 说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
uid | string | 否 | uni-id体系的用户Id;与externalUid 二选一 |
externalUid | string | 否 | 自身系统的用户id;与 uid 二选一 |
username | string | 否 | 用户名 |
password | string | 否 | 密码 |
nickname | string | 否 | 昵称 |
authorizedApp | Array<string> | 否 | 允许登录的app列表 |
role | Array<string> | 否 | 用户角色 |
mobile | string | 否 | 手机号 |
string | 否 | 邮箱 | |
tags | array | 否 | 用户标签 |
status | number | 否 | 用户状态,参考:用户状态 |
avatar | string | 否 | 用户头像 |
gender | number | 否 | 用户性别;0 未知 1 男性 2 女性 |
Response Body 说明
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
实人认证相关功能建议或问题,可以加入uni-im交流群进行讨论,点此加入
基于实人认证服务实现,实现用户刷脸核验真实身份,完成实名认证。
uni-id-pages
已内置实人认证前端页面与云端云对象,了解如在uni-id-pages
中使用。
接口名:getFrvCertifyId
接口形式
await uniIdCo.getFrvCertifyId({
realName,
idCard,
metaInfo
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
realName | string | 是 | 用户真实姓名 |
idCard | string | 是 | 用户身份证号码 |
metaInfo | String | 是 | 客户端初始化时返回的metaInfo |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
certifyId | object | 认证Id;用于客户端调用认证接口及云函数获取认证结果 |
接口名:getFrvAuthResult
接口形式
await uniIdCo.getFrvAuthResult({
certifyId
})
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
certifyId | string | 是 | 认证Id |
返回值
参数名 | 类型 | 说明 |
---|---|---|
errCode | string|number | 错误码 |
errMsg | string | 错误信息 |
authStatus | number | 认证状态:0 未认证 1 等待认证 2 认证通过 3 认证失败 |
realName | string | 姓名(脱敏);敏感信息加密参考 |
identity | string | 身份证号码(脱敏);敏感信息加密参考 |
uni-id-co将validator实例挂载在云对象的this上,在uni-id-co/index.obj.js获取validator实例后可以使用validator实例的mixin方法覆盖或者新增校验规则。
接口形式:validator.mixin(String type, Function handler)
。其中type为规则类型(字符串),handler为校验函数
// uni-id-co/index.obj.js
const {
Validator
} = require('./common/validator.js')
module.exports = {
_before () {
this.validator = new Validator()
/**
* 示例:覆盖密码验证规则
*/
this.validator.mixin('password', function (password) {
if (typeof password !== 'string' || password.length < 10) {
// 调整为密码长度不能小于10
return {
errCode: ERROR.INVALID_PASSWORD
}
}
})
/**
* 示例:新增验证规则
*/
this.validator.mixin('timestamp', function (timestamp) {
if (typeof timestamp !== 'number' || timestamp > Date.now()) {
return {
errCode: ERROR.INVALID_PARAM
}
}
})
// // 新增规则同样可以在数组验证规则中使用
this.validator.valdate({
timestamp: 123456789
}, {
timestamp: 'timestamp'
})
this.validator.valdate({
timestampList: [123456789, 123123123123]
}, {
timestampList: 'array<timestamp>'
})
// // 甚至更复杂的写法
this.validator.valdate({
timestamp: [123456789, 123123123123]
}, {
timestamp: 'timestamp|array<timestamp>'
})
}
}
服务端uni-id
的密钥信息统一在uni-config-center
中配置,路径:uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json
以下简称:uni-id配置文件
,完整的配置信息详情查看
一键登录是运营商提供的、比短信验证码更方便、更安全、更便宜的方案。详见。
manifest.json
-->App模块配置
-->OAuth(登录鉴权)
-->一键登录
,点击后面的开通配置
,在随后打开的web界面中,同意协议,并点击充值按钮充值。如只是测试,可以只充值1元钱。如果你已经确定包名,则可以在web界面点击“添加应用”,提交审核。这个是正式打包必须的。真机运行可以跳过此环节。uni-id-pages已全面支持:app、小程序、web(uni-id-pages 版本号1.0.8起),三端的微信登录。
微信将应用分为4类:
这里的网站应用
和公众帐号
都是给web应用,接入微信登录功能。但有如下区别:
宿主环境 | 所属类型 | 登录方式 |
---|---|---|
微信APP | 公众帐号 | 网页授权登录 |
普通浏览器 | 网站应用 | 手机微信扫码登录 |
根据你的需求开通相应平台账户即可。
注意
如果你的应用有多端,实现同一个用户在公众号、小程序、APP、官方网站等不同场景里的身份统一识别、信息同步和行为跟踪
(详情参考:“UnionID关联”功能介绍及运营建议)
就需要将小程序
、公众帐号
绑定到同一个微信开放平台账号
下。
管理中心
-> 选择公众号/小程序
-> 点击绑定公众号/小程序
manifest.json
->App模块配置
-> OAuth(登录鉴权)
-> 勾选微信登录
-> 填写appid
、ios平台通用链接
。manifest.json
-> 微信小程序配置
-> 填写微信小程序AppID/uni_modules/uni-id-pages/config.js
-> appid
-> weixin
在h5
节点配置微信公众号的appid,web
节点配置微信开放平台创建的网站应用appiduni-id
的密钥信息统一在uni-config-center
中配置,路径:uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json
,完整的配置信息详情查看登录的流程为:
uni-id-co
云对象的loginByWeiXin
方法,得到token
完成登录appid
说明:微信app内打开的网页,为公众号的appid。其他场景则为在微信开放平台
创建的网站应用
的appid。redirect_uri
说明:进入授权页面后返回的网站链接,此链接的域名需要先在服务后台配置,详情查看:回调域名的配置示例代码已经在uni-id-pages插件中提供。
手机微信扫码登录 微信开放平台 -> 管理中心 -> 网站应用 -> 选择对应的应用名称,点击查看 -> 开发信息,点击修改 -> 填写授权回调域
基于微信公众号auth登录 登录微信公众号 -> 设置与开发 -> 公众号设置 -> 设置网页授权域名
回调域名,必须接入外网已经备案的URL地址,不然本地没法进行调试,你可以做内网穿透,映射生成一个外网URL地址来进行回调测试。但是那样比较麻烦,这里我们介绍一种基于HBuilderX本地启动一个Web Server进行调试的方法。
manifest.json
-> H5配置
-> 端口
-> 输入80
注意:mac系统中,非root用户是无法使用小于1024的常用端口的。解决方案打开
终端
,cd 到 HBuilderX安装目录(默认是Applications目录,执行cd /Applications
),然后执行sudo ./HBuilderX.app/Contents/MacOS/HBuilderX
输入开机密码,再按回车,此时会以root用户权限重新打开HBuilderX;
如果没有启动80端口而是81等,说明你的端口被占用了。你有两个办法1.关闭可疑程序,或直接重启电脑 2.命令行关闭占用的端口详情查看
C:\Windows\System32\drivers\etc
。mac系统:/etc/
用HBuilderX打开hosts文件,在末尾添加一行 127.0.0.1 你的域名
保存即可。
此时访问域名,如果就能看到和你的项目运行到浏览器一样的效果,说明已经成功了。manifest.json
--> App模块配置
--> OAuth(登录鉴权)勾选苹果登录
,IOS苹果授权登录参考文档。如不发布到Appstore,不需要配置此项uni-id配置文件
--> app
--> oauth
--> apple
填写bundleId
。manifest.json
--> App常用其他设置
--> iOS设置
--> 关联域(Associated Domains)
填写配置 参考教程。如不发布到Appstore,不需要配置此项为了方便开发调试,uni-id-pages
未配置短信登录时,自动启动测试模式;直接使用:123456作为短信验证码即可。
uni-id配置文件
--> service
--> sms
填写相关密钥信息。在HBuilderX 3.5之前,DCloud提供了一个公共模块uni-id(注意别和uni-id-common混淆)和一个示例性云函数uni-id-cf(集成在uni-starter和uni-admin中)。
老的公共模块uni-id是一个大而全的账户管理公共模块,体积太大,不适合被其他云函数引用。比如某个业务云函数需要校验用户token,引用的uni-id公共模块还包含了忘记密码的代码,很浪费资源。
从HBuilder 3.5起,uni-id和uni-id-cf都将被淘汰,不再更新。老的公共模块uni-id被拆开,变成了uni-id-common公共模块和uni-id-co云对象。
uni-id-common很精简,只包括token和权限,适合被所有云函数引用。
uni-id-co则是一个更加比uni-id-cf更完善和规范的用户管理的云对象。
然后DCloud推出了uni-id-pages
。
目前uni-starter和uni-admin仍然使用老版uni-id和uni-id-cf,官方正在升级中,将其中的用户管理升级为uni-id-pages。
此次升级做了大幅改动,多数接口自公共模块中移除,改为由uni-id-co实现。仅创建token、刷新token、校验token接口保留在uni-id公共模块内。除接口调整外,uni-id体系(包含uni-id公共模块、uni-id-co)还有以下调整:
preferedAppPlatform
、preferedWebPlatform
不再生效,uni-id内部会使用app
代替app-plus
、使用web
代替h5
字段名调整
相关说明字段名调整
相关说明uni-id升级为uni-id-co + uni-id-common需要对个别字段进行重命名,直接运行下面的云函数即可重命名改动的字段。另外还需要修改一下索引,删除旧字段的索引,增加新字段的索引。建议在凌晨或其他低峰段操作,避免数据库操作耗时过久影响线上用户,如果有停服逻辑也可对系统短暂停服再操作。(在实际数据测试中,50000条用户记录重命名字段耗时约5秒钟)
'use strict';
const db = uniCloud.database()
const dbCmd = db.command
exports.main = async (event, context) => {
await db.collection('uni-id-users').update({
wx_openid: {
'app-plus': dbCmd.rename('wx_openid.app'), // app端微信openid
'mp-weixin': dbCmd.rename('wx_openid.mp'), // 小程序端微信openid
'h5-weixin': dbCmd.rename('wx_openid.h5'), // 微信公众号端微信openid
'h5-web': dbCmd.rename('wx_openid.web') // web端微信openid
},
qq_openid: {
'app-plus': dbCmd.rename('qq_openid.app'), // app端QQ openid
'mp-qq': dbCmd.rename('qq_openid.mp') // 小程序端QQ openid
}
})
return {}
};
uni-id-co@1.1.10
及以上版本支持使用uni-cloud-s2s
进行请求签名验证,uni-cloud-s2s
使用方式详见
uni-id-co
请求鉴权签名与uni-cloud-s2s
不能同时存在,如果存在uni-cloud-s2s
,则会优先使用uni-cloud-s2s
进行请求签名验证
uni-id-co 在URL化请求时,会对以下 API 进行调用鉴权验证,
在调用 API 时,开发者需要使用请求鉴权密钥(详见配置文件)requestAuthSecret
按照 uni-id 的约定方式对请求中的关键数据进行签名值计算,
并将签名值添加到Header请求头的 uni-id-signature
参数中传给 uni-id 进行签名验证,uni-id 会对接收到数据进行签名值计算,
并与接收到的请求签名值进行比对,如果签名值不一致,则视为无效签名,将拒绝本次请求。
需要进行签名的API列表
API |
---|
externalRegister |
externalLogin |
参数名称 | 类型 | 是否必须 | 描述 |
---|---|---|---|
uni-id-nonce | string | 是 | 随机字符串 |
uni-id-timestamp | string | 是 | 当前时间戳; 单位毫秒 |
uni-id-signature | string | 是 | 请求鉴权签名; 签名算法见下 |
如下为某请求体参数,介绍如何进行签名:
{
"clientInfo": {
"appId": "__test__"
},
"uniIdToken": "xxxxxx",
"params": {
"foo": 1,
"bar": 2,
"foo_bar": 3,
"foobar": 4
}
}
params
参数,但除去array与object类型的参数),根据参数名称的ASCII码表的顺序排序。如:foo:1, bar:2, foo_bar:3, foobar:4
排序后的顺序是 bar:2, foo:1, foo_bar:3, foobar:4
key1=value1&key2=value2
格式拼装在一起,根据上面的示例得到的结果为:bar=2&foo=1&foo_bar=3&foobar=4
HmacSHA256(timestamp + bar=2&foo=1&foo_bar=3&foobar=4, requestAuthSecret + nonce)
Hex.stringify(Utf8.parse("helloworld")) = "68656C6C6F776F726C64"
const crypto = require('crypto')
class Sign {
constructor (requestAuthSecret) {
this.requestAuthSecret = requestAuthSecret
}
getSignature (params, nonce, timestamp) {
const paramsStr = this.getParamsString(params)
const signature = crypto.createHmac('sha256', `${this.requestAuthSecret}${nonce}`).update(`${timestamp}${paramsStr}`).digest('hex')
return signature.toUpperCase()
}
getParamsString (params) {
return Object.keys(params)
.sort()
.filter(item => typeof params[item] !== "object")
.map(item => `${item}=${params[item]}`)
.join('&')
}
}
const requestAuthSecret = "testSecret"
const nonce = Math.random().toString(36).substring(2)
const timestamp = Date.now()
const params = {
foo: 1,
bar: 2,
foo_bar: 3,
foobar: 4
}
const sign = new Sign(requestAuthSecret)
const signature = sign.getSignature(params, nonce, timestamp)
console.log("nonce: ", nonce)
console.log("timestamp: ", timestamp)
console.log("signature: ", signature)
<?php
class Sign {
private $requestAuthSecret;
public function __construct ($requestAuthSecret) {
$this->requestAuthSecret = $requestAuthSecret;
}
public function getSignature ($params, $nonce, $timestamp) {
$paramsStr = $this->getParamsString($params);
$signature = hash_hmac('sha256', ((string)$timestamp . $paramsStr), ($this->requestAuthSecret . $nonce));
return strtoupper($signature);
}
private function getParamsString ($params) {
ksort($params);
$paramsStr = [];
foreach($params as $key=>$value){
if (gettype($value) == "array" || gettype($value) == "object") {
continue;
}
array_push($paramsStr, $key . '=' . $value);
}
return join('&', $paramsStr);
}
}
$requestAuthSecret = "testSecret";
$nonce = sprintf("%d", rand());
$timestamp = time() * 1000;
$params = [
"foo" => 1,
"bar" => 2,
"foobar" => 4,
"foo_bar" => 3,
];
$sign = new Sign($requestAuthSecret);
$signature = $sign->getSignature($params, $nonce, $timestamp);
print_r("nonce: " . $nonce . PHP_EOL);
print_r("timestamp: " . $timestamp . PHP_EOL);
print_r("signature: " . $signature);
import hmac
import hashlib
import time
class Sign:
def __init__(self, requestAuthSecret):
self.requestAuthSecret = requestAuthSecret
def get_signature (self, params, nonce, timestamp):
params_str = self.get_params_string(params)
signature = hmac.new(bytes("%s%s" % (self.requestAuthSecret, nonce), 'utf-8'), bytes("%s%s" % (timestamp, params_str), 'utf-8'), digestmod = hashlib.sha256).hexdigest().upper()
return signature
def get_params_string(self, params):
params_str = []
for k in sorted(params):
if isinstance(params[k], (list, dict)):
continue
params_str.append("%s=%s" % (k, params[k]))
return "&".join(params_str)
if __name__ == "__main__":
requestAuthSecret = "testSecret"
nonce = "xxxxxxx"
timestamp = int(round(time.time() * 1000))
params = {
"foo": 1,
"bar": 2,
"foobar": 4,
"foo_bar": 3,
}
sign = Sign(requestAuthSecret)
signature = sign.get_signature(params, nonce, timestamp)
print(nonce, timestamp, signature)
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"sort"
"strconv"
"strings"
"time"
)
type Sign struct {
requestAuthSecret string
}
func (sign Sign) getSignature(params map[string]string, nonce string, timestamp int64) string {
paramsStr := sign.getParamsString(params)
mac := hmac.New(sha256.New, []byte(sign.requestAuthSecret+nonce))
mac.Write([]byte(strconv.Itoa(int(timestamp)) + paramsStr))
hexSignature := mac.Sum(nil)
signature := hex.EncodeToString(hexSignature)
return strings.ToUpper(signature)
}
func (sign Sign) getParamsString(params map[string]string) string {
keys := make([]string, 0, len(params))
for k := range params {
keys = append(keys, k)
}
sort.Strings(keys)
var paramsStr string = ""
i := 0
for _, k := range keys {
v := params[k]
if i != 0 {
paramsStr += "&"
}
paramsStr += k
paramsStr += "="
paramsStr += v
i++
}
return paramsStr
}
func main() {
requestAuthSecret := "testSecret"
nonce := "xxxxxxx"
timestamp := time.Now().UnixMilli()
params := map[string]string{
"foo": "1",
"bar": "2",
"foo_bar": "3",
"foobar": "4",
}
sign := Sign{
requestAuthSecret: requestAuthSecret,
}
signature := sign.getSignature(params, nonce, timestamp)
result := fmt.Sprintf("nonce: %s, timestamp: %d, signature: %s", nonce, timestamp, signature)
fmt.Println(result)
}
import java.util.HashMap;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Arrays;
import java.util.Map;
public class Sign {
static String requestAuthSecret = "testSecret";
public static void main(String[] args) {
String nonce = "xxxxxx";
long timestamp = System.currentTimeMillis();
Map<String, String> params = new HashMap<String, String>();
params.put("foo", "1");
params.put("bar", "2");
params.put("foo_bar", "4");
params.put("foobar", "3");
String signature = getSignature(params, nonce, timestamp);
System.out.println("nonce: " + nonce);
System.out.println("timestamp: " + timestamp);
System.out.println("signature: " + signature);
}
public static String getSignature (Map<String, String> params, String nonce, long timestamp) {
String paramsStr = getParamsString(params);
String algorithm = "HmacSHA256";
Mac hmacSha256;
String digestHexString = null;
try {
hmacSha256 = Mac.getInstance(algorithm);
String key = new StringBuilder().append(requestAuthSecret).append(nonce).toString();
String message = new StringBuilder().append(Long.toString(timestamp)).append(paramsStr).toString();
byte[] keyBytes = key.getBytes("utf-8");
byte[] messageBytes = message.getBytes("utf-8");
hmacSha256.init(new SecretKeySpec(keyBytes, 0, keyBytes.length, algorithm));
byte[] digestBytes = hmacSha256.doFinal(messageBytes);
digestHexString = byteArrayToHexString(digestBytes);
} catch (Exception e) {
System.out.println("[ERROR] not supposed to happen: " + e.getMessage());
}
return digestHexString.toUpperCase();
}
private static String getParamsString (Map<String, String> params) {
String[] keys = params.keySet().toArray(new String[0]);
Arrays.sort(keys);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < keys.length; i ++) {
String key = keys[i];
if (i != 0) {
sb.append("&");
}
sb.append(key).append("=").append(params.get(key));
}
return sb.toString();
}
private static String byteArrayToHexString(byte[] b) {
StringBuilder hs = new StringBuilder();
String stmp;
for (int n = 0; b!=null && n < b.length; n++) {
stmp = Integer.toHexString(b[n] & 0XFF);
if (stmp.length() == 1)
hs.append('0');
hs.append(stmp);
}
return hs.toString();
}
}