# 认证系统使用指南

本文档说明如何在项目中使用认证系统。

## 认证流程

### 1. 应用启动流程

```
应用启动
    ↓
进入首页 (pages/index/index.vue)
    ↓
检查 Token
    ↓
┌─────────────┬─────────────┐
│  Token 有效  │  Token 无效  │
└─────────────┴─────────────┘
       ↓              ↓
   显示首页      跳转登录页
```

### 2. 登录流程

```
用户点击登录
    ↓
获取微信 code
    ↓
调用后端登录接口
    ↓
保存 token 和用户信息
    ↓
跳转到首页
```

### 3. Token 验证流程

```
页面加载
    ↓
检查本地 token
    ↓
调用 GetUserProfile 接口验证
    ↓
┌─────────────┬─────────────┐
│   验证成功   │   验证失败   │
└─────────────┴─────────────┘
       ↓              ↓
  更新用户信息    清除数据并跳转登录页
```

## 认证工具使用

### 引入认证工具

```javascript
import { 
  isLoggedIn, 
  getCurrentUser, 
  requireAuth, 
  logout 
} from '@/utils/auth.js'
```

### 常用方法

#### 1. 检查是否已登录

```javascript
if (isLoggedIn()) {
  console.log('用户已登录')
} else {
  console.log('用户未登录')
}
```

#### 2. 获取当前用户信息

```javascript
const user = getCurrentUser()
if (user) {
  console.log('用户昵称:', user.nickname)
  console.log('用户头像:', user.avatar)
}
```

#### 3. 要求登录（未登录则跳转）

```javascript
// 在需要登录的页面中使用
onLoad() {
  // 检查登录状态，未登录则跳转到登录页
  if (!requireAuth()) {
    return // 未登录，已跳转
  }
  
  // 已登录，继续执行
  this.loadData()
}
```

#### 4. 登出

```javascript
async handleLogout() {
  uni.showModal({
    title: '提示',
    content: '确定要退出登录吗？',
    success: async (res) => {
      if (res.confirm) {
        await logout()
      }
    }
  })
}
```

#### 5. 验证 Token

```javascript
import { validateToken } from '@/utils/auth.js'

async checkToken() {
  const isValid = await validateToken()
  if (isValid) {
    console.log('Token 有效')
  } else {
    console.log('Token 无效')
  }
}
```

#### 6. 刷新 Token

```javascript
import { refreshToken } from '@/utils/auth.js'

async refreshAuthToken() {
  const success = await refreshToken()
  if (success) {
    console.log('Token 刷新成功')
  } else {
    console.log('Token 刷新失败')
  }
}
```

## 在页面中使用

### 示例 1: 需要登录的页面

```vue
<template>
  <view class="page">
    <view v-if="user">
      <text>欢迎，{{ user.nickname }}</text>
    </view>
  </view>
</template>

<script>
import { requireAuth, getCurrentUser } from '@/utils/auth.js'

export default {
  data() {
    return {
      user: null
    }
  },
  onLoad() {
    // 检查登录状态
    if (!requireAuth()) {
      return
    }
    
    // 获取用户信息
    this.user = getCurrentUser()
  }
}
</script>
```

### 示例 2: 个人中心页面

```vue
<template>
  <view class="page">
    <view class="user-info">
      <image :src="user.avatar" class="avatar"></image>
      <text class="nickname">{{ user.nickname }}</text>
    </view>
    
    <button @click="handleLogout">退出登录</button>
  </view>
</template>

<script>
import { getCurrentUser, logout } from '@/utils/auth.js'

export default {
  data() {
    return {
      user: null
    }
  },
  onLoad() {
    this.user = getCurrentUser()
  },
  methods: {
    async handleLogout() {
      uni.showModal({
        title: '提示',
        content: '确定要退出登录吗？',
        success: async (res) => {
          if (res.confirm) {
            await logout()
          }
        }
      })
    }
  }
}
</script>
```

### 示例 3: 条件显示登录按钮

