uni-id-common 模块
概述
uni-id-common 是 uni-id 体系中用于 token 管理的公共模块。从 HBuilderX 3.5.0+ 开始支持。
旧版本的 uni-id 公共模块是一个大而全的公共模块,不适用于被众多云函数引用。新版的 uni-id-common 仅包含 token 校验、生成及刷新功能,而用户注册、登录、忘记密码等实现都移到了 uni-id-co 云对象中。这样不仅减小了公共模块的体积,也简化了学习成本。
从 HBuilderX 3.5 起,新建 uniCloud 项目时,会自动加载 uni-id-common 依赖,默认内置在每个项目中。
一般开发者无需了解 uni-id-common 公共模块的 API,直接使用 uni-id-pages 云端一体页面模板即可。
API 列表
创建 uni-id 实例
注意:不同于旧版本 uni-id 公共模块,uni-id-common 必须调用此接口创建实例后才可以调用 checkToken 等接口
用法:uniID.createInstance(Object CreateInstanceOptions);
CreateInstanceOptions 内可以传入云函数 context,也可以传入 clientInfo 参数,作用和 context 类似。方便在云对象内获取 clientInfo 后直接传入。
// 云函数代码,传入 context
const uniID = require('uni-id-common')
exports.main = async function(event, context) {
context.APPID = '__UNI__xxxxxxx' // 替换为当前客户端的 APPID
context.PLATFORM = 'web' // 替换为当前客户端的平台类型
context.LOCALE = 'zh-Hans' // 替换为当前客户端的语言代码
const uniIDIns = uniID.createInstance({ // 创建 uni-id 实例
context: context,
// config: {} // 完整 uni-id 配置信息,使用 config.json 进行配置时无需传此参数
})
payload = await uniIDIns.checkToken(event.uniIdToken) // 后续使用 uniIDIns 调用相关接口
if (payload.code) {
return payload
}
}
// 云对象代码传入 clientInfo
const uniID = require('uni-id-common')
module.exports = {
_before() {
const clientInfo = this.getClientInfo()
this.uniID = uniID.createInstance({ // 创建 uni-id 实例,其上方法同 uniID
clientInfo
})
},
refreshToken() {
// ...
// this.uniID.refreshToken()
}
}
为什么需要自行创建 uni-id 实例
默认情况下 uni-id-common 某些接口会自动从全局 context 内获取客户端的 PLATFORM(平台,如:app、h5、mp-weixin)等信息。
在云函数单实例多并发的场景下可能无法正确获取(全局对象会被后面的请求覆盖,可能会导致前面一次请求使用了后面一次请求的 PLATFORM 信息)。因此推荐在开启云函数单实例多并发后,自行为 uni-id 传入 context。
此外云函数 url 化时无法获取客户端信息,也需要使用这种方式将客户端信息传入 uni-id。
token 校验
一个校验客户端发起请求(uniCloud.callFunction)自带的 uniIdToken,获得用户的 uid、token、token 的过期时间、角色、权限的 API。
这是非常高频且重要的 API,通常用于换取操作当前云函数的用户 Id。
思考
如果你并没有服务端开发经验,可能会想:为什么需要通过 token 去换取用户 Id,而不是让客户端直接传递用户 Id 更方便?这里就涉及到安全问题,有一句话叫做:"前端传递的参数都是不可信任的"。比如:你去银行取款,柜台会要求出示你的身份证来证明你是谁,而不是你直接告诉银行柜台你是谁就管用。否则这是一个极大的安全漏洞。综上所述:所有服务端操作涉及账户信息相关内容,都需要使用 token 来获得,而不是使用前端传递的参数。
用法:uniIDIns.checkToken(String token, Object checkTokenOptions)
参数说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| token | String | 是 | 客户端 callFunction 带上的 token |
| options | object | 否 | checkToken 方法的选项 |
| options.autoRefresh | boolean | 否 | 是否需要自动判断刷新 token,默认 true |
说明
- 角色内包含 admin 时返回的 permission 是一个空数组,因此判断一个用户是否有权限时应注意 admin 角色额外进行判断
响应参数
| 字段 | 类型 | 说明 |
|---|---|---|
| errCode | Number|String | 错误码,0 表示成功 |
| message | String | 详细信息 |
| uid | String | 用户 Id,校验成功之后会返回 |
| token | String | 用户 token 快要过期时,新生成的 token,只有在 config 内配置了 tokenExpiresThreshold 的值时才会有此行为 |
| tokenExpired | TimeStamp | 新 token 的过期时间,单位毫秒 |
| role | Array | 用户角色列表 |
| permission | Array | 用户权限列表 |
uni-id 使用 jwt 生成 token,jwt 所生成的 token 包含三部分,其中存储的信息为明文信息,uni-id 只根据 tokenSecret 来校验客户端 token 是否合法。
角色权限将被缓存在 token 中,此举能减少或消除 checkToken 的查库次数(有效节省费用、减少响应时间)
注意:
- 客户端会自动查找 storage 内的 token 在 callFunction 时插入
- HBuilderX 2.9.5+ 客户端允许开发者自行在 callFunction 时传入 uniIdToken,此时不再从 storage 获取 token
- HBuilderX 2.8.0 版本起 token 存储在 storage 内推荐使用使用蛇形
uni_id_token,会在一段时间内兼容驼峰形式uniIdToken
主动刷新 token
新增于 uni-id 3.3.14
用法:uniIDIns.refreshToken(Object RefreshTokenOptions);
参数说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| token | String | 是 | 用户 token |
示例
const {
token,
tokenExpired
} = await uniIDIns.refreshToken({
token: 'xxx'
})
注意
- 刷新 token 时会自动更新 token 内 uid 对应的角色权限
生成 token
用法:uniIDIns.createToken(Object CreateTokenOptions)
参数说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| uid | String | 是 | 用户 Id |
| role | Array | 否 | 指定缓存在 token 内的角色 |
| permission | Array | 否 | 指定缓存在角色内的权限 |
响应参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| token | String | 是 | 生成的 token |
| tokenExpired | Number | 是 | token 过期时间对应的时间戳 |
说明
- 创建 token 时如果未传角色权限会自动获取 uid 对应的角色权限
uni-id-common 完整方法列表
除了上述主要方法外,uni-id-common 还提供了以下方法:
密码相关方法
加密密码
用法:uniIDIns.encryptPwd(String password)
参数说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| password | String | 是 | 需要加密的密码 |
响应参数
| 字段 | 类型 | 说明 |
|---|---|---|
| passwordHash | String | 加密后的密码 |
示例
const passwordHash = await uniIDIns.encryptPwd('password123')
校验密码
用法:uniIDIns.checkPwd(String password, String passwordHash)
参数说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| password | String | 是 | 需要校验的密码 |
| passwordHash | String | 是 | 加密后的密码 |
响应参数
| 字段 | 类型 | 说明 |
|---|---|---|
| isMatch | Boolean | 密码是否匹配 |
示例
const isMatch = await uniIDIns.checkPwd('password123', passwordHash)
用户相关方法
获取用户信息
用法:uniIDIns.getUserInfo(Object getUserInfoOptions)
参数说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| uid | String | 是 | 用户 Id |
响应参数
| 字段 | 类型 | 说明 |
|---|---|---|
| errCode | Number | 错误码,0 表示成功 |
| message | String | 详细信息 |
| userInfo | Object | 用户信息 |
示例
const userInfo = await uniIDIns.getUserInfo({
uid: 'user-id'
})
更新用户信息
用法:uniIDIns.updateUser(Object updateUserOptions)
参数说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| uid | String | 是 | 用户 Id |
| ... | ... | 否 | 需要更新的用户字段 |
响应参数
| 字段 | 类型 | 说明 |
|---|---|---|
| errCode | Number | 错误码,0 表示成功 |
| message | String | 详细信息 |
示例
const result = await uniIDIns.updateUser({
uid: 'user-id',
nickname: '新昵称',
avatar: '新头像地址'
})
角色权限相关方法
获取用户角色
用法:uniIDIns.getUserRole(Object getUserRoleOptions)
参数说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| uid | String | 是 | 用户 Id |
响应参数
| 字段 | 类型 | 说明 |
|---|---|---|
| errCode | Number | 错误码,0 表示成功 |
| message | String | 详细信息 |
| role | Array | 用户角色列表 |
示例
const userRole = await uniIDIns.getUserRole({
uid: 'user-id'
})
获取用户权限
用法:uniIDIns.getUserPermission(Object getUserPermissionOptions)
参数说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| uid | String | 是 | 用户 Id |
响应参数
| 字段 | 类型 | 说明 |
|---|---|---|
| errCode | Number | 错误码,0 表示成功 |
| message | String | 详细信息 |
| permission | Array | 用户权限列表 |
示例
const userPermission = await uniIDIns.getUserPermission({
uid: 'user-id'
})
检查用户权限
用法:uniIDIns.checkPermission(Object checkPermissionOptions)
参数说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| uid | String | 是 | 用户 Id |
| permissionID | String | 是 | 权限 ID |
响应参数
| 字段 | 类型 | 说明 |
|---|---|---|
| errCode | Number | 错误码,0 表示成功 |
| message | String | 详细信息 |
示例
const result = await uniIDIns.checkPermission({
uid: 'user-id',
permissionID: 'permission-id'
})
配置相关方法
获取配置
用法:uniIDIns.getConfig()
响应参数
| 字段 | 类型 | 说明 |
|---|---|---|
| config | Object | uni-id 配置信息 |
示例
const config = await uniIDIns.getConfig()
设置配置
用法:uniIDIns.setConfig(Object config)
参数说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| config | Object | 是 | uni-id 配置信息 |
响应参数
| 字段 | 类型 | 说明 |
|---|---|---|
| errCode | Number | 错误码,0 表示成功 |
| message | String | 详细信息 |
示例
const result = await uniIDIns.setConfig({
passwordSecret: 'passwordSecret-demo',
tokenSecret: 'tokenSecret-demo',
tokenExpiresIn: 7200
})
其他方法
获取客户端信息
用法:uniIDIns.getClientInfo()
响应参数
| 字段 | 类型 | 说明 |
|---|---|---|
| clientInfo | Object | 客户端信息,包含 APPID、PLATFORM、LOCALE 等 |
示例
const clientInfo = await uniIDIns.getClientInfo()
获取数据库实例
用法:uniIDIns.getDB()
响应参数
| 字段 | 类型 | 说明 |
|---|---|---|
| db | Object | 数据库实例 |
示例
const db = await uniIDIns.getDB()
使用示例
在云对象中使用
// uni-id-co 云对象
const uniID = require('uni-id-common')
module.exports = {
_before() {
// 获取客户端信息
const clientInfo = this.getClientInfo()
// 创建 uni-id 实例
this.uniID = uniID.createInstance({
clientInfo
})
},
// 登录方法
async login(params) {
// 登录逻辑
const { username, password } = params
// 查询用户
const user = await this.db.collection('uni-id-users').where({
username: username
}).limit(1).get()
if (user.data.length === 0) {
return {
code: 10001,
message: '用户不存在'
}
}
// 验证密码
const isMatch = await this.uniID.checkPwd(password, user.data[0].password)
if (!isMatch) {
return {
code: 10002,
message: '密码错误'
}
}
// 生成 token
const token = await this.uniID.createToken({
uid: user.data[0]._id
})
return {
code: 0,
message: '登录成功',
token: token.token,
tokenExpired: token.tokenExpired,
userInfo: user.data[0]
}
},
// 获取用户信息
async getUserInfo() {
// 获取 token
const token = this.getUniIdToken()
if (!token) {
return {
code: 10003,
message: '未登录'
}
}
// 校验 token
const result = await this.uniID.checkToken(token)
if (result.code !== 0) {
return result
}
// 返回用户信息
return {
code: 0,
message: '获取用户信息成功',
userInfo: result.userInfo
}
}
}
在云函数中使用
// 云函数
const uniID = require('uni-id-common')
exports.main = async function(event, context) {
// 设置客户端信息
context.APPID = '__UNI__xxxxxxx' // 替换为当前客户端的 APPID
context.PLATFORM = 'web' // 替换为当前客户端的平台类型
context.LOCALE = 'zh-Hans' // 替换为当前客户端的语言代码
// 创建 uni-id 实例
const uniIDIns = uniID.createInstance({
context: context
})
// 校验 token
const result = await uniIDIns.checkToken(event.uniIdToken)
if (result.code !== 0) {
return result
}
// 获取用户信息
const userInfo = await uniIDIns.getUserInfo({
uid: result.uid
})
return {
code: 0,
message: '获取用户信息成功',
userInfo: userInfo.userInfo
}
}
总结
uni-id-common 是 uni-id 用户体系中的核心模块,主要负责 token 的管理,包括 token 的校验、生成和刷新。通过 uni-id-common,开发者可以方便地实现用户身份验证和权限控制。
使用 uni-id-common 的主要步骤是:
- 引入
uni-id-common模块 - 创建
uni-id-common实例,传入 context 或 clientInfo - 使用实例调用相关方法,如 checkToken、createToken、refreshToken 等
uni-id-common 模块的设计使得开发者可以更加灵活地使用 uni-id 用户体系,同时也可以减少不必要的数据库查询,提高应用性能。