Files
urbanLifeline/urbanLifelineWeb/packages/workcase_wechat/最终登录方案.md
2026-01-09 12:17:21 +08:00

7.7 KiB
Raw Blame History

微信小程序最终登录方案

方案说明

采用自动静默登录方案,用户打开小程序即自动完成登录,无需任何授权操作。

实现方式

1. 进入首页自动登录

  • 用户打开小程序,进入首页
  • 检查本地缓存,如果有登录信息,直接使用
  • 如果没有缓存,自动调用 wx.login 获取 code
  • 使用 code 调用后端 identify 接口完成登录
  • 全程无需用户操作

2. 登录流程

用户打开小程序
  ↓
进入首页 (pages/index/index)
  ↓
检查缓存 (token, userInfo, wechatId)
  ↓
有缓存 → 直接使用
  ↓
无缓存 → 自动登录
  ↓
wx.login 获取 code
  ↓
调用 identify 接口
  ↓
保存登录信息
  ↓
完成登录

3. Token 过期处理

API 请求返回 401
  ↓
清除缓存
  ↓
提示"登录已过期,正在重新登录"
  ↓
刷新页面
  ↓
触发自动登录

4. 退出登录

点击"退出"按钮
  ↓
确认对话框
  ↓
清除登录信息
  ↓
调用 autoLogin() 重新登录

代码实现

首页 (pages/index/index.uvue)

// 初始化用户信息
async function initUserInfo() {
  try {
    // 1. 先尝试从缓存获取
    const cachedWechatId = uni.getStorageSync('wechatId')
    const cachedUserInfo = uni.getStorageSync('userInfo')
    const cachedToken = uni.getStorageSync('token')
    
    if (cachedWechatId && cachedUserInfo && cachedToken) {
      // 有完整缓存,直接使用
      const parsedUserInfo = typeof cachedUserInfo === 'string' 
        ? JSON.parse(cachedUserInfo) 
        : cachedUserInfo
      
      userInfo.value = {
        wechatId: cachedWechatId,
        username: parsedUserInfo.username || parsedUserInfo.realName || '微信用户',
        phone: parsedUserInfo.phone || '',
        userId: parsedUserInfo.userId || ''
      }
      
      // 判断用户类型
      userType.value = parsedUserInfo.status !== 'guest'
      
      console.log('使用缓存的用户信息:', userInfo.value)
      return
    }

    // 2. 没有缓存,自动登录
    await autoLogin()
  } catch (error) {
    console.error('初始化用户信息失败:', error)
    await autoLogin()
  }
}

// 自动登录
async function autoLogin() {
  uni.showLoading({ title: '登录中...' })
  
  try {
    uni.login({
      provider: 'weixin',
      success: async (loginRes) => {
        console.log('微信登录成功code:', loginRes.code)
        
        const code = loginRes.code
        const wechatId = code.substring(0, 20) // 使用部分code作为临时ID
        
        // 调用 identify 接口
        const identifyRes = await guestAPI.identify({
          wechatId: wechatId,
          phone: ''
        })
        
        uni.hideLoading()
        
        if (identifyRes.success && identifyRes.data) {
          const loginDomain = identifyRes.data
          
          // 保存登录信息
          uni.setStorageSync('token', loginDomain.token || '')
          uni.setStorageSync('userInfo', JSON.stringify(loginDomain.user))
          uni.setStorageSync('loginDomain', JSON.stringify(loginDomain))
          uni.setStorageSync('wechatId', wechatId)
          
          // 更新用户信息
          userInfo.value = {
            wechatId: wechatId,
            username: loginDomain.user?.username || loginDomain.user?.realName || '微信用户',
            phone: loginDomain.user?.phone || '',
            userId: loginDomain.user?.userId || ''
          }
          
          // 判断用户类型
          userType.value = loginDomain.user?.status !== 'guest'
          
          console.log('自动登录成功:', userInfo.value)
        } else {
          uni.showToast({
            title: identifyRes.message || '登录失败',
            icon: 'none'
          })
        }
      },
      fail: (err) => {
        console.error('微信登录失败:', err)
        uni.hideLoading()
        uni.showToast({ title: '登录失败,请重试', icon: 'none' })
      }
    })
  } catch (error: any) {
    console.error('自动登录失败:', error)
    uni.hideLoading()
    uni.showToast({
      title: error.message || '登录失败',
      icon: 'none'
    })
  }
}