```vue
<template>
  <view class="page">
    <button v-if="!isLoggedIn" @click="goToLogin">登录</button>
    <view v-else>
      <text>已登录</text>
    </view>
  </view>
</template>

<script>
import { isLoggedIn } from '@/utils/auth.js'

export default {
  data() {
    return {
      isLoggedIn: false
    }
  },
  onShow() {
    this.isLoggedIn = isLoggedIn()
  },
  methods: {
    goToLogin() {
      uni.navigateTo({
        url: '/pages/login/login-page'
      })
    }
  }
}
</script>
```

## 全局数据访问

### 在页面中访问全局用户数据

```javascript
const app = getApp()

// 获取 token
const token = app.globalData.token

// 获取用户信息
const user = app.globalData.user

// 检查是否需要刷新
if (app.globalData.shouldRefresh) {
  // 执行刷新操作
  this.refreshData()
  app.globalData.shouldRefresh = false
}
```

## API 请求中的认证

AppServer 会自动在请求头中添加 Authorization，无需手动处理：

```javascript
import { AppServer } from '@/modules/api/AppServer'

const appServer = new AppServer()

// 自动携带 token
const result = await appServer.GetUserProfile()
```

## 错误处理

### Token 过期处理

当 API 返回 401 错误时，说明 token 已过期：

```javascript
const result = await appServer.GetUserProfile()

if (!result.success && result.error?.code === 'UNAUTHORIZED') {
  // Token 过期，尝试刷新
  const refreshSuccess = await refreshToken()
  
  if (refreshSuccess) {
    // 刷新成功，重试请求
    const retryResult = await appServer.GetUserProfile()
  } else {
    // 刷新失败，跳转登录页
    clearAuthData()
    uni.reLaunch({ url: '/pages/login/login-page' })
  }
}
```

## 注意事项

1. **首页自动检查**: 首页会自动检查登录状态，无需手动调用
2. **Token 格式**: Token 格式为 `Bearer <token>`
3. **本地存储**: Token 和用户信息同时存储在 localStorage 和 globalData
4. **登出清理**: 登出时会清除所有认证相关数据
5. **页面刷新**: 使用 `reLaunch` 跳转登录页，确保页面栈清空

## 调试技巧

### 查看当前登录状态

```javascript
console.log('Token:', uni.getStorageSync('token'))
console.log('User:', uni.getStorageSync('user'))
console.log('RefreshToken:', uni.getStorageSync('refreshToken'))
```

### 清除登录状态（用于测试）

```javascript
import { clearAuthData } from '@/utils/auth.js'

// 清除所有认证数据
clearAuthData()

// 跳转到登录页
uni.reLaunch({ url: '/pages/login/login-page' })
```

### 模拟登录（用于开发测试）

```javascript
import { saveAuthData } from '@/utils/auth.js'

// 保存测试数据
saveAuthData(
  'Bearer test-token',
  'test-refresh-token',
  {
    id: 'test-user-id',
    nickname: '测试用户',
    avatar: 'https://...'
  }
)
```

## 常见问题

### Q: 为什么每次打开应用都要重新登录？
A: 检查 token 是否正确保存到 localStorage，确认 `saveAuthData` 方法被正确调用。

### Q: 如何在多个页面间共享用户信息？
A: 使用 `getCurrentUser()` 方法或访问 `getApp().globalData.user`。

### Q: Token 过期后如何自动刷新？
A: 使用 `refreshToken()` 方法，建议在 API 返回 401 时自动调用。

### Q: 如何实现"记住我"功能？
A: Token 默认会保存到 localStorage，下次打开应用会自动恢复。

### Q: 如何处理网络错误？
A: 在 `validateToken` 失败时，可以选择不跳转登录页，而是显示错误提示。

## 相关文档

- [API 使用指南](./modules/api/API_GUIDE.md)
- [配置指南](./CONFIG_GUIDE.md)
- [登录指南](./LOGIN_GUIDE.md)
