用户认证与管理的核心服务,负责注册、登录、用户 CRUD、密码管理。支持 Admin 和 Customer 两种用户类型,认证方式分别为 Session Cookie(Admin)和 JWT Bearer(Customer)。
| RPC | 描述 | 权限 |
| Register | 注册新用户(自动创建关联 Customer) | 公开 |
| SendVerificationCode | 发送邮箱验证码 | 公开 |
| Login | 登录(admin 返回 session cookie,customer 返回 JWT) | 公开 |
| RefreshToken | 刷新 access token(仅 customer) | 公开 |
| ListUsers | 用户列表(分页+筛选) | admin |
| GetUser | 获取单个用户 | admin |
| UpdateUser | 更新用户信息 | admin |
| DeleteUser | 删除用户 | admin-only |
| ChangePassword | 修改自己的密码 | 已认证 |
| AdminResetPassword | 管理员重置他人密码 | admin-only |
| GetMe | 获取当前登录用户信息 | 已认证 |
| Logout | 登出(admin 清除 session,customer 客户端删 token) | 已认证 |
注册新 customer 用户,自动创建关联的 Customer 记录。
| 字段 | 类型 | 编号 | 必填 | 描述 |
| username | string | 1 | 是 | 用户名 |
| email | string | 2 | 是 | 邮箱地址 |
| display_name | string | 3 | 是 | 显示名称 |
| password | string | 4 | 是 | 登录密码 |
| verification_code | string | 5 | 是 | 邮箱验证码 |
| 字段 | 类型 | 编号 | 描述 |
| user | UserInfo | 1 | 新创建的用户信息 |
| customer_id | string | 2 | 自动创建的关联 Customer ID |
| 错误 | 说明 |
| InvalidArgument | 验证码无效或已过期、用户名已存在、密码不符合要求 |
| AlreadyExists | 邮箱已被注册 |
grpcurl -plaintext \
-d '{"username":"testuser","email":"[email protected]","display_name":"Test","password":"Pass123!","verification_code":"123456"}' \
localhost:50051 rustbill.identity.IdentityService/Register
const resp = await api.register({
username: "testuser",
email: "[email protected]",
display_name: "Test",
password: "Pass123!",
verification_code: "123456"
});
// resp.user, resp.customer_id
向指定邮箱发送验证码,用于注册或密码重置流程。
| 字段 | 类型 | 编号 | 必填 | 描述 |
| email | string | 1 | 是 | 接收验证码的邮箱 |
| purpose | string | 2 | 是 | 用途:"registration" 或 "password_reset" |
| 字段 | 类型 | 编号 | 描述 |
| sent | bool | 1 | 是否发送成功 |
| message | string | 2 | 提示信息 |
| retry_after_secs | int32 | 3 | 多少秒后可重新发送 |
| 错误 | 说明 |
| InvalidArgument | 邮箱格式无效、发送频率过高 |
| Internal | 邮件服务不可用 |
grpcurl -plaintext \
-d '{"email":"[email protected]","purpose":"registration"}' \
localhost:50051 rustbill.identity.IdentityService/SendVerificationCode
const resp = await api.sendVerificationCode({
email: "[email protected]",
purpose: "registration"
});
// resp.sent, resp.retry_after_secs
用户登录。user_type="admin" 时返回 session cookie(Set-Cookie 响应头),user_type="customer" 时返回 JWT token 对。
| 字段 | 类型 | 编号 | 必填 | 描述 |
| username | string | 1 | 是 | 用户名 |
| password | string | 2 | 是 | 密码 |
| user_type | string | 3 | 是 | 用户类型:"admin" 或 "customer" |
| 字段 | 类型 | 编号 | 描述 |
| access_token | string | 1 | JWT access token(仅 customer) |
| refresh_token | string | 2 | JWT refresh token(仅 customer) |
| expires_in | int64 | 3 | token 过期时间(秒) |
| user | UserInfo | 4 | 当前用户信息 |
| admin_path | string | 5 | Admin 面板路径(来自服务端配置) |
| 错误 | 说明 |
| InvalidArgument | 用户名或密码错误 |
| PermissionDenied | 用户已禁用 |
| NotFound | 用户不存在 |
# Admin 登录
grpcurl -plaintext \
-d '{"username":"admin","password":"admin123","user_type":"admin"}' \
localhost:50051 rustbill.identity.IdentityService/Login
# Customer 登录
grpcurl -plaintext \
-d '{"username":"customer1","password":"pass123","user_type":"customer"}' \
localhost:50051 rustbill.identity.IdentityService/Login
const resp = await api.login({
username: "customer1",
password: "pass123",
user_type: "customer"
});
// resp.access_token → 存入 localStorage
// resp.user → 存入 auth store
使用 refresh token 获取新的 access token(仅 customer 用户)。
| 字段 | 类型 | 编号 | 必填 | 描述 |
| refresh_token | string | 1 | 是 | 有效的 refresh token |
| 字段 | 类型 | 编号 | 描述 |
| access_token | string | 1 | 新的 access token |
| expires_in | int64 | 2 | 过期时间(秒) |
| refresh_token | string | 3 | 新的 refresh token(轮换) |
| 错误 | 说明 |
| InvalidArgument | refresh token 无效或已过期 |
grpcurl -plaintext \
-d '{"refresh_token":"eyJhbGciOiJIUzI1NiIs..."}' \
localhost:50051 rustbill.identity.IdentityService/RefreshToken
const resp = await api.refreshToken({
refresh_token: localStorage.getItem("rustbill_customer_refresh")
});
// 更新 localStorage 中的 token
分页查询用户列表,支持按角色、状态、用户类型、关键词、客户 ID 筛选。
| 字段 | 类型 | 编号 | 必填 | 描述 |
| pagination | PageRequest | 1 | 是 | 分页参数 |
| role | string? | 2 | 否 | 角色过滤("admin" / "operator") |
| is_active | bool? | 3 | 否 | 启用状态过滤 |
| search | string? | 4 | 否 | 用户名/邮箱搜索 |
| user_type | string? | 5 | 否 | 用户类型:"admin" 或 "customer",不填默认 admin |
| customer_id | string? | 6 | 否 | 按关联客户过滤(仅 user_type=“customer” 时有效) |
| 字段 | 类型 | 编号 | 描述 |
| users | repeated UserInfo | 1 | 用户列表 |
| meta | PageMeta | 2 | 分页元数据 |
| 错误 | 说明 |
| PermissionDenied | 非 admin 用户 |
grpcurl -plaintext -H "authorization: Bearer <token>" \
-d '{"pagination":{"page":1,"page_size":20},"user_type":"customer","is_active":true}' \
localhost:50051 rustbill.identity.IdentityService/ListUsers
const resp = await api.listUsers({
pagination: { page: 1, page_size: 20 },
user_type: "customer",
is_active: true
});
获取单个用户的详细信息。
| 字段 | 类型 | 编号 | 必填 | 描述 |
| id | string | 1 | 是 | 用户 ID(UUID) |
| user_type | string? | 2 | 否 | 用户类型提示,避免回退查询 |
| 字段 | 类型 | 编号 | 描述 |
| user | UserInfo | 1 | 用户信息 |
| 错误 | 说明 |
| NotFound | 用户不存在 |
| PermissionDenied | 非 admin 用户 |
grpcurl -plaintext -H "authorization: Bearer <token>" \
-d '{"id":"0192a123-4567-7890-abcd-ef0123456789"}' \
localhost:50051 rustbill.identity.IdentityService/GetUser
更新用户信息(邮箱、显示名称、角色、状态等)。
| 字段 | 类型 | 编号 | 必填 | 描述 |
| id | string | 1 | 是 | 用户 ID |
| email | string? | 2 | 否 | 新邮箱 |
| display_name | string? | 3 | 否 | 新显示名称 |
| role | string? | 4 | 否 | 新角色(仅 user_type=“admin” 时有效) |
| is_active | bool? | 5 | 否 | 启用/禁用 |
| user_type | string? | 6 | 否 | 用户类型 |
| customer_id | string? | 7 | 否 | 关联客户 ID(仅 user_type=“customer” 时有效) |
| 字段 | 类型 | 编号 | 描述 |
| user | UserInfo | 1 | 更新后的用户信息 |
| 错误 | 说明 |
| NotFound | 用户不存在 |
| InvalidArgument | 参数校验失败 |
| PermissionDenied | 非 admin 用户 |
grpcurl -plaintext -H "authorization: Bearer <token>" \
-d '{"id":"0192a123-...","display_name":"New Name","is_active":true}' \
localhost:50051 rustbill.identity.IdentityService/UpdateUser
删除指定用户(仅 Admin 角色可操作)。
| 字段 | 类型 | 编号 | 必填 | 描述 |
| id | string | 1 | 是 | 用户 ID(UUID) |
无字段。
| 错误 | 说明 |
| NotFound | 用户不存在 |
| PermissionDenied | 非 Admin 角色 |
grpcurl -plaintext -H "authorization: Bearer <token>" \
-d '{"id":"0192a123-4567-7890-abcd-ef0123456789"}' \
localhost:50051 rustbill.identity.IdentityService/DeleteUser
当前登录用户修改自己的密码(需提供旧密码验证)。
| 字段 | 类型 | 编号 | 必填 | 描述 |
| old_password | string | 1 | 是 | 当前密码 |
| new_password | string | 2 | 是 | 新密码 |
无字段。
| 错误 | 说明 |
| InvalidArgument | 旧密码错误、新密码不符合要求 |
| Unauthenticated | 未登录 |
grpcurl -plaintext -H "authorization: Bearer <token>" \
-d '{"old_password":"oldpass","new_password":"newpass123!"}' \
localhost:50051 rustbill.identity.IdentityService/ChangePassword
const resp = await api.changePassword({
old_password: "oldpass",
new_password: "newpass123!"
});
管理员重置指定用户的密码(仅 Admin 角色可操作,无需旧密码)。
| 字段 | 类型 | 编号 | 必填 | 描述 |
| user_id | string | 1 | 是 | 目标用户 ID |
| new_password | string | 2 | 是 | 新密码 |
无字段。
| 错误 | 说明 |
| NotFound | 用户不存在 |
| PermissionDenied | 非 Admin 角色 |
grpcurl -plaintext -H "authorization: Bearer <token>" \
-d '{"user_id":"0192a123-...","new_password":"resetpass123!"}' \
localhost:50051 rustbill.identity.IdentityService/AdminResetPassword
获取当前登录用户的个人信息。Admin 用户从 session cookie 恢复身份,Customer 用户从 JWT 解析。
无字段。
| 字段 | 类型 | 编号 | 描述 |
| user | UserInfo | 1 | 当前用户信息 |
# Admin: cookie 自动携带
grpcurl -plaintext -H "cookie: rustbill_session=..." \
-d '{}' \
localhost:50051 rustbill.identity.IdentityService/GetMe
# Customer: JWT Bearer
grpcurl -plaintext -H "authorization: Bearer <token>" \
-d '{}' \
localhost:50051 rustbill.identity.IdentityService/GetMe
// Admin SPA (credentials: 'include' 自动携带 cookie)
const resp = await api.getMe({});
// Customer SPA
const resp = await api.getMe({});
登出当前用户。Admin 端清除 session cookie,Customer 端客户端自行删除本地 token。
无字段。
无字段。
grpcurl -plaintext -H "authorization: Bearer <token>" \
-d '{}' \
localhost:50051 rustbill.identity.IdentityService/Logout
const resp = await api.logout({});
// 清除 localStorage 中的 token
localStorage.removeItem("rustbill_customer_token");
localStorage.removeItem("rustbill_customer_refresh");
| 字段 | 类型 | 编号 | 描述 |
| id | string | 1 | 用户 UUID |
| username | string | 2 | 用户名 |
| email | string | 3 | 邮箱地址 |
| display_name | string | 4 | 显示名称 |
| role | string | 5 | 角色:"admin" / "operator"(admin 用户);空字符串(customer 用户) |
| is_active | bool | 6 | 是否启用 |
| created_at | string | 7 | 创建时间(RFC3339) |
| user_type | string | 8 | 用户类型:"admin" / "customer" |
| customer_id | string | 9 | 关联的 Customer ID(admin 用户为空字符串) |