Files
workspace/code/g3soft-libs/docs/content/api/auth.md
T
2026-10-13 22:32:50 +08:00

141 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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` | 需重新登录 |