优势

1. 用户体验极佳

  • 无需任何授权操作
  • 打开即用
  • 无感知登录
  • 无弹窗干扰

2. 无权限要求

  • 不需要企业认证
  • 不需要开通手机号快速验证
  • 个人小程序也可使用
  • 测试环境友好

3. 代码简洁

  • 删除了授权页面
  • 删除了切换用户功能
  • 删除了所有 mock 相关代码
  • 只保留核心登录逻辑

4. 维护方便

  • 登录逻辑集中在首页
  • Token 过期自动处理
  • 错误处理完善
  • 日志清晰

后端要求

identify 接口

POST /urban-lifeline/system/guest/identify
{
  "wechatId": "微信ID使用code的前20位作为临时标识",
  "phone": ""  // 可以为空
}

返回:
{
  "success": true,
  "data": {
    "token": "jwt_token",
    "user": {
      "userId": "用户ID",
      "username": "用户名",
      "realName": "真实姓名",
      "phone": "手机号(可能为空)",
      "status": "guest" | "employee"
    }
  }
}

建议优化

  1. 后端可以通过 code 换取 openid

    • 前端传递完整的 code
    • 后端调用微信 API 换取 openid
    • 使用 openid 作为用户唯一标识
  2. 支持游客模式

    • 如果 wechatId 不存在,创建游客账号
    • 返回游客身份的 token
    • 允许后续绑定手机号升级为正式用户

已删除的内容

1. 授权页面

  • pages/auth/auth.uvue - 已删除
  • pages.json 中的 auth 路由配置 - 已删除

2. 切换用户功能

  • switchMockUser() 函数 - 已删除
  • isMockMode 变量 - 已删除
  • 切换按钮 UI - 已删除
  • 所有条件编译代码 - 已删除

3. getUserProfile

  • 不再使用 getUserProfile API
  • 不再需要用户授权昵称

4. getPhoneNumber

  • 不再使用 getPhoneNumber API
  • 不再需要手机号授权

保留的功能

1. 退出登录

  • 右上角"退出"按钮
  • 点击后清除缓存并重新自动登录
  • 红色主题,易于识别

2. Token 管理

  • 自动检测 401 错误
  • 自动清除过期信息
  • 自动重新登录

3. 用户类型识别

  • 区分 guest 和 employee
  • 根据类型控制功能权限

测试清单

首次使用

  • 打开小程序,自动登录成功
  • 无任何授权弹窗
  • 用户信息正确显示
  • 可以正常使用所有功能

再次使用

  • 关闭小程序重新打开
  • 直接进入首页,无需重新登录
  • 用户信息保持不变

Token 过期

  • 模拟 Token 过期(后端返回 401
  • 自动提示"登录已过期,正在重新登录"
  • 自动完成重新登录
  • 功能恢复正常

退出登录

  • 点击"退出"按钮
  • 显示确认对话框
  • 确认后自动重新登录
  • 登录成功后可正常使用

API 请求

  • 所有 API 请求携带正确的 token
  • 请求路径正确(/urban-lifeline/
  • WebSocket 连接正常
  • 文件上传功能正常

部署说明

1. 编译

npm run build:mp-weixin

2. 上传

  • 使用微信开发者工具打开 unpackage/dist/build/mp-weixin
  • 点击"上传"按钮
  • 填写版本号和备注

3. 提交审核

  • 登录微信公众平台
  • 进入"版本管理"
  • 提交审核

4. 发布

  • 审核通过后,点击"发布"
  • 用户即可使用

总结

当前方案是最简洁、最友好的登录方案:

  • 无需任何用户操作
  • 无需小程序认证
  • 代码简洁易维护
  • 用户体验极佳
  • 适用于所有场景

可以直接部署使用!