uni-id 用户体系

251 阅读9分钟

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)

参数说明

字段类型必填说明
tokenString客户端 callFunction 带上的 token
optionsobjectcheckToken 方法的选项
options.autoRefreshboolean是否需要自动判断刷新 token,默认 true

说明

  • 角色内包含 admin 时返回的 permission 是一个空数组,因此判断一个用户是否有权限时应注意 admin 角色额外进行判断

响应参数

字段类型说明
errCodeNumber|String错误码,0 表示成功
messageString详细信息
uidString用户 Id,校验成功之后会返回
tokenString用户 token 快要过期时,新生成的 token,只有在 config 内配置了 tokenExpiresThreshold 的值时才会有此行为
tokenExpiredTimeStamp新 token 的过期时间,单位毫秒
roleArray用户角色列表
permissionArray用户权限列表

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);

参数说明

字段类型必填说明
tokenString用户 token

示例

const {
  token,
  tokenExpired
} = await uniIDIns.refreshToken({
  token: 'xxx'
})

注意

  • 刷新 token 时会自动更新 token 内 uid 对应的角色权限

生成 token

用法:uniIDIns.createToken(Object CreateTokenOptions)

参数说明

字段类型必填说明
uidString用户 Id
roleArray指定缓存在 token 内的角色
permissionArray指定缓存在角色内的权限

响应参数

字段类型必填说明
tokenString生成的 token
tokenExpiredNumbertoken 过期时间对应的时间戳

说明

  • 创建 token 时如果未传角色权限会自动获取 uid 对应的角色权限

uni-id-common 完整方法列表

除了上述主要方法外,uni-id-common 还提供了以下方法:

密码相关方法

加密密码

用法:uniIDIns.encryptPwd(String password)

参数说明

字段类型必填说明
passwordString需要加密的密码

响应参数

字段类型说明
passwordHashString加密后的密码

示例

const passwordHash = await uniIDIns.encryptPwd('password123')
校验密码

用法:uniIDIns.checkPwd(String password, String passwordHash)

参数说明

字段类型必填说明
passwordString需要校验的密码
passwordHashString加密后的密码

响应参数

字段类型说明
isMatchBoolean密码是否匹配

示例

const isMatch = await uniIDIns.checkPwd('password123', passwordHash)

用户相关方法

获取用户信息

用法:uniIDIns.getUserInfo(Object getUserInfoOptions)

参数说明

字段类型必填说明
uidString用户 Id

响应参数

字段类型说明
errCodeNumber错误码,0 表示成功
messageString详细信息
userInfoObject用户信息

示例

const userInfo = await uniIDIns.getUserInfo({
  uid: 'user-id'
})
更新用户信息

用法:uniIDIns.updateUser(Object updateUserOptions)

参数说明

字段类型必填说明
uidString用户 Id
......需要更新的用户字段

响应参数

字段类型说明
errCodeNumber错误码,0 表示成功
messageString详细信息

示例

const result = await uniIDIns.updateUser({
  uid: 'user-id',
  nickname: '新昵称',
  avatar: '新头像地址'
})

角色权限相关方法

获取用户角色

用法:uniIDIns.getUserRole(Object getUserRoleOptions)

参数说明

字段类型必填说明
uidString用户 Id

响应参数

字段类型说明
errCodeNumber错误码,0 表示成功
messageString详细信息
roleArray用户角色列表

示例

const userRole = await uniIDIns.getUserRole({
  uid: 'user-id'
})
获取用户权限

用法:uniIDIns.getUserPermission(Object getUserPermissionOptions)

参数说明

字段类型必填说明
uidString用户 Id

响应参数

字段类型说明
errCodeNumber错误码,0 表示成功
messageString详细信息
permissionArray用户权限列表

示例

const userPermission = await uniIDIns.getUserPermission({
  uid: 'user-id'
})
检查用户权限

用法:uniIDIns.checkPermission(Object checkPermissionOptions)

参数说明

字段类型必填说明
uidString用户 Id
permissionIDString权限 ID

响应参数

字段类型说明
errCodeNumber错误码,0 表示成功
messageString详细信息

示例

const result = await uniIDIns.checkPermission({
  uid: 'user-id',
  permissionID: 'permission-id'
})

配置相关方法

获取配置

用法:uniIDIns.getConfig()

响应参数

字段类型说明
configObjectuni-id 配置信息

示例

const config = await uniIDIns.getConfig()
设置配置

用法:uniIDIns.setConfig(Object config)

参数说明

字段类型必填说明
configObjectuni-id 配置信息

响应参数

字段类型说明
errCodeNumber错误码,0 表示成功
messageString详细信息

示例

const result = await uniIDIns.setConfig({
  passwordSecret: 'passwordSecret-demo',
  tokenSecret: 'tokenSecret-demo',
  tokenExpiresIn: 7200
})

其他方法

获取客户端信息

用法:uniIDIns.getClientInfo()

响应参数

字段类型说明
clientInfoObject客户端信息,包含 APPID、PLATFORM、LOCALE 等

示例

const clientInfo = await uniIDIns.getClientInfo()
获取数据库实例

用法:uniIDIns.getDB()

响应参数

字段类型说明
dbObject数据库实例

示例

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 的主要步骤是:

  1. 引入 uni-id-common 模块
  2. 创建 uni-id-common 实例,传入 context 或 clientInfo
  3. 使用实例调用相关方法,如 checkToken、createToken、refreshToken 等

uni-id-common 模块的设计使得开发者可以更加灵活地使用 uni-id 用户体系,同时也可以减少不必要的数据库查询,提高应用性能。