100 lines
3.6 KiB
Plaintext
100 lines
3.6 KiB
Plaintext
|
|
%% 4.1 员工端 OAuth 静默授权(snsapi_base → ?token= 镜像)
|
|||
|
|
sequenceDiagram
|
|||
|
|
participant U as 员工(企微WebView)
|
|||
|
|
participant H5 as H5前端(/itdesk/)
|
|||
|
|
participant R as 路由守卫
|
|||
|
|
participant B as 后端(/api/h5)
|
|||
|
|
participant W as 企微OAuth
|
|||
|
|
U->>H5: 打开 /itdesk/
|
|||
|
|
H5->>R: beforeEach 守卫
|
|||
|
|
R->>R: 读 ?token=(无) / ?code=(无) / 无 token
|
|||
|
|
R->>B: GET /h5/oauth/authorize (prod 校验 wxwork UA)
|
|||
|
|
B-->>R: {authorize_url}
|
|||
|
|
R->>W: 302 跳转企微授权页
|
|||
|
|
W-->>H5: 回调 redirect_uri?code=CODE
|
|||
|
|
H5->>B: GET /h5/oauth/sns-callback?code=CODE
|
|||
|
|
B->>W: code 换 userid + 用户信息
|
|||
|
|
B->>B: 生成 employee token 存 Redis(employee:token:)
|
|||
|
|
B-->>H5: 302 /itdesk/?token=XXX
|
|||
|
|
H5->>R: 守卫读 ?token=XXX
|
|||
|
|
R->>R: localStorage.h5_token = XXX;replaceState 清除 URL
|
|||
|
|
R->>B: 携带 Bearer 拉取用户信息
|
|||
|
|
B-->>H5: 工作台数据(内层 data)
|
|||
|
|
|
|||
|
|
%% 4.2 坐席/管理 扫码登录(auth_qrcode)
|
|||
|
|
sequenceDiagram
|
|||
|
|
participant A as 坐席/管理员
|
|||
|
|
participant FE as 前端登录页
|
|||
|
|
participant B as 后端(/api/auth_qrcode)
|
|||
|
|
participant WX as 企微App(扫码确认)
|
|||
|
|
participant R as Redis
|
|||
|
|
A->>FE: 点击「企微扫码登录」
|
|||
|
|
FE->>B: POST /auth_qrcode/create
|
|||
|
|
B->>R: 写 ticket(120s) + OAuth URL
|
|||
|
|
B-->>FE: {ticket, qrcode_png_base64}
|
|||
|
|
FE->>FE: 展示二维码 + 2s 轮询
|
|||
|
|
loop 轮询
|
|||
|
|
FE->>B: GET /auth_qrcode/poll/{ticket}
|
|||
|
|
B-->>FE: {status: waiting/scanned}
|
|||
|
|
end
|
|||
|
|
WX->>B: GET /auth_qrcode/scan?code&state=ticket (企微OAuth回调)
|
|||
|
|
B->>R: 写 scan:{ticket}
|
|||
|
|
A->>WX: 在企微点「确认登录」
|
|||
|
|
WX->>B: POST /auth_qrcode/confirm {ticket}
|
|||
|
|
B->>B: 校验身份→签发 token(agent/admin)
|
|||
|
|
B->>R: 写 confirm:{ticket}=token
|
|||
|
|
FE->>B: GET /poll/{ticket} → {status:confirmed, token}
|
|||
|
|
FE->>FE: localStorage.agent_token/admin_token = token
|
|||
|
|
FE->>FE: 跳 /workspace 或 /
|
|||
|
|
|
|||
|
|
%% 4.3 坐席/管理 账号密码 + OTP
|
|||
|
|
sequenceDiagram
|
|||
|
|
participant A as 坐席/管理员
|
|||
|
|
participant FE as 前端登录页
|
|||
|
|
participant B as 后端(/api/agents/login)
|
|||
|
|
participant M as MFAService/Redis
|
|||
|
|
A->>FE: 输入账号+密码,点登录
|
|||
|
|
FE->>B: POST /agents/login {user_id, password}
|
|||
|
|
alt 已绑定 MFA 且无 otp_code
|
|||
|
|
B-->>FE: {require_otp:true, user_id, name, role}(无 token)
|
|||
|
|
FE->>FE: 渲染 OTP 输入框(v-if requireOtp)
|
|||
|
|
A->>FE: 输入 6 位 OTP
|
|||
|
|
FE->>B: POST /agents/login {user_id, password, otp_code}
|
|||
|
|
B->>M: verify_code(mfa_secret, otp_code)
|
|||
|
|
M-->>B: True
|
|||
|
|
B->>B: 签发 token
|
|||
|
|
B-->>FE: {token, user_id, name, role}
|
|||
|
|
else 未绑定 MFA
|
|||
|
|
B-->>FE: {token, ...} 直接登录
|
|||
|
|
end
|
|||
|
|
FE->>FE: localStorage.agent_token/admin_token = token;跳主页
|
|||
|
|
|
|||
|
|
%% 4.4 令牌过期 / 401 处理
|
|||
|
|
sequenceDiagram
|
|||
|
|
participant FE as 三端前端
|
|||
|
|
participant I as 响应拦截器
|
|||
|
|
participant B as 后端
|
|||
|
|
participant R as Redis
|
|||
|
|
FE->>B: 业务请求(Bearer token)
|
|||
|
|
B-->>FE: 401 / {code:1002}
|
|||
|
|
alt H5 员工端
|
|||
|
|
I->>I: 清 h5_token
|
|||
|
|
alt 生产(有 CorpId)
|
|||
|
|
I->>B: 重走 OAuth 重定向(带防循环计数)
|
|||
|
|
else Mock(dev)
|
|||
|
|
I->>FE: 跳 /itdesk/login
|
|||
|
|
end
|
|||
|
|
else 坐席端
|
|||
|
|
I->>B: POST /api/auth/refresh?token=(静默)
|
|||
|
|
B->>R: 延长 user:token TTL
|
|||
|
|
alt 刷新成功
|
|||
|
|
I->>FE: 重放原请求
|
|||
|
|
else 失败
|
|||
|
|
I->>I: 清 agent_token(不再清 portal_token)
|
|||
|
|
I->>FE: 跳 /login
|
|||
|
|
end
|
|||
|
|
else 管理端
|
|||
|
|
I->>I: 清 admin_token
|
|||
|
|
I->>FE: 跳 /login
|
|||
|
|
end
|