141 lines
4.5 KiB
Markdown
141 lines
4.5 KiB
Markdown
---
|
||
title: 登录与鉴权
|
||
description: 登录、凭证携带、会话顶替与登录日志
|
||
pageClass: g3-api
|
||
---
|
||
|
||
# 登录与鉴权
|
||
|
||
除 `/auth/login` 外,**所有接口都需要携带凭证**。
|
||
|
||
## `POST` `/auth/login`
|
||
|
||
<G3ApiParams title="请求字段">
|
||
|
||
| 字段 | 类型 | 必填 | 说明 |
|
||
|---|---|---|---|
|
||
| `orgid` | string | 是 | 机构码,决定登录到**哪个机构的库** |
|
||
| `userid` | string | 是 | 用户账号(`b_user.b_id`) |
|
||
| `password` | string | 是 | 密码 |
|
||
|
||
</G3ApiParams>
|
||
|
||
<G3ApiPayload title="请求">
|
||
|
||
```bash
|
||
curl -X POST http://localhost:8088/api/auth/login \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"orgid":"G3HD","userid":"g3soft","password":"******"}'
|
||
```
|
||
|
||
</G3ApiPayload>
|
||
|
||
<G3ApiPayload title="登录成功" :code="0">
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "操作成功",
|
||
"data": {
|
||
"token": "eyJhbGciOiJIUzI1NiJ9...",
|
||
"orgid": "G3HD",
|
||
"user": {
|
||
"id": "g3soft",
|
||
"account": "g3soft",
|
||
"name": "G3Soft"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
</G3ApiPayload>
|
||
|
||
<G3ApiPayload title="账号或密码错误" :code="401">
|
||
|
||
```json
|
||
{
|
||
"code": 401,
|
||
"message": "机构码、账号或密码错误",
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
</G3ApiPayload>
|
||
|
||
**几点要注意**:
|
||
|
||
- **机构码会归一化**:去掉首尾空白并转大写,所以传 `g3hd` 与 `G3HD` 等价。
|
||
- **机构码决定数据源**:登录时按机构码加载该机构的数据库配置;机构码不存在或配置缺失会失败。
|
||
- **「账号不存在」与「密码错误」对外是同一个提示**(`机构码、账号或密码错误`),不区分——避免被用来探测账号是否存在。但**登录日志里会分别记录**真实原因,便于排查。
|
||
- **`user.id` 与 `user.account` 目前是同一个值**(字符串业务键方案:`b_user.b_id` 即账号本身)。
|
||
- 用户编码与机构码都会写进 JWT,后续请求据此路由数据源与判定权限。
|
||
|
||
## 携带凭证
|
||
|
||
所有后续请求在请求头带 Bearer token:
|
||
|
||
```bash
|
||
curl -X POST http://localhost:8088/api/data/page \
|
||
-H 'Content-Type: application/json' \
|
||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...' \
|
||
-d '{"view_name":"v_b_othercompany","order_by":"b_id ASC"}'
|
||
```
|
||
|
||
| 场景 | 结果 |
|
||
|---|---|
|
||
| 缺少或格式不对的 `Authorization` | `401` |
|
||
| token 无效 / 过期 / 签名不符 | `401` |
|
||
| token 有效但**会话已被顶替** | `40101` |
|
||
| `OPTIONS` 预检请求 | **放行**(不校验) |
|
||
| `/auth/login` | **放行**(唯一不需要凭证的业务接口) |
|
||
|
||
> **HTTP 状态码始终是 200**,鉴权失败靠响应体的 `code`(`401` / `40101`)判断。
|
||
> 不要用 HTTP 状态码或 axios 的错误拦截分支处理鉴权失败。
|
||
|
||
## 会话与顶替
|
||
|
||
服务端维护**活动会话表**,同一个「机构 + 账号」只保留一个有效会话:
|
||
|
||
```text
|
||
登录 → 生成 sessionId → 登记为活动会话
|
||
再次登录同一账号 → 旧会话被顶替
|
||
旧 token 继续用 → 返回 40101(账号已在其他设备登录)
|
||
```
|
||
|
||
**前端处理**:拿到 `401` 或 `40101` 都应**清 token、回登录页**。`40101` 建议给一句「账号已在其他设备登录」,比笼统的「登录已失效」更有助于用户理解。
|
||
|
||
> 会话是**内存态**:服务重启后全部失效,用户需重新登录。
|
||
|
||
## 登录日志
|
||
|
||
每次登录尝试都会记录,含成功与失败:
|
||
|
||
| 记录内容 | 说明 |
|
||
|---|---|
|
||
| 机构码、用户账号 | 尝试登录的身份 |
|
||
| 成功 / 失败、失败原因 | 「账号不存在」/「密码错误」 |
|
||
| 会话 ID | 登录成功时 |
|
||
| 客户端信息 | 浏览器、操作系统、设备类型 |
|
||
| IP 与归属地 | 来源地址解析 |
|
||
|
||
查询入口:`v_s_log_login` 视图(走通用查询接口)。日志表本身**不需要登录权限之外的特殊授权**,但建议只给管理员开放。
|
||
|
||
## 相关配置
|
||
|
||
| 配置项 | 说明 |
|
||
|---|---|
|
||
| `erp.auth.jwt-secret` | 签名密钥,**生产必须改**(默认值仅用于开发) |
|
||
| `erp.auth.jwt-expiration` | token 有效期,默认 `24h` |
|
||
| `erp.database.config-dir` | 机构数据库配置目录,登录时按机构码在此查找 |
|
||
|
||
## 常见错误
|
||
|
||
| 场景 | code | 说明 |
|
||
|---|---|---|
|
||
| 机构码为空 | `1000` | 「机构码不能为空」 |
|
||
| 用户 ID 为空 | `1000` | 「用户ID不能为空」 |
|
||
| 机构码、账号或密码错误 | `401` | 三者统一提示 |
|
||
| 机构码在配置目录里不存在 | `401` | 加载机构配置失败时按机构码错误处理 |
|
||
| 未带凭证访问其他接口 | `401` | —— |
|
||
| 会话被顶替 | `40101` | 需重新登录 |
|