227 lines
5.6 KiB
Markdown
227 lines
5.6 KiB
Markdown
|
|
# 租户登录使用指南
|
|||
|
|
|
|||
|
|
## 概述
|
|||
|
|
|
|||
|
|
系统已完整支持多租户登录功能,每个租户可以独立访问系统,数据完全隔离。
|
|||
|
|
|
|||
|
|
## 租户识别方式
|
|||
|
|
|
|||
|
|
系统支持以下方式识别租户:
|
|||
|
|
|
|||
|
|
### 1. URL参数方式(推荐)
|
|||
|
|
|
|||
|
|
在登录页面URL中添加 `tenant` 参数:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
http://your-domain.com/login?tenant=tenant-a
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
登录页面会自动识别租户编码,并在登录时自动发送。
|
|||
|
|
|
|||
|
|
### 2. 登录表单输入
|
|||
|
|
|
|||
|
|
如果URL中没有租户参数,登录页面会显示租户编码输入框,用户可以手动输入。
|
|||
|
|
|
|||
|
|
### 3. 请求头方式
|
|||
|
|
|
|||
|
|
前端会自动将租户信息添加到所有API请求的请求头中:
|
|||
|
|
- `X-Tenant-Code`: 租户编码
|
|||
|
|
- `X-Tenant-Id`: 租户ID
|
|||
|
|
|
|||
|
|
## 使用流程
|
|||
|
|
|
|||
|
|
### 方式一:通过URL参数访问(推荐)
|
|||
|
|
|
|||
|
|
1. **访问租户登录页面**
|
|||
|
|
```
|
|||
|
|
http://your-domain.com/login?tenant=tenant-a
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
2. **输入用户名和密码**
|
|||
|
|
- 用户名:租户内的用户名
|
|||
|
|
- 密码:用户密码
|
|||
|
|
- 租户编码:已自动填充(从URL参数)
|
|||
|
|
|
|||
|
|
3. **登录成功**
|
|||
|
|
- 系统自动保存租户信息到 localStorage
|
|||
|
|
- 后续所有API请求都会自动携带租户信息
|
|||
|
|
- 用户只能看到和操作自己租户的数据
|
|||
|
|
|
|||
|
|
### 方式二:手动输入租户编码
|
|||
|
|
|
|||
|
|
1. **访问登录页面**
|
|||
|
|
```
|
|||
|
|
http://your-domain.com/login
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
2. **输入租户信息**
|
|||
|
|
- 租户编码:输入租户编码(如:`tenant-a`)
|
|||
|
|
- 用户名:租户内的用户名
|
|||
|
|
- 密码:用户密码
|
|||
|
|
|
|||
|
|
3. **登录成功**
|
|||
|
|
- 系统保存租户信息
|
|||
|
|
- 后续请求自动携带租户信息
|
|||
|
|
|
|||
|
|
## 后端API使用
|
|||
|
|
|
|||
|
|
### 登录接口
|
|||
|
|
|
|||
|
|
**请求:**
|
|||
|
|
```bash
|
|||
|
|
POST /api/auth/login
|
|||
|
|
Content-Type: application/json
|
|||
|
|
|
|||
|
|
{
|
|||
|
|
"username": "user1",
|
|||
|
|
"password": "password123",
|
|||
|
|
"tenantCode": "tenant-a" // 可选,也可以从请求头获取
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**或者通过请求头:**
|
|||
|
|
```bash
|
|||
|
|
POST /api/auth/login
|
|||
|
|
X-Tenant-Code: tenant-a
|
|||
|
|
Content-Type: application/json
|
|||
|
|
|
|||
|
|
{
|
|||
|
|
"username": "user1",
|
|||
|
|
"password": "password123"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**响应:**
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|||
|
|
"user": {
|
|||
|
|
"id": 1,
|
|||
|
|
"username": "user1",
|
|||
|
|
"nickname": "用户1",
|
|||
|
|
"email": "user1@example.com",
|
|||
|
|
"tenantId": 2,
|
|||
|
|
"tenantCode": "tenant-a",
|
|||
|
|
"roles": ["admin"],
|
|||
|
|
"permissions": ["user:read", "user:create", ...]
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 其他API请求
|
|||
|
|
|
|||
|
|
登录后,所有API请求都会自动携带租户信息(通过JWT Token或请求头),后端会自动过滤数据:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
GET /api/users
|
|||
|
|
Authorization: Bearer <token>
|
|||
|
|
X-Tenant-Code: tenant-a # 自动添加
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
返回的数据只会包含该租户的用户。
|
|||
|
|
|
|||
|
|
## 前端实现细节
|
|||
|
|
|
|||
|
|
### 1. 登录页面自动识别租户
|
|||
|
|
|
|||
|
|
登录页面 (`Login.vue`) 会:
|
|||
|
|
- 从URL参数 `?tenant=xxx` 获取租户编码
|
|||
|
|
- 如果URL中没有,从 localStorage 读取之前保存的租户编码
|
|||
|
|
- 如果都没有,显示租户输入框
|
|||
|
|
|
|||
|
|
### 2. 请求拦截器自动添加租户信息
|
|||
|
|
|
|||
|
|
所有API请求都会自动添加租户信息到请求头:
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// utils/request.ts
|
|||
|
|
service.interceptors.request.use((config) => {
|
|||
|
|
const tenantCode = getTenantCode();
|
|||
|
|
const tenantId = getTenantId();
|
|||
|
|
|
|||
|
|
if (tenantCode) {
|
|||
|
|
config.headers['X-Tenant-Code'] = tenantCode;
|
|||
|
|
}
|
|||
|
|
if (tenantId) {
|
|||
|
|
config.headers['X-Tenant-Id'] = tenantId;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return config;
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 登录后保存租户信息
|
|||
|
|
|
|||
|
|
登录成功后,系统会自动保存:
|
|||
|
|
- Token
|
|||
|
|
- 租户编码 (tenantCode)
|
|||
|
|
- 租户ID (tenantId)
|
|||
|
|
|
|||
|
|
这些信息保存在 localStorage 中,页面刷新后仍然有效。
|
|||
|
|
|
|||
|
|
## 示例场景
|
|||
|
|
|
|||
|
|
### 场景1:租户A的用户登录
|
|||
|
|
|
|||
|
|
1. 访问:`http://your-domain.com/login?tenant=tenant-a`
|
|||
|
|
2. 输入用户名和密码
|
|||
|
|
3. 登录后只能看到租户A的数据
|
|||
|
|
|
|||
|
|
### 场景2:租户B的用户登录
|
|||
|
|
|
|||
|
|
1. 访问:`http://your-domain.com/login?tenant=tenant-b`
|
|||
|
|
2. 输入用户名和密码
|
|||
|
|
3. 登录后只能看到租户B的数据
|
|||
|
|
4. 租户A的数据完全不可见
|
|||
|
|
|
|||
|
|
### 场景3:超级租户管理员登录
|
|||
|
|
|
|||
|
|
1. 访问:`http://your-domain.com/login?tenant=super`
|
|||
|
|
2. 使用超级管理员账号登录
|
|||
|
|
3. 可以管理所有租户
|
|||
|
|
|
|||
|
|
## 注意事项
|
|||
|
|
|
|||
|
|
1. **租户编码必须唯一**:每个租户都有唯一的编码(code)
|
|||
|
|
2. **用户属于特定租户**:用户只能登录到自己所属的租户
|
|||
|
|
3. **数据完全隔离**:不同租户的数据完全隔离,无法互相访问
|
|||
|
|
4. **租户信息持久化**:登录后租户信息保存在 localStorage,刷新页面不会丢失
|
|||
|
|
5. **切换租户**:如果需要切换租户,需要先登出,然后使用新的租户编码登录
|
|||
|
|
|
|||
|
|
## 故障排查
|
|||
|
|
|
|||
|
|
### 问题1:登录时提示"无法确定租户信息"
|
|||
|
|
|
|||
|
|
**原因**:没有提供租户编码或租户ID
|
|||
|
|
|
|||
|
|
**解决**:
|
|||
|
|
- 在URL中添加 `?tenant=xxx` 参数
|
|||
|
|
- 或者在登录表单中输入租户编码
|
|||
|
|
- 或者通过请求头 `X-Tenant-Code` 提供
|
|||
|
|
|
|||
|
|
### 问题2:登录时提示"用户不属于该租户"
|
|||
|
|
|
|||
|
|
**原因**:用户不属于指定的租户
|
|||
|
|
|
|||
|
|
**解决**:
|
|||
|
|
- 确认租户编码是否正确
|
|||
|
|
- 确认用户是否属于该租户
|
|||
|
|
- 联系管理员检查用户和租户的关联关系
|
|||
|
|
|
|||
|
|
### 问题3:登录后看不到数据
|
|||
|
|
|
|||
|
|
**原因**:可能是租户信息没有正确传递
|
|||
|
|
|
|||
|
|
**解决**:
|
|||
|
|
- 检查浏览器控制台的网络请求,确认请求头中是否包含 `X-Tenant-Code`
|
|||
|
|
- 检查 localStorage 中是否保存了租户信息
|
|||
|
|
- 确认后端是否正确识别了租户
|
|||
|
|
|
|||
|
|
## 开发建议
|
|||
|
|
|
|||
|
|
1. **使用URL参数方式**:这是最用户友好的方式,用户只需要记住租户的访问链接
|
|||
|
|
2. **提供租户选择器**:如果系统需要支持租户切换,可以在前端添加租户选择器
|
|||
|
|
3. **错误提示优化**:当租户信息缺失时,提供清晰的错误提示
|
|||
|
|
4. **租户信息显示**:在用户界面显示当前租户信息,让用户知道自己在哪个租户下操作
|
|||
|
|
|