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 | 33 | throw new UserFriendlyException("门店Id不能为空"); |
| 34 | 34 | } |
| 35 | 35 | |
| 36 | + // 全门店共用一套 Support 联系方式,按任意门店 Id 查询都返回同一条配置。 | |
| 36 | 37 | var entity = await _dbContext.SqlSugarClient.Queryable<FlLocationSupportDbEntity>() |
| 37 | - .FirstAsync(x => !x.IsDeleted && x.LocationId == lid); | |
| 38 | + .FirstAsync(x => !x.IsDeleted); | |
| 38 | 39 | if (entity is null) |
| 39 | 40 | { |
| 40 | 41 | return null; |
| ... | ... | @@ -60,10 +61,10 @@ public class LocationSupportAppService : ApplicationService, ILocationSupportApp |
| 60 | 61 | await EnsureLocationExistsAsync(locationId); |
| 61 | 62 | |
| 62 | 63 | var existed = await _dbContext.SqlSugarClient.Queryable<FlLocationSupportDbEntity>() |
| 63 | - .AnyAsync(x => !x.IsDeleted && x.LocationId == locationId); | |
| 64 | + .AnyAsync(x => !x.IsDeleted); | |
| 64 | 65 | if (existed) |
| 65 | 66 | { |
| 66 | - throw new UserFriendlyException("该门店已配置 Support 联系方式,请使用编辑接口"); | |
| 67 | + throw new UserFriendlyException("已存在全局 Support 联系方式,请使用编辑接口"); | |
| 67 | 68 | } |
| 68 | 69 | |
| 69 | 70 | var now = Clock.Now; |
| ... | ... | @@ -113,10 +114,10 @@ public class LocationSupportAppService : ApplicationService, ILocationSupportApp |
| 113 | 114 | await EnsureLocationExistsAsync(locationId); |
| 114 | 115 | |
| 115 | 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 | 118 | if (conflict) |
| 118 | 119 | { |
| 119 | - throw new UserFriendlyException("目标门店已配置 Support 联系方式,一个门店仅允许一条"); | |
| 120 | + throw new UserFriendlyException("系统仅允许一条全局 Support 联系方式"); | |
| 120 | 121 | } |
| 121 | 122 | |
| 122 | 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 | using Microsoft.AspNetCore.Mvc; |
| 7 | 7 | using Microsoft.Extensions.Caching.Distributed; |
| 8 | 8 | using Microsoft.Extensions.Options; |
| 9 | +using SqlSugar; | |
| 9 | 10 | using Volo.Abp.Application.Services; |
| 10 | 11 | using Volo.Abp.Authorization; |
| 11 | 12 | using Volo.Abp.Caching; |
| ... | ... | @@ -83,7 +84,7 @@ namespace Yi.Framework.Rbac.Application.Services |
| 83 | 84 | //登录不想要验证码 ,可不校验 |
| 84 | 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 | 98 | [AllowAnonymous] |
| 98 | 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 | 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 | 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 | 142 | /// <summary> |
| 117 | 143 | /// 提供其他服务使用,根据用户id,直接返回token | ... | ... |
项目相关文档/美国版App登录接口说明.md
| ... | ... | @@ -287,8 +287,8 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... |
| 287 | 287 | |
| 288 | 288 | ## 接口 6:门店 Support 联系方式(App 展示) |
| 289 | 289 | |
| 290 | -用于 App「Support」页面读取当前门店的联系方式(电话、邮箱)。 | |
| 291 | -后台由 `LocationSupportAppService` 维护,规则是 **一个门店仅允许一条** 联系方式记录。 | |
| 290 | +用于 App「Support」页面读取联系方式(电话、邮箱)。 | |
| 291 | +后台由 `LocationSupportAppService` 维护,规则已调整为 **全门店共用一条全局联系方式**。 | |
| 292 | 292 | |
| 293 | 293 | ### HTTP |
| 294 | 294 | |
| ... | ... | @@ -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 | 305 | ### 响应体(LocationSupportGetOutputDto) |
| 306 | 306 | |
| 307 | 307 | | 字段(JSON) | 类型 | 说明 | |
| 308 | 308 | |--------------|------|------| |
| 309 | 309 | | `id` | string | 联系方式主键 | |
| 310 | -| `locationId` | string | 门店主键 | | |
| 311 | -| `locationName` | string \| null | 门店名称 | | |
| 310 | +| `locationId` | string | 配置记录中的门店主键(仅作兼容字段) | | |
| 311 | +| `locationName` | string \| null | 配置记录中的门店名称(仅作兼容字段) | | |
| 312 | 312 | | `supportPhone` | string | Support 电话 | |
| 313 | 313 | | `supportEmail` | string | Support 邮箱 | |
| 314 | 314 | |
| ... | ... | @@ -330,9 +330,9 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... |
| 330 | 330 | |
| 331 | 331 | ## 后台维护接口:Location Support(新增/编辑) |
| 332 | 332 | |
| 333 | -仅后台管理端使用,用于配置 App Support 页面展示内容。 | |
| 333 | +仅后台管理端使用,用于配置 App Support 页面展示内容(全局唯一)。 | |
| 334 | 334 | |
| 335 | -### 接口 A:新增门店联系方式 | |
| 335 | +### 接口 A:新增 Support 联系方式(全局) | |
| 336 | 336 | |
| 337 | 337 | - **方法**:`POST` |
| 338 | 338 | - **路径**:`/api/app/location-support` |
| ... | ... | @@ -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 | 356 | - **方法**:`PUT` |
| 357 | 357 | - **路径**:`/api/app/location-support/{id}` |
| ... | ... | @@ -371,7 +371,55 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... |
| 371 | 371 | - `门店Id不能为空` / `门店Id格式不正确` |
| 372 | 372 | - `Support 电话不能为空` |
| 373 | 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 | 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 | 433 | 两者共用同一 `User` 表与 JWT 体系;App 端需保证账号已维护 **`Email`** 字段,否则无法通过邮箱登录。 | ... | ... |