uni-id 身份认证
uni-id 是 uniCloud 提供的身份认证服务,它提供了一套完整的用户身份管理解决方案,包括用户注册、登录、密码重置、角色权限管理等功能。本文将详细介绍 uni-id 的使用方法,帮助开发者快速实现应用的身份认证功能。
1. uni-id 概述
1.1 什么是 uni-id
uni-id 是 uniCloud 提供的身份认证服务,它基于 JWT(JSON Web Token)技术,提供了一套完整的用户身份管理解决方案。uni-id 支持多种登录方式,包括账号密码登录、手机号登录、邮箱登录、第三方登录等,可以满足各种应用场景的需求。
1.2 uni-id 的优势
- 开箱即用:uni-id 已经封装了常用的身份认证功能,开发者无需从零开始实现
- 多端支持:支持 H5、App、小程序等多种平台
- 安全可靠:基于 JWT 技术,支持 token 自动续期,安全性高
- 灵活扩展:支持自定义登录方式、自定义字段、自定义权限等
- 与 uniCloud 无缝集成:与 uniCloud 的云函数、云数据库、云存储等服务无缝集成
1.3 uni-id 的功能
uni-id 提供以下核心功能:
- 用户管理:用户注册、登录、注销、信息修改等
- 身份验证:账号密码验证、手机号验证、邮箱验证等
- 权限管理:角色管理、权限分配、权限验证等
- 第三方登录:微信、QQ、支付宝等第三方平台登录
- 安全机制:密码加密、token 管理、登录限制等
2. uni-id 的安装与配置
2.1 安装 uni-id
uni-id 是 uniCloud 的扩展库,需要先安装:
# 在项目根目录下执行
npm install uni-id
2.2 初始化 uni-id
在云函数中初始化 uni-id:
// 云函数入口文件
const uniID = require('uni-id')
exports.main = async (event, context) => {
// 初始化 uni-id
const uniIDInstance = new uniID({
context: context
})
// 调用 uni-id 的方法
const result = await uniIDInstance.login({
username: event.username,
password: event.password
})
return result
}
2.3 配置 uni-id
uni-id 支持多种配置选项,可以通过配置文件进行设置:
// uni-id 配置文件 (uni-id/config.json)
{
"passwordSecret": "passwordSecret-demo", // 密码加密密钥
"tokenSecret": "tokenSecret-demo", // token 加密密钥
"tokenExpiresIn": 7200, // token 过期时间,单位为秒
"tokenExpiresThreshold": 3600, // token 过期阈值,单位为秒
"passwordErrorLimit": 6, // 密码错误次数限制
"passwordErrorRetryTime": 3600, // 密码错误重试时间,单位为秒
"autoSetInviteCode": false, // 是否自动设置邀请码
"forceInviteCode": false, // 是否强制使用邀请码
"app-plus": {
"tokenExpiresIn": 2592000, // App 端 token 过期时间,单位为秒
"oauth": {
"weixin": {
"appid": "weixin-appid",
"appsecret": "weixin-appsecret"
}
}
},
"mp-weixin": {
"oauth": {
"weixin": {
"appid": "weixin-appid",
"appsecret": "weixin-appsecret"
}
}
},
"h5": {
"oauth": {
"weixin": {
"appid": "weixin-appid",
"appsecret": "weixin-appsecret"
}
}
}
}
2.4 数据库初始化
uni-id 需要特定的数据库集合,可以通过以下命令初始化:
# 在项目根目录下执行
npx uni-id init
这将创建以下集合:
uni-id-users:用户信息集合uni-id-tokens:token 信息集合uni-id-permissions:权限信息集合uni-id-roles:角色信息集合
3. uni-id 基本功能
3.1 用户注册
3.1.1 账号密码注册
// 云函数
const uniID = require('uni-id')
exports.main = async (event, context) => {
const uniIDInstance = new uniID({
context: context
})
const result = await uniIDInstance.register({
username: event.username,
password: event.password,
nickname: event.nickname,
gender: event.gender,
avatar: event.avatar
})
return result
}
// 前端调用
uniCloud.callFunction({
name: 'register',
data: {
username: 'username',
password: 'password',
nickname: 'nickname',
gender: 1,
avatar: 'avatar-url'
},
success: function(res) {
console.log(res.result)
},
fail: function(err) {
console.error(err)
}
})
3.1.2 手机号注册
// 云函数
const uniID = require('uni-id')
exports.main = async (event, context) => {
const uniIDInstance = new uniID({
context: context
})
const result = await uniIDInstance.register({
mobile: event.mobile,
password: event.password,
code: event.code // 短信验证码
})
return result
}
3.1.3 邮箱注册
// 云函数
const uniID = require('uni-id')
exports.main = async (event, context) => {
const uniIDInstance = new uniID({
context: context
})
const result = await uniIDInstance.register({
email: event.email,
password: event.password,
code: event.code // 邮箱验证码
})
return result
}
3.2 用户登录
3.2.1 账号密码登录
// 云函数
const uniID = require('uni-id')
exports.main = async (event, context) => {
const uniIDInstance = new uniID({
context: context
})
const result = await uniIDInstance.login({
username: event.username,
password: event.password
})
return result
}
// 前端调用
uniCloud.callFunction({
name: 'login',
data: {
username: 'username',
password: 'password'
},
success: function(res) {
console.log(res.result)
// 保存 token
uni.setStorageSync('uni_id_token', res.result.token)
uni.setStorageSync('uni_id_token_expired', res.result.tokenExpired)
},
fail: function(err) {
console.error(err)
}
})
3.2.2 手机号登录
// 云函数
const uniID = require('uni-id')
exports.main = async (event, context) => {
const uniIDInstance = new uniID({
context: context
})
const result = await uniIDInstance.loginByMobile({
mobile: event.mobile,
code: event.code // 短信验证码
})
return result
}
3.2.3 邮箱登录
// 云函数
const uniID = require('uni-id')
exports.main = async (event, context) => {
const uniIDInstance = new uniID({
context: context
})
const result = await uniIDInstance.loginByEmail({
email: event.email,
code: event.code // 邮箱验证码
})
return result
}
3.3 用户注销
// 云函数
const uniID = require('uni-id')
exports.main = async (event, context) => {
const uniIDInstance = new uniID({
context: context
})
const result = await uniIDInstance.logout({
token: event.token
})
return result
}
// 前端调用
uniCloud.callFunction({
name: 'logout',
data: {
token: uni.getStorageSync('uni_id_token')
},
success: function(res) {
console.log(res.result)
// 清除 token
uni.removeStorageSync('uni_id_token')
uni.removeStorageSync('uni_id_token_expired')
},
fail: function(err) {
console.error(err)
}
})
3.4 获取用户信息
// 云函数
const uniID = require('uni-id')
exports.main = async (event, context) => {
const uniIDInstance = new uniID({
context: context
})
const result = await uniIDInstance.checkToken({
token: event.token
})
if (result.code === 0) {
// token 有效,返回用户信息
return {
code: 0,
message: '获取用户信息成功',
userInfo: result.userInfo
}
} else {
// token 无效
return {
code: result.code,
message: result.message
}
}
}
// 前端调用
uniCloud.callFunction({
name: 'getUserInfo',
data: {
token: uni.getStorageSync('uni_id_token')
},
success: function(res) {
console.log(res.result)
if (res.result.code === 0) {
// 保存用户信息
uni.setStorageSync('userInfo', res.result.userInfo)
}
},
fail: function(err) {
console.error(err)
}
})
3.5 修改用户信息
// 云函数
const uniID = require('uni-id')
exports.main = async (event, context) => {
const uniIDInstance = new uniID({
context: context
})
const result = await uniIDInstance.updateUser({
uid: event.uid,
nickname: event.nickname,
gender: event.gender,
avatar: event.avatar
})
return result
}
3.6 修改密码
// 云函数
const uniID = require('uni-id')
exports.main = async (event, context) => {
const uniIDInstance = new uniID({
context: context
})
const result = await uniIDInstance.updatePwd({
uid: event.uid,
oldPassword: event.oldPassword,
newPassword: event.newPassword
})
return result
}
3.7 重置密码
// 云函数
const uniID = require('uni-id')
exports.main = async (event, context) => {
const uniIDInstance = new uniID({
context: context
})
const result = await uniIDInstance.resetPwd({
mobile: event.mobile,
code: event.code, // 短信验证码
password: event.password
})
return result
}
4. uni-id 高级功能
4.1 第三方登录
4.1.1 微信登录
// 云函数
const uniID = require('uni-id')
exports.main = async (event, context) => {
const uniIDInstance = new uniID({
context: context
})
const result = await uniIDInstance.loginByWeixin({
code: event.code
})
return result
}
// 前端调用
// 获取微信登录 code
uni.login({
provider: 'weixin',
success: function(loginRes) {
const code = loginRes.code
// 调用云函数登录
uniCloud.callFunction({
name: 'loginByWeixin',
data: {
code: code
},
success: function(res) {
console.log(res.result)
// 保存 token
uni.setStorageSync('uni_id_token', res.result.token)
uni.setStorageSync('uni_id_token_expired', res.result.tokenExpired)
},
fail: function(err) {
console.error(err)
}
})
},
fail: function(err) {
console.error(err)
}
})
4.1.2 QQ 登录
// 云函数
const uniID = require('uni-id')
exports.main = async (event, context) => {
const uniIDInstance = new uniID({
context: context
})
const result = await uniIDInstance.loginByQQ({
code: event.code
})
return result
}
4.1.3 支付宝登录
// 云函数
const uniID = require('uni-id')
exports.main = async (event, context) => {
const uniIDInstance = new uniID({
context: context
})
const result = await uniIDInstance.loginByAlipay({
code: event.code
})
return result
}
4.2 角色权限管理
4.2.1 创建角色
// 云函数
const uniID = require('uni-id')
exports.main = async (event, context) => {
const uniIDInstance = new uniID({
context: context
})
const result = await uniIDInstance.createRole({
roleID: event.roleID,
roleName: event.roleName,
permission: event.permission
})
return result
}
4.2.2 删除角色
// 云函数
const uniID = require('uni-id')
exports.main = async (event, context) => {
const uniIDInstance = new uniID({
context: context
})
const result = await uniIDInstance.deleteRole({
roleID: event.roleID
})
return result
}
4.2.3 修改角色
// 云函数
const uniID = require('uni-id')
exports.main = async (event, context) => {
const uniIDInstance = new uniID({
context: context
})
const result = await uniIDInstance.updateRole({
roleID: event.roleID,
roleName: event.roleName,
permission: event.permission
})
return result
}
4.2.4 获取角色列表
// 云函数
const uniID = require('uni-id')
exports.main = async (event, context) => {
const uniIDInstance = new uniID({
context: context
})
const result = await uniIDInstance.getRoleList({
limit: event.limit,
offset: event.offset
})
return result
}
4.2.5 为用户分配角色
// 云函数
const uniID = require('uni-id')
exports.main = async (event, context) => {
const uniIDInstance = new uniID({
context: context
})
const result = await uniIDInstance.addUserRole({
uid: event.uid,
roleID: event.roleID
})
return result
}
4.2.6 移除用户角色
// 云函数
const uniID = require('uni-id')
exports.main = async (event, context) => {
const uniIDInstance = new uniID({
context: context
})
const result = await uniIDInstance.removeUserRole({
uid: event.uid,
roleID: event.roleID
})
return result
}
4.2.7 检查用户权限
// 云函数
const uniID = require('uni-id')
exports.main = async (event, context) => {
const uniIDInstance = new uniID({
context: context
})
const result = await uniIDInstance.checkPermission({
uid: event.uid,
permissionID: event.permissionID
})
return result
}
4.3 自定义字段
uni-id 支持自定义用户字段,可以在注册和更新用户信息时添加自定义字段:
// 云函数
const uniID = require('uni-id')
exports.main = async (event, context) => {
const uniIDInstance = new uniID({
context: context
})
const result = await uniIDInstance.register({
username: event.username,
password: event.password,
// 自定义字段
customField1: event.customField1,
customField2: event.customField2
})
return result
}
4.4 自定义登录方式
uni-id 支持自定义登录方式,可以通过扩展 uni-id 实现:
// 云函数
const uniID = require('uni-id')
// 扩展 uni-id
uniID.prototype.loginByCustom = async function(params) {
// 自定义登录逻辑
const { customField, customValue } = params
// 查询用户
const user = await this.db.collection('uni-id-users').where({
[customField]: customValue
}).limit(1).get()
if (user.data.length === 0) {
return {
code: 10001,
message: '用户不存在'
}
}
// 生成 token
const token = await this.createToken({
uid: user.data[0]._id
})
return {
code: 0,
message: '登录成功',
token: token.token,
tokenExpired: token.tokenExpired,
userInfo: user.data[0]
}
}
exports.main = async (event, context) => {
const uniIDInstance = new uniID({
context: context
})
const result = await uniIDInstance.loginByCustom({
customField: event.customField,
customValue: event.customValue
})
return result
}
5. uni-id 安全性
5.1 密码加密
uni-id 使用 bcrypt 算法对密码进行加密,确保密码安全存储:
// 密码加密示例
const bcrypt = require('bcrypt')
const saltRounds = 10
// 加密密码
const hash = bcrypt.hashSync(password, saltRounds)
// 验证密码
const isMatch = bcrypt.compareSync(password, hash)
5.2 Token 管理
uni-id 使用 JWT 技术管理 token,支持 token 自动续期:
// token 配置
{
"tokenSecret": "tokenSecret-demo", // token 加密密钥
"tokenExpiresIn": 7200, // token 过期时间,单位为秒
"tokenExpiresThreshold": 3600 // token 过期阈值,单位为秒
}
5.3 登录限制
uni-id 支持登录限制,可以限制密码错误次数和重试时间:
// 登录限制配置
{
"passwordErrorLimit": 6, // 密码错误次数限制
"passwordErrorRetryTime": 3600 // 密码错误重试时间,单位为秒
}
5.4 权限控制
uni-id 提供基于角色的权限控制,可以精细控制用户权限:
// 权限检查
const result = await uniIDInstance.checkPermission({
uid: uid,
permissionID: 'permission-id'
})
if (result.code === 0) {
// 有权限
} else {
// 无权限
}
6. uni-id 最佳实践
6.1 前端封装
为了方便使用,可以在前端封装 uni-id 的调用:
// uni-id 前端封装
const uniID = {
// 登录
login: function(username, password) {
return new Promise((resolve, reject) => {
uniCloud.callFunction({
name: 'login',
data: {
username: username,
password: password
},
success: function(res) {
if (res.result.code === 0) {
// 保存 token
uni.setStorageSync('uni_id_token', res.result.token)
uni.setStorageSync('uni_id_token_expired', res.result.tokenExpired)
resolve(res.result)
} else {
reject(res.result)
}
},
fail: function(err) {
reject(err)
}
})
})
},
// 注册
register: function(username, password, nickname) {
return new Promise((resolve, reject) => {
uniCloud.callFunction({
name: 'register',
data: {
username: username,
password: password,
nickname: nickname
},
success: function(res) {
resolve(res.result)
},
fail: function(err) {
reject(err)
}
})
})
},
// 注销
logout: function() {
return new Promise((resolve, reject) => {
const token = uni.getStorageSync('uni_id_token')
uniCloud.callFunction({
name: 'logout',
data: {
token: token
},
success: function(res) {
// 清除 token
uni.removeStorageSync('uni_id_token')
uni.removeStorageSync('uni_id_token_expired')
resolve(res.result)
},
fail: function(err) {
reject(err)
}
})
})
},
// 获取用户信息
getUserInfo: function() {
return new Promise((resolve, reject) => {
const token = uni.getStorageSync('uni_id_token')
uniCloud.callFunction({
name: 'getUserInfo',
data: {
token: token
},
success: function(res) {
resolve(res.result)
},
fail: function(err) {
reject(err)
}
})
})
},
// 检查登录状态
checkLogin: function() {
const token = uni.getStorageSync('uni_id_token')
const tokenExpired = uni.getStorageSync('uni_id_token_expired')
if (!token || !tokenExpired) {
return false
}
if (Date.now() > tokenExpired) {
// token 已过期
uni.removeStorageSync('uni_id_token')
uni.removeStorageSync('uni_id_token_expired')
return false
}
return true
}
}
// 使用示例
async function login() {
try {
const result = await uniID.login('username', 'password')
console.log('登录成功', result)
} catch (err) {
console.error('登录失败', err)
}
}
6.2 云函数封装
为了方便使用,可以在云函数中封装 uni-id 的调用:
// uni-id 云函数封装
const uniID = require('uni-id')
// 初始化 uni-id
function initUniID(context) {
return new uniID({
context: context
})
}
// 登录
async function login(event, context) {
const uniIDInstance = initUniID(context)
const result = await uniIDInstance.login({
username: event.username,
password: event.password
})
return result
}
// 注册
async function register(event, context) {
const uniIDInstance = initUniID(context)
const result = await uniIDInstance.register({
username: event.username,
password: event.password,
nickname: event.nickname
})
return result
}
// 注销
async function logout(event, context) {
const uniIDInstance = initUniID(context)
const result = await uniIDInstance.logout({
token: event.token
})
return result
}
// 获取用户信息
async function getUserInfo(event, context) {
const uniIDInstance = initUniID(context)
const result = await uniIDInstance.checkToken({
token: event.token
})
if (result.code === 0) {
return {
code: 0,
message: '获取用户信息成功',
userInfo: result.userInfo
}
} else {
return {
code: result.code,
message: result.message
}
}
}
// 云函数入口
exports.main = async (event, context) => {
const { action, data } = event
switch (action) {
case 'login':
return await login(data, context)
case 'register':
return await register(data, context)
case 'logout':
return await logout(data, context)
case 'getUserInfo':
return await getUserInfo(data, context)
default:
return {
code: 10001,
message: '未知的操作类型'
}
}
}
6.3 权限控制最佳实践
6.3.1 基于角色的权限控制
// 定义角色
const roles = {
admin: {
roleID: 'admin',
roleName: '管理员',
permission: ['*'] // 所有权限
},
user: {
roleID: 'user',
roleName: '普通用户',
permission: ['read', 'write'] // 读写权限
},
guest: {
roleID: 'guest',
roleName: '访客',
permission: ['read'] // 只读权限
}
}
// 创建角色
async function createRoles(context) {
const uniIDInstance = new uniID({
context: context
})
for (const roleID in roles) {
const role = roles[roleID]
await uniIDInstance.createRole({
roleID: role.roleID,
roleName: role.roleName,
permission: role.permission
})
}
}
// 检查权限
async function checkPermission(uid, permissionID, context) {
const uniIDInstance = new uniID({
context: context
})
const result = await uniIDInstance.checkPermission({
uid: uid,
permissionID: permissionID
})
return result.code === 0
}
6.3.2 权限中间件
// 权限中间件
async function permissionMiddleware(event, context) {
const { action, data } = event
// 不需要权限的操作
const publicActions = ['login', 'register', 'resetPwd']
if (publicActions.includes(action)) {
return event
}
// 获取 token
const token = data.token || context.TOKEN
if (!token) {
return {
code: 10002,
message: '未登录'
}
}
// 检查 token
const uniIDInstance = new uniID({
context: context
})
const tokenResult = await uniIDInstance.checkToken({
token: token
})
if (tokenResult.code !== 0) {
return {
code: tokenResult.code,
message: tokenResult.message
}
}
// 将用户信息添加到 context
context.USER_INFO = tokenResult.userInfo
return event
}
// 云函数入口
exports.main = async (event, context) => {
// 权限中间件
const middlewareResult = await permissionMiddleware(event, context)
if (middlewareResult.code) {
return middlewareResult
}
const { action, data } = middlewareResult
// 处理请求
switch (action) {
case 'login':
return await login(data, context)
case 'register':
return await register(data, context)
case 'logout':
return await logout(data, context)
case 'getUserInfo':
return await getUserInfo(data, context)
default:
return {
code: 10001,
message: '未知的操作类型'
}
}
}
6.4 多端适配
uni-id 支持多端适配,可以为不同平台配置不同的登录方式:
// 多端配置
{
"app-plus": {
"tokenExpiresIn": 2592000, // App 端 token 过期时间,单位为秒
"oauth": {
"weixin": {
"appid": "weixin-appid",
"appsecret": "weixin-appsecret"
}
}
},
"mp-weixin": {
"oauth": {
"weixin": {
"appid": "weixin-appid",
"appsecret": "weixin-appsecret"
}
}
},
"h5": {
"oauth": {
"weixin": {
"appid": "weixin-appid",
"appsecret": "weixin-appsecret"
}
}
}
}
7. 总结
uni-id 是 uniCloud 提供的身份认证服务,它提供了一套完整的用户身份管理解决方案,包括用户注册、登录、密码重置、角色权限管理等功能。通过本文的介绍,您应该已经了解了 uni-id 的基本用法和高级功能,可以在实际开发中灵活运用。
uni-id 的优势在于开箱即用、多端支持、安全可靠、灵活扩展和与 uniCloud 无缝集成。通过合理使用 uni-id,可以快速实现应用的身份认证功能,提高开发效率,降低开发成本。
在实际开发中,可以根据业务需求,合理使用 uni-id 的各种功能,构建安全、可靠的身份认证系统。