Commit 87313aec197c4eda0fbca6cb0e155142b9683f5b
1 parent
957e20a0
门店支持;登陆接口优化
Showing
3 changed files
with
98 additions
and
23 deletions
美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LocationSupportAppService.cs
| @@ -33,8 +33,9 @@ public class LocationSupportAppService : ApplicationService, ILocationSupportApp | @@ -33,8 +33,9 @@ public class LocationSupportAppService : ApplicationService, ILocationSupportApp | ||
| 33 | throw new UserFriendlyException("门店Id不能为空"); | 33 | throw new UserFriendlyException("门店Id不能为空"); |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | + // 全门店共用一套 Support 联系方式,按任意门店 Id 查询都返回同一条配置。 | ||
| 36 | var entity = await _dbContext.SqlSugarClient.Queryable<FlLocationSupportDbEntity>() | 37 | var entity = await _dbContext.SqlSugarClient.Queryable<FlLocationSupportDbEntity>() |
| 37 | - .FirstAsync(x => !x.IsDeleted && x.LocationId == lid); | 38 | + .FirstAsync(x => !x.IsDeleted); |
| 38 | if (entity is null) | 39 | if (entity is null) |
| 39 | { | 40 | { |
| 40 | return null; | 41 | return null; |
| @@ -60,10 +61,10 @@ public class LocationSupportAppService : ApplicationService, ILocationSupportApp | @@ -60,10 +61,10 @@ public class LocationSupportAppService : ApplicationService, ILocationSupportApp | ||
| 60 | await EnsureLocationExistsAsync(locationId); | 61 | await EnsureLocationExistsAsync(locationId); |
| 61 | 62 | ||
| 62 | var existed = await _dbContext.SqlSugarClient.Queryable<FlLocationSupportDbEntity>() | 63 | var existed = await _dbContext.SqlSugarClient.Queryable<FlLocationSupportDbEntity>() |
| 63 | - .AnyAsync(x => !x.IsDeleted && x.LocationId == locationId); | 64 | + .AnyAsync(x => !x.IsDeleted); |
| 64 | if (existed) | 65 | if (existed) |
| 65 | { | 66 | { |
| 66 | - throw new UserFriendlyException("该门店已配置 Support 联系方式,请使用编辑接口"); | 67 | + throw new UserFriendlyException("已存在全局 Support 联系方式,请使用编辑接口"); |
| 67 | } | 68 | } |
| 68 | 69 | ||
| 69 | var now = Clock.Now; | 70 | var now = Clock.Now; |
| @@ -113,10 +114,10 @@ public class LocationSupportAppService : ApplicationService, ILocationSupportApp | @@ -113,10 +114,10 @@ public class LocationSupportAppService : ApplicationService, ILocationSupportApp | ||
| 113 | await EnsureLocationExistsAsync(locationId); | 114 | await EnsureLocationExistsAsync(locationId); |
| 114 | 115 | ||
| 115 | var conflict = await _dbContext.SqlSugarClient.Queryable<FlLocationSupportDbEntity>() | 116 | var conflict = await _dbContext.SqlSugarClient.Queryable<FlLocationSupportDbEntity>() |
| 116 | - .AnyAsync(x => !x.IsDeleted && x.LocationId == locationId && x.Id != supportId); | 117 | + .AnyAsync(x => !x.IsDeleted && x.Id != supportId); |
| 117 | if (conflict) | 118 | if (conflict) |
| 118 | { | 119 | { |
| 119 | - throw new UserFriendlyException("目标门店已配置 Support 联系方式,一个门店仅允许一条"); | 120 | + throw new UserFriendlyException("系统仅允许一条全局 Support 联系方式"); |
| 120 | } | 121 | } |
| 121 | 122 | ||
| 122 | entity.LocationId = locationId; | 123 | entity.LocationId = locationId; |
美国版/Food Labeling Management Code/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/AccountService.cs
| @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Http; | @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Http; | ||
| 6 | using Microsoft.AspNetCore.Mvc; | 6 | using Microsoft.AspNetCore.Mvc; |
| 7 | using Microsoft.Extensions.Caching.Distributed; | 7 | using Microsoft.Extensions.Caching.Distributed; |
| 8 | using Microsoft.Extensions.Options; | 8 | using Microsoft.Extensions.Options; |
| 9 | +using SqlSugar; | ||
| 9 | using Volo.Abp.Application.Services; | 10 | using Volo.Abp.Application.Services; |
| 10 | using Volo.Abp.Authorization; | 11 | using Volo.Abp.Authorization; |
| 11 | using Volo.Abp.Caching; | 12 | using Volo.Abp.Caching; |
| @@ -83,7 +84,7 @@ namespace Yi.Framework.Rbac.Application.Services | @@ -83,7 +84,7 @@ namespace Yi.Framework.Rbac.Application.Services | ||
| 83 | //登录不想要验证码 ,可不校验 | 84 | //登录不想要验证码 ,可不校验 |
| 84 | if (!_captcha.Validate(uuid, code)) | 85 | if (!_captcha.Validate(uuid, code)) |
| 85 | { | 86 | { |
| 86 | - throw new UserFriendlyException("验证码错误"); | 87 | + throw new UserFriendlyException("Invalid captcha."); |
| 87 | } | 88 | } |
| 88 | } | 89 | } |
| 89 | } | 90 | } |
| @@ -97,21 +98,46 @@ namespace Yi.Framework.Rbac.Application.Services | @@ -97,21 +98,46 @@ namespace Yi.Framework.Rbac.Application.Services | ||
| 97 | [AllowAnonymous] | 98 | [AllowAnonymous] |
| 98 | public async Task<LoginOutputDto> PostLoginAsync(LoginInputVo input) | 99 | public async Task<LoginOutputDto> PostLoginAsync(LoginInputVo input) |
| 99 | { | 100 | { |
| 100 | - if (string.IsNullOrEmpty(input.Password) || string.IsNullOrEmpty(input.UserName)) | 101 | + var email = input.UserName?.Trim(); |
| 102 | + var password = input.Password ?? string.Empty; | ||
| 103 | + if (string.IsNullOrWhiteSpace(email) || string.IsNullOrWhiteSpace(password)) | ||
| 101 | { | 104 | { |
| 102 | - throw new UserFriendlyException("请输入合理数据!"); | 105 | + throw new UserFriendlyException("Email and password are required."); |
| 106 | + } | ||
| 107 | + | ||
| 108 | + if (!IsPlausibleEmail(email)) | ||
| 109 | + { | ||
| 110 | + // Platform sign-in supports email only. | ||
| 111 | + throw new UserFriendlyException("Sign-in failed: email is required as the account."); | ||
| 103 | } | 112 | } |
| 104 | 113 | ||
| 105 | //校验验证码 | 114 | //校验验证码 |
| 106 | ValidationImageCaptcha(input.Uuid,input.Code); | 115 | ValidationImageCaptcha(input.Uuid,input.Code); |
| 107 | 116 | ||
| 108 | - UserAggregateRoot user = new(); | ||
| 109 | - //校验 | ||
| 110 | - await _accountManager.LoginValidationAsync(input.UserName, input.Password, x => user = x); | 117 | + var normalized = email.ToLowerInvariant(); |
| 118 | + var candidates = await _userRepository._DbQueryable | ||
| 119 | + .Where(u => !u.IsDeleted && u.State == true) | ||
| 120 | + .Where(u => u.Email != null && SqlFunc.ToLower(u.Email) == normalized) | ||
| 121 | + .ToListAsync(); | ||
| 122 | + var user = candidates.FirstOrDefault(); | ||
| 123 | + if (user is null) | ||
| 124 | + { | ||
| 125 | + throw new UserFriendlyException("Sign-in failed: account not found."); | ||
| 126 | + } | ||
| 127 | + | ||
| 128 | + if (!user.JudgePassword(password)) | ||
| 129 | + { | ||
| 130 | + throw new UserFriendlyException("Sign-in failed: incorrect email or password."); | ||
| 131 | + } | ||
| 111 | 132 | ||
| 112 | return await PostLoginAsync(user.Id); | 133 | return await PostLoginAsync(user.Id); |
| 113 | } | 134 | } |
| 114 | 135 | ||
| 136 | + private static bool IsPlausibleEmail(string email) => | ||
| 137 | + email.Contains("@", StringComparison.Ordinal) && | ||
| 138 | + !email.StartsWith("@", StringComparison.Ordinal) && | ||
| 139 | + !email.EndsWith("@", StringComparison.Ordinal); | ||
| 140 | + | ||
| 115 | 141 | ||
| 116 | /// <summary> | 142 | /// <summary> |
| 117 | /// 提供其他服务使用,根据用户id,直接返回token | 143 | /// 提供其他服务使用,根据用户id,直接返回token |
项目相关文档/美国版App登录接口说明.md
| @@ -287,8 +287,8 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... | @@ -287,8 +287,8 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... | ||
| 287 | 287 | ||
| 288 | ## 接口 6:门店 Support 联系方式(App 展示) | 288 | ## 接口 6:门店 Support 联系方式(App 展示) |
| 289 | 289 | ||
| 290 | -用于 App「Support」页面读取当前门店的联系方式(电话、邮箱)。 | ||
| 291 | -后台由 `LocationSupportAppService` 维护,规则是 **一个门店仅允许一条** 联系方式记录。 | 290 | +用于 App「Support」页面读取联系方式(电话、邮箱)。 |
| 291 | +后台由 `LocationSupportAppService` 维护,规则已调整为 **全门店共用一条全局联系方式**。 | ||
| 292 | 292 | ||
| 293 | ### HTTP | 293 | ### HTTP |
| 294 | 294 | ||
| @@ -300,15 +300,15 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... | @@ -300,15 +300,15 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... | ||
| 300 | 300 | ||
| 301 | | 参数名 | 位置 | 类型 | 必填 | 说明 | | 301 | | 参数名 | 位置 | 类型 | 必填 | 说明 | |
| 302 | |--------|------|------|------|------| | 302 | |--------|------|------|------|------| |
| 303 | -| `locationId` | Query | string | 是 | 门店主键(Guid 字符串) | | 303 | +| `locationId` | Query | string | 是 | 门店主键(Guid 字符串)。当前用于入参兼容,返回值按全局联系方式配置 | |
| 304 | 304 | ||
| 305 | ### 响应体(LocationSupportGetOutputDto) | 305 | ### 响应体(LocationSupportGetOutputDto) |
| 306 | 306 | ||
| 307 | | 字段(JSON) | 类型 | 说明 | | 307 | | 字段(JSON) | 类型 | 说明 | |
| 308 | |--------------|------|------| | 308 | |--------------|------|------| |
| 309 | | `id` | string | 联系方式主键 | | 309 | | `id` | string | 联系方式主键 | |
| 310 | -| `locationId` | string | 门店主键 | | ||
| 311 | -| `locationName` | string \| null | 门店名称 | | 310 | +| `locationId` | string | 配置记录中的门店主键(仅作兼容字段) | |
| 311 | +| `locationName` | string \| null | 配置记录中的门店名称(仅作兼容字段) | | ||
| 312 | | `supportPhone` | string | Support 电话 | | 312 | | `supportPhone` | string | Support 电话 | |
| 313 | | `supportEmail` | string | Support 邮箱 | | 313 | | `supportEmail` | string | Support 邮箱 | |
| 314 | 314 | ||
| @@ -330,9 +330,9 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... | @@ -330,9 +330,9 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... | ||
| 330 | 330 | ||
| 331 | ## 后台维护接口:Location Support(新增/编辑) | 331 | ## 后台维护接口:Location Support(新增/编辑) |
| 332 | 332 | ||
| 333 | -仅后台管理端使用,用于配置 App Support 页面展示内容。 | 333 | +仅后台管理端使用,用于配置 App Support 页面展示内容(全局唯一)。 |
| 334 | 334 | ||
| 335 | -### 接口 A:新增门店联系方式 | 335 | +### 接口 A:新增 Support 联系方式(全局) |
| 336 | 336 | ||
| 337 | - **方法**:`POST` | 337 | - **方法**:`POST` |
| 338 | - **路径**:`/api/app/location-support` | 338 | - **路径**:`/api/app/location-support` |
| @@ -349,9 +349,9 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... | @@ -349,9 +349,9 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... | ||
| 349 | ``` | 349 | ``` |
| 350 | 350 | ||
| 351 | 约束: | 351 | 约束: |
| 352 | -- 同一 `locationId` 只能新增一条,重复会报错:`该门店已配置 Support 联系方式,请使用编辑接口` | 352 | +- 系统内仅允许存在一条未删除记录;若已存在,再次新增会报错:`已存在全局 Support 联系方式,请使用编辑接口` |
| 353 | 353 | ||
| 354 | -### 接口 B:编辑门店联系方式 | 354 | +### 接口 B:编辑 Support 联系方式(全局) |
| 355 | 355 | ||
| 356 | - **方法**:`PUT` | 356 | - **方法**:`PUT` |
| 357 | - **路径**:`/api/app/location-support/{id}` | 357 | - **路径**:`/api/app/location-support/{id}` |
| @@ -371,7 +371,55 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... | @@ -371,7 +371,55 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... | ||
| 371 | - `门店Id不能为空` / `门店Id格式不正确` | 371 | - `门店Id不能为空` / `门店Id格式不正确` |
| 372 | - `Support 电话不能为空` | 372 | - `Support 电话不能为空` |
| 373 | - `Support 邮箱不能为空` / `Support 邮箱格式不正确` | 373 | - `Support 邮箱不能为空` / `Support 邮箱格式不正确` |
| 374 | -- `目标门店已配置 Support 联系方式,一个门店仅允许一条` | 374 | +- `系统仅允许一条全局 Support 联系方式` |
| 375 | + | ||
| 376 | +--- | ||
| 377 | + | ||
| 378 | +## 平台端登录接口(Web) | ||
| 379 | + | ||
| 380 | +> 对应 `RBAC.AccountService.PostLoginAsync`。当前平台端登录规则已调整为:**仅支持 Email 作为账号,不再支持 UserName**。 | ||
| 381 | + | ||
| 382 | +### HTTP | ||
| 383 | + | ||
| 384 | +- **方法**:`POST` | ||
| 385 | +- **路径**:`/api/app/account/login`(以 Swagger 中 `Account` 为准) | ||
| 386 | +- **Content-Type**:`application/json` | ||
| 387 | +- **鉴权**:匿名 | ||
| 388 | + | ||
| 389 | +### 请求体(LoginInputVo) | ||
| 390 | + | ||
| 391 | +| 字段(JSON) | 类型 | 必填 | 说明 | | ||
| 392 | +|--------------|------|------|------| | ||
| 393 | +| `userName` | string | 是 | 兼容历史字段名;现必须传 **邮箱**(例如 `admin@example.com`) | | ||
| 394 | +| `password` | string | 是 | 密码 | | ||
| 395 | +| `uuid` | string | 条件 | 开启图形验证码时必填 | | ||
| 396 | +| `code` | string | 条件 | 开启图形验证码时必填 | | ||
| 397 | + | ||
| 398 | +### 请求示例 | ||
| 399 | + | ||
| 400 | +```json | ||
| 401 | +{ | ||
| 402 | + "userName": "admin@example.com", | ||
| 403 | + "password": "YourPassword", | ||
| 404 | + "uuid": "captcha-uuid", | ||
| 405 | + "code": "captcha-code" | ||
| 406 | +} | ||
| 407 | +``` | ||
| 408 | + | ||
| 409 | +### 响应体(LoginOutputDto) | ||
| 410 | + | ||
| 411 | +| 字段(JSON) | 类型 | 说明 | | ||
| 412 | +|--------------|------|------| | ||
| 413 | +| `token` | string | Access Token | | ||
| 414 | +| `refreshToken` | string | Refresh Token | | ||
| 415 | + | ||
| 416 | +### 错误文案(英文) | ||
| 417 | + | ||
| 418 | +- `Email and password are required.` | ||
| 419 | +- `Sign-in failed: email is required as the account.` | ||
| 420 | +- `Sign-in failed: account not found.` | ||
| 421 | +- `Sign-in failed: incorrect email or password.` | ||
| 422 | +- `Invalid captcha.` | ||
| 375 | 423 | ||
| 376 | --- | 424 | --- |
| 377 | 425 | ||
| @@ -379,7 +427,7 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... | @@ -379,7 +427,7 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... | ||
| 379 | 427 | ||
| 380 | | 场景 | 说明 | | 428 | | 场景 | 说明 | |
| 381 | |------|------| | 429 | |------|------| |
| 382 | -| Web 管理端 | 仍使用 RBAC **`AccountService.PostLoginAsync`**,一般为人 **`userName`** + 密码 | | ||
| 383 | -| 美国版 App | **仅**本模块 **`/api/app/us-app-auth/login`** 使用 **邮箱 + 密码** | | 430 | +| Web 管理端 | 使用 RBAC **`/api/app/account/login`**,字段名虽为 `userName`,但值必须是 **Email** | |
| 431 | +| 美国版 App | 使用 **`/api/app/us-app-auth/login`**,显式字段 `email` + `password` | | ||
| 384 | 432 | ||
| 385 | 两者共用同一 `User` 表与 JWT 体系;App 端需保证账号已维护 **`Email`** 字段,否则无法通过邮箱登录。 | 433 | 两者共用同一 `User` 表与 JWT 体系;App 端需保证账号已维护 **`Email`** 字段,否则无法通过邮箱登录。 |