# 美国版 App 登录接口说明 ## 概述 美国版移动端认证由 `food-labeling-us` 模块的 **`UsAppAuthAppService`** 提供,采用 ABP 约定式动态 API。宿主统一前缀为 **`/api/app`**,建议以 Swagger 为准核对路径(本地示例:`http://localhost:19001/swagger`,搜索 `UsAppAuth`)。 | 说明 | 内容 | |------|------| | 账号标识 | 使用 **`User.Email`**(邮箱)登录,邮箱比对**忽略大小写** | | 密码 | 与 Web 共用 `User` 表,校验方式与 RBAC **`AccountManager`** 一致(盐值 + `MD5Helper.SHA2Encode`) | | 权限 | **App 登录不校验角色/权限**(允许“未配置权限”的账号登录);H5 管理端再按 RBAC 权限控制 | | 验证码 | 当配置 **`Rbac:EnableCaptcha`** 为 `true` 时,需先拉取图形验证码,本接口入参传 `uuid`、`code`;未开启时可传空或不传 | --- ## 接口 1:App 登录 签发 **Access Token**、**Refresh Token**,并返回当前用户在 **`userlocation`** 中绑定的门店列表(关联 **`location`** 表详情)。 ### HTTP - **方法**:`POST` - **路径**:`/api/app/us-app-auth/login` - **Content-Type**:`application/json` - **鉴权**:无需登录(匿名) ### 请求体参数(UsAppLoginInputVo) | 参数名(JSON) | 类型 | 必填 | 说明 | |----------------|------|------|------| | `email` | string | 是 | 登录邮箱,对应数据库 `User.Email` | | `password` | string | 是 | 明文密码 | | `uuid` | string | 条件 | 图形验证码 UUID;**开启验证码时必填** | | `code` | string | 条件 | 图形验证码;**开启验证码时必填** | ### 传参示例(请求 Body) 未开启图形验证码时: ```json { "email": "admin@example.com", "password": "123456" } ``` 开启图形验证码时(需与系统验证码接口返回的 `uuid`、用户输入的验证码一致): ```json { "email": "test@example.com", "password": "您的密码", "uuid": "验证码接口返回的 uuid", "code": "用户看到的验证码" } ``` ### 响应体(UsAppLoginOutputDto) | 字段(JSON) | 类型 | 说明 | |--------------|------|------| | `token` | string | 访问令牌(Bearer),后续业务接口放在 Header `Authorization: Bearer {token}` | | `refreshToken` | string | 刷新令牌(与系统账号体系一致,用于刷新 access token,具体用法与 Web 一致) | | `locations` | array | 绑定门店列表,元素见下表 | #### `locations[]` 元素(UsAppBoundLocationDto) | 字段(JSON) | 类型 | 说明 | |--------------|------|------| | `id` | string | 门店主键(Guid 字符串) | | `locationCode` | string | 业务编码,如 LOC-1 | | `locationName` | string | 门店名称 | | `fullAddress` | string | 拼接后的完整地址(街道、城市、州、邮编等;无数据时可能为 `"无"`) | | `state` | bool | 门店是否启用 | ### 响应示例 ```json { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "locations": [ { "id": "a2696b9e-2277-11f1-b4c6-00163e0c7c4f", "locationCode": "LOC-1", "locationName": "Downtown Kitchen", "fullAddress": "123 Main St, New York, NY 10001", "state": true } ] } ``` ### 常见错误提示(业务异常文案) - 邮箱或密码为空:`请输入合理数据!` - 邮箱在库中不存在(未删除且启用用户中无匹配邮箱):`登录失败!邮箱不存在!` - 密码错误:`登录失败!用户名或密码错误!`(与 `UserConst.Login_Error` 一致) - 验证码错误(开启验证码时):`验证码错误` --- ## 接口 2:获取当前账号绑定门店 无需重新登录即可刷新 **`userlocation`** 绑定门店列表(例如切换门店前先同步列表)。 ### HTTP - **方法**:`GET` - **路径**:`/api/app/us-app-auth/my-locations` - **鉴权**:需要登录,请求头携带 **`Authorization: Bearer {token}`**(使用接口 1 返回的 `token`) ### 请求参数 无 Query / Body 参数;用户身份由 JWT 解析。 ### 传参示例 ```http GET /api/app/us-app-auth/my-locations HTTP/1.1 Host: localhost:19001 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... ``` 若前端统一约定 GET 使用 `data` 封装,可自行在客户端组装;本接口服务端**不读取额外 Query 参数**。 ### 响应体 与登录接口中 **`locations`** 相同:**`UsAppBoundLocationDto[]`**(数组)。 ### 响应示例 ```json [ { "id": "a2696b9e-2277-11f1-b4c6-00163e0c7c4f", "locationCode": "LOC-1", "locationName": "Downtown Kitchen", "fullAddress": "123 Main St, New York, NY 10001", "state": true } ] ``` ### 常见错误 - 未登录或 Token 无效:按网关/ABP 返回 401 及统一错误体 - 无用户上下文:`用户未登录` --- ## 接口 3:我的资料(My Profile) 用于「My Profile」页展示:全名、邮箱、电话、员工号、角色。 ### HTTP - **方法**:`GET` - **路径**:`/api/app/us-app-auth/my-profile`(以 Swagger 中 `UsAppAuth` 为准) - **鉴权**:需要登录(`Authorization: Bearer {token}`) ### 请求参数 无。 ### 响应体(UsAppMyProfileOutputDto) | 字段(JSON) | 类型 | 说明 | |--------------|------|------| | `fullName` | string | `User.Name`,无则 `Nick`,再无则 `UserName` | | `email` | string | `User.Email`;空为 `"无"` | | `phone` | string | 由 `User.Phone`(long)格式化为可读字符串;10 位数字按 `+1 (555) 123-4567` 形式;无则 `"无"` | | `employeeId` | string | 当前取 **`User.UserName`**(可与业务约定为工号/登录名) | | `roleDisplay` | string | 多角色 `Role.RoleName` 按 `OrderNum` 排序后以英文逗号拼接;无角色为 `"无"` | | `primaryRoleCode` | string \| null | 第一个角色的 `RoleCode`,供前端样式 | --- ## 接口 4:修改密码(Change Password) 与 **`User.JudgePassword` / `BuildPassword`** 一致:校验当前密码后写入新盐值哈希。 ### HTTP - **方法**:`POST` - **路径**:`/api/app/us-app-auth/change-password` - **Content-Type**:`application/json` - **鉴权**:需要登录 ### 请求体(UsAppChangePasswordInputVo) | 字段(JSON) | 类型 | 必填 | 说明 | |--------------|------|------|------| | `currentPassword` | string | 是 | 当前明文密码 | | `newPassword` | string | 是 | 新密码 | | `confirmNewPassword` | string | 是 | 必须与 `newPassword` **完全一致** | ### 新密码复杂度(与原型「Password Requirements」一致) 1. 至少 **8** 位 2. 至少 **1** 个大写字母、**1** 个小写字母 3. 至少 **1** 个数字 4. 至少 **1** 个**非字母数字**字符(特殊字符) ### 请求示例 ```json { "currentPassword": "OldPass1!", "newPassword": "NewPass9@x", "confirmNewPassword": "NewPass9@x" } ``` ### 响应 成功时 HTTP 200,无业务体要求(ABP 可能返回空对象);失败为业务异常文案。 ### 常见错误 - 未登录:`用户未登录` - 当前密码错误:与登录失败一致(`UserConst.Login_Error` 文案) - 新密码与确认不一致:`新密码与确认密码不一致` - 新密码与当前相同:`新密码不能与当前密码相同` - 不满足复杂度:如 `新密码至少 8 位`、`新密码需包含大写字母` 等 --- ## 接口 5:门店详情(Location) 用于移动端「Location」页:店名、完整地址、门店电话、营业时间占位、店长姓名与电话。**仅当当前 JWT 用户在 `userlocation` 中绑定该门店**时可查(与接口 1、2 的门店范围一致)。 ### HTTP - **方法**:`GET` - **路径**:`/api/app/us-app-auth/location-detail`(以 Swagger 中 `UsAppAuth` → `GetLocationDetail` 为准;`locationId` 一般为 **Query** 参数) - **鉴权**:需要登录(`Authorization: Bearer {token}`) ### 请求参数 | 参数名 | 位置 | 类型 | 必填 | 说明 | |--------|------|------|------|------| | `locationId` | Query | string | 是 | 门店主键,Guid 字符串(与 `locations[].id` 一致) | ### 传参示例 ```http GET /api/app/us-app-auth/location-detail?locationId=a2696b9e-2277-11f1-b4c6-00163e0c7c4f HTTP/1.1 Host: localhost:19001 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... ``` ### 响应体(UsAppLocationDetailOutputDto) | 字段(JSON) | 类型 | 说明 | |--------------|------|------| | `locationId` | string | 门店主键 | | `locationName` | string | 门店名称;空为 `"无"` | | `fullAddress` | string | 与登录接口相同的地址拼接规则;无有效片段为 `"无"` | | `storePhone` | string | `location.Phone` 去首尾空格;空为 `"无"` | | `operatingHours` | string | 当前 **`location` 表无营业时间字段**,固定返回 **`"无"`**(后续若落库可再对接) | | `managerName` | string | 在同店 `userlocation` 绑定用户中,取角色 `RoleCode` / `RoleName`(忽略大小写)包含 **`manager`** 的第一人展示姓名(`Name` → `Nick` → `UserName`);无匹配为 **`"无"`** | | `managerPhone` | string | 同上用户的 `User.Phone`(long)按与「我的资料」相同的可读格式;无电话为 **`"无"`** | ### 响应示例 ```json { "locationId": "a2696b9e-2277-11f1-b4c6-00163e0c7c4f", "locationName": "Downtown Store", "fullAddress": "123 Main St, New York, NY 10001", "storePhone": "(212) 555-0100", "operatingHours": "无", "managerName": "Jane Doe", "managerPhone": "+1 (555) 123-4567" } ``` ### 常见错误(业务异常文案) - 未登录:`用户未登录` - `locationId` 非法或空:`无效的门店标识` - 当前用户未绑定该门店:`当前账号未绑定该门店,无法查看` - 门店已删或不存在:`门店不存在或已删除` --- ## 与其他登录方式的区别 | 场景 | 说明 | |------|------| | Web 管理端 | 仍使用 RBAC **`AccountService.PostLoginAsync`**,一般为人 **`userName`** + 密码 | | 美国版 App | **仅**本模块 **`/api/app/us-app-auth/login`** 使用 **邮箱 + 密码** | 两者共用同一 `User` 表与 JWT 体系;App 端需保证账号已维护 **`Email`** 字段,否则无法通过邮箱登录。