任务
This commit is contained in:
parent
da39817b89
commit
c32e0d803b
588
.kiro/specs/user-auth-migration/design.md
Normal file
588
.kiro/specs/user-auth-migration/design.md
Normal file
|
|
@ -0,0 +1,588 @@
|
|||
# Design Document: 用户认证系统迁移
|
||||
|
||||
## Overview
|
||||
|
||||
本设计文档描述了将PHP用户认证系统迁移到.NET 8的技术方案。系统采用分层架构,包括Controller层、Service层和Repository层。迁移过程中保持与现有UniApp前端的100%兼容性,使用相同的请求/响应格式。
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ UniApp 前端 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ API Gateway / Nginx │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ .NET 8 API 服务 │
|
||||
│ ┌─────────────────────────────────────────────────────┐ │
|
||||
│ │ Controllers │ │
|
||||
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
|
||||
│ │ │AuthController│ │UserController│ │HealthCheck │ │ │
|
||||
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────────┘ │
|
||||
│ ┌─────────────────────────────────────────────────────┐ │
|
||||
│ │ Services │ │
|
||||
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
|
||||
│ │ │ AuthService │ │ UserService │ │ JwtService │ │ │
|
||||
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
|
||||
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
|
||||
│ │ │WechatService│ │ SmsService │ │IpLocationSvc│ │ │
|
||||
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────────┘ │
|
||||
│ ┌─────────────────────────────────────────────────────┐ │
|
||||
│ │ Infrastructure │ │
|
||||
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
|
||||
│ │ │ EF Core │ │ Redis │ │ COS Upload │ │ │
|
||||
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│ │
|
||||
▼ ▼
|
||||
┌───────────┐ ┌───────────┐
|
||||
│ MySQL │ │ Redis │
|
||||
└───────────┘ └───────────┘
|
||||
```
|
||||
|
||||
## Components and Interfaces
|
||||
|
||||
### 1. AuthController
|
||||
|
||||
负责处理所有认证相关的HTTP请求。
|
||||
|
||||
```csharp
|
||||
[ApiController]
|
||||
[Route("api")]
|
||||
public class AuthController : ControllerBase
|
||||
{
|
||||
// POST /login - 微信小程序登录
|
||||
[HttpPost("login")]
|
||||
public async Task<ApiResponse<string>> WechatMiniProgramLogin(WechatLoginRequest request);
|
||||
|
||||
// POST /mobileLogin - 手机号验证码登录
|
||||
[HttpPost("mobileLogin")]
|
||||
public async Task<ApiResponse<string>> MobileLogin(MobileLoginRequest request);
|
||||
|
||||
// POST /login_bind_mobile - 微信授权绑定手机号
|
||||
[HttpPost("login_bind_mobile")]
|
||||
public async Task<ApiResponse<BindMobileResponse>> LoginBindMobile(BindMobileRequest request);
|
||||
|
||||
// POST /bindMobile - 验证码绑定手机号
|
||||
[HttpPost("bindMobile")]
|
||||
public async Task<ApiResponse<BindMobileResponse>> BindMobile(BindMobileWithCodeRequest request);
|
||||
|
||||
// GET|POST /login_record - 记录用户登录
|
||||
[HttpPost("login_record")]
|
||||
[HttpGet("login_record")]
|
||||
public async Task<ApiResponse<RecordLoginResponse>> RecordLogin(RecordLoginRequest request);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. UserController
|
||||
|
||||
负责处理用户信息相关的HTTP请求。
|
||||
|
||||
```csharp
|
||||
[ApiController]
|
||||
[Route("api")]
|
||||
public class UserController : ControllerBase
|
||||
{
|
||||
// POST /user - 获取用户信息
|
||||
[HttpPost("user")]
|
||||
public async Task<ApiResponse<UserInfoResponse>> GetUserInfo();
|
||||
|
||||
// POST /update_userinfo - 更新用户信息
|
||||
[HttpPost("update_userinfo")]
|
||||
public async Task<ApiResponse> UpdateUserInfo(UpdateUserInfoRequest request);
|
||||
|
||||
// POST /user_log_off - 注销账号
|
||||
[HttpPost("user_log_off")]
|
||||
public async Task<ApiResponse> LogOff(LogOffRequest request);
|
||||
}
|
||||
```
|
||||
|
||||
### 3. IAuthService
|
||||
|
||||
认证服务接口。
|
||||
|
||||
```csharp
|
||||
public interface IAuthService
|
||||
{
|
||||
Task<LoginResult> WechatMiniProgramLoginAsync(string code, int? pid, string clickId);
|
||||
Task<LoginResult> MobileLoginAsync(string mobile, string code, int? pid, string clickId);
|
||||
Task<BindMobileResult> BindMobileAsync(int userId, string mobile, string code);
|
||||
Task<BindMobileResult> WechatBindMobileAsync(int userId, string wechatCode);
|
||||
Task RecordLoginAsync(int userId, string device, string deviceInfo);
|
||||
Task LogOffAsync(int userId, int type);
|
||||
}
|
||||
```
|
||||
|
||||
### 4. IWechatService
|
||||
|
||||
微信服务接口。
|
||||
|
||||
```csharp
|
||||
public interface IWechatService
|
||||
{
|
||||
Task<WechatAuthResult> GetOpenIdAsync(string code);
|
||||
Task<WechatMobileResult> GetMobileAsync(string code);
|
||||
}
|
||||
```
|
||||
|
||||
### 5. IJwtService
|
||||
|
||||
JWT服务接口。
|
||||
|
||||
```csharp
|
||||
public interface IJwtService
|
||||
{
|
||||
string GenerateToken(User user);
|
||||
ClaimsPrincipal ValidateToken(string token);
|
||||
int? GetUserIdFromToken(string token);
|
||||
}
|
||||
```
|
||||
|
||||
### 6. IUserService
|
||||
|
||||
用户服务接口。
|
||||
|
||||
```csharp
|
||||
public interface IUserService
|
||||
{
|
||||
Task<User> GetUserByIdAsync(int userId);
|
||||
Task<User> GetUserByOpenIdAsync(string openId);
|
||||
Task<User> GetUserByUnionIdAsync(string unionId);
|
||||
Task<User> GetUserByMobileAsync(string mobile);
|
||||
Task<User> CreateUserAsync(CreateUserDto dto);
|
||||
Task UpdateUserAsync(int userId, UpdateUserDto dto);
|
||||
Task<UserInfoDto> GetUserInfoAsync(int userId);
|
||||
Task<int> CalculateVipLevelAsync(int userId, int currentVip);
|
||||
}
|
||||
```
|
||||
|
||||
### 7. IIpLocationService
|
||||
|
||||
IP地理位置服务接口。
|
||||
|
||||
```csharp
|
||||
public interface IIpLocationService
|
||||
{
|
||||
Task<IpLocationResult> GetLocationAsync(string ip);
|
||||
}
|
||||
```
|
||||
|
||||
## Data Models
|
||||
|
||||
### Request Models
|
||||
|
||||
```csharp
|
||||
public class WechatLoginRequest
|
||||
{
|
||||
public string Code { get; set; }
|
||||
public int? Pid { get; set; }
|
||||
}
|
||||
|
||||
public class MobileLoginRequest
|
||||
{
|
||||
public string Mobile { get; set; }
|
||||
public string Code { get; set; }
|
||||
public int? Pid { get; set; }
|
||||
}
|
||||
|
||||
public class BindMobileRequest
|
||||
{
|
||||
public string Code { get; set; } // 微信授权code
|
||||
}
|
||||
|
||||
public class BindMobileWithCodeRequest
|
||||
{
|
||||
public string Mobile { get; set; }
|
||||
public string Code { get; set; } // 短信验证码
|
||||
}
|
||||
|
||||
public class UpdateUserInfoRequest
|
||||
{
|
||||
public string Nickname { get; set; }
|
||||
public string Headimg { get; set; }
|
||||
public string Imagebase { get; set; } // Base64图片
|
||||
}
|
||||
|
||||
public class RecordLoginRequest
|
||||
{
|
||||
public string Device { get; set; }
|
||||
public string DeviceInfo { get; set; }
|
||||
}
|
||||
|
||||
public class LogOffRequest
|
||||
{
|
||||
public int Type { get; set; } // 0-注销 1-取消注销
|
||||
}
|
||||
```
|
||||
|
||||
### Response Models
|
||||
|
||||
```csharp
|
||||
public class ApiResponse<T>
|
||||
{
|
||||
public int Status { get; set; } // 1成功 0失败 -1未登录
|
||||
public string Msg { get; set; }
|
||||
public T Data { get; set; }
|
||||
}
|
||||
|
||||
public class UserInfoResponse
|
||||
{
|
||||
public UserInfoDto Userinfo { get; set; }
|
||||
public OtherConfigDto Other { get; set; }
|
||||
public List<TaskDto> TaskList { get; set; }
|
||||
}
|
||||
|
||||
public class UserInfoDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Uid { get; set; }
|
||||
public string Nickname { get; set; }
|
||||
public string Headimg { get; set; }
|
||||
public string Mobile { get; set; } // 脱敏后的手机号
|
||||
public int MobileIs { get; set; } // 是否绑定手机
|
||||
public decimal Money { get; set; }
|
||||
public decimal Money2 { get; set; }
|
||||
public decimal Integral { get; set; }
|
||||
public decimal Score { get; set; }
|
||||
public int Vip { get; set; }
|
||||
public string VipImgurl { get; set; }
|
||||
public int Coupon { get; set; }
|
||||
public int Day { get; set; } // 注册天数
|
||||
}
|
||||
|
||||
public class BindMobileResponse
|
||||
{
|
||||
public string Token { get; set; } // 账户合并时返回新token
|
||||
}
|
||||
|
||||
public class RecordLoginResponse
|
||||
{
|
||||
public string Uid { get; set; }
|
||||
public string Nickname { get; set; }
|
||||
public string Headimg { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
### Internal DTOs
|
||||
|
||||
```csharp
|
||||
public class LoginResult
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
public string Token { get; set; }
|
||||
public int UserId { get; set; }
|
||||
public string ErrorMessage { get; set; }
|
||||
}
|
||||
|
||||
public class WechatAuthResult
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
public string OpenId { get; set; }
|
||||
public string UnionId { get; set; }
|
||||
public string ErrorMessage { get; set; }
|
||||
}
|
||||
|
||||
public class IpLocationResult
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
public string Province { get; set; }
|
||||
public string City { get; set; }
|
||||
public string Adcode { get; set; }
|
||||
}
|
||||
|
||||
public class CreateUserDto
|
||||
{
|
||||
public string OpenId { get; set; }
|
||||
public string UnionId { get; set; }
|
||||
public string Mobile { get; set; }
|
||||
public string Nickname { get; set; }
|
||||
public string Headimg { get; set; }
|
||||
public int Pid { get; set; }
|
||||
public int? ClickId { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
## Key Implementation Details
|
||||
|
||||
### 1. 防抖机制实现
|
||||
|
||||
使用Redis实现登录防抖,防止用户频繁请求:
|
||||
|
||||
```csharp
|
||||
public async Task<bool> TryAcquireLoginLockAsync(string key, int expireSeconds = 3)
|
||||
{
|
||||
var lockKey = $"login:debounce:{key}";
|
||||
return await _redis.StringSetAsync(lockKey, "1", TimeSpan.FromSeconds(expireSeconds), When.NotExists);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 用户UID生成策略
|
||||
|
||||
根据配置支持三种UID生成方式:
|
||||
- 类型0: 使用真实用户ID
|
||||
- 类型1: 生成指定长度的纯数字ID
|
||||
- 类型2: 生成字母数字混合ID
|
||||
|
||||
```csharp
|
||||
public string GenerateUid(int userId, UidConfig config)
|
||||
{
|
||||
return config.UidType switch
|
||||
{
|
||||
0 => userId.ToString(),
|
||||
1 => GenerateNumericUid(config.UidLength),
|
||||
2 => GenerateAlphaNumericUid(config.UidLength),
|
||||
_ => userId.ToString()
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 账户合并逻辑
|
||||
|
||||
当用户绑定的手机号已被其他账户使用时,需要合并账户:
|
||||
|
||||
```csharp
|
||||
public async Task<BindMobileResult> MergeAccountsAsync(int currentUserId, int mobileUserId)
|
||||
{
|
||||
// 1. 将当前用户的openid迁移到手机号用户
|
||||
// 2. 生成新的token
|
||||
// 3. 删除当前用户和账户记录
|
||||
// 4. 返回新token
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Token兼容策略
|
||||
|
||||
为保持与旧系统兼容,同时使用JWT和数据库token:
|
||||
|
||||
```csharp
|
||||
public async Task<string> CreateAccountTokenAsync(int userId)
|
||||
{
|
||||
var tokenNum = GenerateRandomString(10);
|
||||
var time = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||
var accountToken = ComputeMd5($"{userId}{tokenNum}{time}");
|
||||
|
||||
// 存储到UserAccount表
|
||||
await UpdateUserAccountAsync(userId, accountToken, tokenNum, time);
|
||||
|
||||
return accountToken;
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 默认头像生成
|
||||
|
||||
使用Identicon库生成用户默认头像:
|
||||
|
||||
```csharp
|
||||
public async Task<(string nickname, string headimg)> CreateDefaultAvatarAsync(string seed, string prefix)
|
||||
{
|
||||
var nickname = $"{prefix}{Random.Shared.Next(1000, 9999)}";
|
||||
var identicon = new Identicon(seed + nickname);
|
||||
var imageData = identicon.GetImageData();
|
||||
var url = await _cosUploader.UploadAsync(imageData, $"storage/users/icon/default/{Guid.NewGuid()}.png");
|
||||
return (nickname, url);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Correctness Properties
|
||||
|
||||
*A property is a characteristic or behavior that should hold true across all valid executions of a system-essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.*
|
||||
|
||||
### Property 1: 微信登录用户查找优先级
|
||||
|
||||
*For any* 用户登录请求,如果提供了unionid,系统应优先通过unionid查找用户;只有当unionid查找失败时,才通过openid查找。
|
||||
|
||||
**Validates: Requirements 1.2**
|
||||
|
||||
### Property 2: 新用户创建完整性
|
||||
|
||||
*For any* 不存在的用户(无论是微信登录还是手机号登录),系统创建的新用户记录应包含:有效的uid、非空的昵称、有效的头像URL、正确的pid(如果提供)。
|
||||
|
||||
**Validates: Requirements 1.3, 2.3**
|
||||
|
||||
### Property 3: 登录成功Token生成
|
||||
|
||||
*For any* 成功的登录请求(微信或手机号),系统应返回包含用户ID的有效JWT Token,且该Token应使用配置的密钥正确签名。
|
||||
|
||||
**Validates: Requirements 1.5, 2.4, 3.1, 3.2**
|
||||
|
||||
### Property 4: 登录防抖机制
|
||||
|
||||
*For any* 用户在3秒内发起的重复登录请求,第二次及之后的请求应被拒绝并返回"请勿频繁登录"错误。
|
||||
|
||||
**Validates: Requirements 1.6, 2.6**
|
||||
|
||||
### Property 5: 推荐关系记录
|
||||
|
||||
*For any* 新用户注册时提供的有效推荐人ID(pid),系统应将该pid正确保存到用户记录中。
|
||||
|
||||
**Validates: Requirements 1.8, 2.7**
|
||||
|
||||
### Property 6: 验证码验证与清理
|
||||
|
||||
*For any* 手机号登录请求,如果验证码正确,系统应验证通过并删除Redis中的验证码;如果验证码错误或过期,系统应返回"验证码错误"。
|
||||
|
||||
**Validates: Requirements 2.1, 2.2**
|
||||
|
||||
### Property 7: Token验证与授权
|
||||
|
||||
*For any* 携带Token的API请求,如果Token有效,系统应允许访问;如果Token无效或过期,系统应返回状态码-1(未登录)。
|
||||
|
||||
**Validates: Requirements 3.3, 3.4**
|
||||
|
||||
### Property 8: 数据库Token兼容存储
|
||||
|
||||
*For any* 成功的登录请求,系统应同时在UserAccount表中存储account_token,确保与旧系统兼容。
|
||||
|
||||
**Validates: Requirements 3.6**
|
||||
|
||||
### Property 9: 用户信息完整性
|
||||
|
||||
*For any* 用户信息查询请求,返回的数据应包含所有必要字段(id、uid、nickname、headimg、mobile、money、integral、vip等),且手机号应进行脱敏处理(格式:138****8000)。
|
||||
|
||||
**Validates: Requirements 4.1, 4.4**
|
||||
|
||||
### Property 10: 昵称更新验证
|
||||
|
||||
*For any* 昵称更新请求,如果昵称为空,系统应拒绝更新;如果昵称有效,系统应保存更新。
|
||||
|
||||
**Validates: Requirements 4.2**
|
||||
|
||||
### Property 11: VIP等级计算
|
||||
|
||||
*For any* 用户信息查询,系统应根据用户的累计消费金额正确计算并返回VIP等级。
|
||||
|
||||
**Validates: Requirements 4.5**
|
||||
|
||||
### Property 12: 手机号绑定验证码验证
|
||||
|
||||
*For any* 手机号绑定请求,系统应验证短信验证码;验证码错误时应返回"验证码错误"。
|
||||
|
||||
**Validates: Requirements 5.1, 5.5**
|
||||
|
||||
### Property 13: 账户合并正确性
|
||||
|
||||
*For any* 手机号已被其他用户绑定的情况,系统应正确合并账户:将当前用户的openid迁移到手机号用户,删除当前用户记录,并返回新的Token。
|
||||
|
||||
**Validates: Requirements 5.2, 5.3**
|
||||
|
||||
### Property 14: 直接绑定手机号
|
||||
|
||||
*For any* 手机号未被其他用户绑定的情况,系统应直接更新当前用户的手机号。
|
||||
|
||||
**Validates: Requirements 5.4**
|
||||
|
||||
### Property 15: 登录日志记录
|
||||
|
||||
*For any* 成功的登录请求,系统应在UserLoginLog表中记录登录日志,并更新UserAccount表中的最后登录时间和IP信息。
|
||||
|
||||
**Validates: Requirements 6.1, 6.3**
|
||||
|
||||
### Property 16: recordLogin接口返回值
|
||||
|
||||
*For any* recordLogin接口调用,系统应返回用户的uid、昵称和头像。
|
||||
|
||||
**Validates: Requirements 6.4**
|
||||
|
||||
### Property 17: 账号注销类型处理
|
||||
|
||||
*For any* 账号注销请求,type=0时表示注销账号,type=1时表示取消注销,系统应记录相应的日志并返回成功消息。
|
||||
|
||||
**Validates: Requirements 7.1, 7.2, 7.3**
|
||||
|
||||
## Error Handling
|
||||
|
||||
### 1. 微信API错误
|
||||
|
||||
- 当微信API返回错误时,记录详细错误日志
|
||||
- 返回用户友好的错误信息:"登录失败,请稍后重试"
|
||||
|
||||
### 2. 验证码错误
|
||||
|
||||
- 验证码不存在或已过期:返回"验证码错误"
|
||||
- 验证码不匹配:返回"验证码错误"
|
||||
|
||||
### 3. 防抖限制
|
||||
|
||||
- 用户频繁请求:返回"请勿频繁登录,请稍后再试"
|
||||
|
||||
### 4. Token错误
|
||||
|
||||
- Token无效:返回status=-1,msg="未登录"
|
||||
- Token过期:返回status=-1,msg="登录已过期"
|
||||
|
||||
### 5. 数据库错误
|
||||
|
||||
- 事务失败时回滚
|
||||
- 记录详细错误日志
|
||||
- 返回"网络故障,请稍后再试"
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### 单元测试
|
||||
|
||||
使用xUnit框架编写单元测试,覆盖以下场景:
|
||||
|
||||
1. **AuthService测试**
|
||||
- 微信登录成功/失败场景
|
||||
- 手机号登录成功/失败场景
|
||||
- 防抖机制测试
|
||||
- 账户合并测试
|
||||
|
||||
2. **JwtService测试**
|
||||
- Token生成测试
|
||||
- Token验证测试
|
||||
- Token过期测试
|
||||
|
||||
3. **UserService测试**
|
||||
- 用户查找测试
|
||||
- 用户创建测试
|
||||
- 用户信息更新测试
|
||||
- VIP等级计算测试
|
||||
|
||||
### 属性测试
|
||||
|
||||
使用FsCheck库进行属性测试,每个属性测试运行至少100次迭代:
|
||||
|
||||
1. **Property 1-5**: 登录相关属性测试
|
||||
2. **Property 6-8**: Token相关属性测试
|
||||
3. **Property 9-11**: 用户信息相关属性测试
|
||||
4. **Property 12-14**: 手机号绑定相关属性测试
|
||||
5. **Property 15-17**: 日志和注销相关属性测试
|
||||
|
||||
### 集成测试
|
||||
|
||||
1. **API端到端测试**
|
||||
- 完整的微信登录流程
|
||||
- 完整的手机号登录流程
|
||||
- 用户信息获取和更新流程
|
||||
|
||||
2. **数据库集成测试**
|
||||
- 用户创建和查询
|
||||
- 账户合并
|
||||
- 登录日志记录
|
||||
|
||||
### 测试配置
|
||||
|
||||
```csharp
|
||||
// 属性测试配置示例
|
||||
[Property(MaxTest = 100)]
|
||||
public Property LoginShouldGenerateValidToken()
|
||||
{
|
||||
return Prop.ForAll(
|
||||
Arb.From<ValidLoginRequest>(),
|
||||
request => {
|
||||
var result = _authService.LoginAsync(request).Result;
|
||||
return result.Success && !string.IsNullOrEmpty(result.Token);
|
||||
});
|
||||
}
|
||||
```
|
||||
116
.kiro/specs/user-auth-migration/requirements.md
Normal file
116
.kiro/specs/user-auth-migration/requirements.md
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
# Requirements Document
|
||||
|
||||
## Introduction
|
||||
|
||||
本文档定义了将PHP用户认证系统迁移到.NET 8的需求规范。迁移范围包括微信小程序登录、手机号验证码登录、JWT Token管理、用户信息管理、手机号绑定、登录记录和账号注销功能。迁移过程中需要保持与现有UniApp前端的100%兼容性。
|
||||
|
||||
## Glossary
|
||||
|
||||
- **Auth_System**: 用户认证系统,负责处理用户登录、注册、Token管理等功能
|
||||
- **Wechat_Service**: 微信服务,负责与微信API交互获取openid和用户信息
|
||||
- **Sms_Service**: 短信服务,负责验证短信验证码(发送验证码暂不迁移,继续使用PHP接口)
|
||||
- **Jwt_Service**: JWT服务,负责生成、验证和刷新JWT Token
|
||||
- **User_Service**: 用户服务,负责用户信息的增删改查
|
||||
- **Redis_Cache**: Redis缓存服务,用于存储验证码和防抖锁
|
||||
- **IP_Location_Service**: IP地理位置服务,用于解析用户登录IP的地理位置
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement 1: 微信小程序登录
|
||||
|
||||
**User Story:** As a 用户, I want to 通过微信小程序授权登录, so that 我可以快速进入系统而无需输入账号密码
|
||||
|
||||
#### Acceptance Criteria
|
||||
|
||||
1. WHEN 用户提交微信授权code, THE Auth_System SHALL 调用微信API获取openid和unionid
|
||||
2. WHEN 获取到openid后, THE Auth_System SHALL 查找是否存在该用户(优先通过unionid查找,其次通过openid查找)
|
||||
3. WHEN 用户不存在时, THE Auth_System SHALL 自动创建新用户并生成默认头像和昵称
|
||||
4. WHEN 用户存在时, THE Auth_System SHALL 更新用户的unionid(如果之前为空)
|
||||
5. WHEN 登录成功后, THE Auth_System SHALL 生成JWT Token并返回给客户端
|
||||
6. WHEN 用户在3秒内重复请求登录, THE Auth_System SHALL 返回"请勿频繁登录"错误(防抖机制)
|
||||
7. IF 微信API调用失败, THEN THE Auth_System SHALL 返回明确的错误信息
|
||||
8. WHEN 用户提供推荐人ID(pid), THE Auth_System SHALL 记录推荐关系
|
||||
|
||||
### Requirement 2: 手机号验证码登录
|
||||
|
||||
**User Story:** As a 用户, I want to 通过手机号和验证码登录, so that 我可以在没有微信的情况下也能登录系统
|
||||
|
||||
#### Acceptance Criteria
|
||||
|
||||
1. WHEN 用户提交手机号和验证码登录, THE Auth_System SHALL 从Redis获取并验证验证码是否正确
|
||||
2. WHEN 验证码验证通过后, THE Auth_System SHALL 删除Redis中的验证码
|
||||
3. WHEN 手机号用户不存在时, THE Auth_System SHALL 自动创建新用户并生成默认头像和昵称
|
||||
4. WHEN 登录成功后, THE Auth_System SHALL 生成JWT Token并返回
|
||||
5. IF 验证码错误或过期, THEN THE Auth_System SHALL 返回"验证码错误"
|
||||
6. WHEN 用户在3秒内重复请求登录, THE Auth_System SHALL 返回"请勿频繁登录"错误
|
||||
7. WHEN 用户提供推荐人ID(pid), THE Auth_System SHALL 记录推荐关系
|
||||
|
||||
**注意:** 发送短信验证码接口暂不迁移,继续使用PHP原有接口
|
||||
|
||||
### Requirement 3: JWT Token管理
|
||||
|
||||
**User Story:** As a 系统, I want to 使用JWT Token进行用户认证, so that 可以实现无状态的安全认证
|
||||
|
||||
#### Acceptance Criteria
|
||||
|
||||
1. WHEN 用户登录成功, THE Jwt_Service SHALL 生成包含用户ID的JWT Token
|
||||
2. THE Jwt_Service SHALL 使用配置的密钥对Token进行签名
|
||||
3. WHEN 请求携带Token访问受保护接口, THE Auth_System SHALL 验证Token的有效性
|
||||
4. IF Token无效或过期, THEN THE Auth_System SHALL 返回状态码-1(未登录)
|
||||
5. WHEN Token即将过期时, THE Jwt_Service SHALL 支持Token刷新功能
|
||||
6. THE Auth_System SHALL 同时在数据库UserAccount表中存储account_token用于兼容旧系统
|
||||
|
||||
### Requirement 4: 用户信息管理
|
||||
|
||||
**User Story:** As a 用户, I want to 查看和修改我的个人信息, so that 我可以维护我的账户资料
|
||||
|
||||
#### Acceptance Criteria
|
||||
|
||||
1. WHEN 用户请求获取个人信息, THE User_Service SHALL 返回用户的完整信息(包括余额、积分、VIP等级等)
|
||||
2. WHEN 用户更新昵称, THE User_Service SHALL 验证昵称不为空并保存
|
||||
3. WHEN 用户上传新头像, THE User_Service SHALL 将Base64图片上传到腾讯云COS并更新头像URL
|
||||
4. THE User_Service SHALL 对手机号进行脱敏处理(显示为138****8000格式)
|
||||
5. WHEN 返回用户信息时, THE User_Service SHALL 计算并返回用户的VIP等级和相关权益
|
||||
|
||||
### Requirement 5: 手机号绑定
|
||||
|
||||
**User Story:** As a 用户, I want to 绑定我的手机号, so that 我可以使用手机号登录并接收重要通知
|
||||
|
||||
#### Acceptance Criteria
|
||||
|
||||
1. WHEN 用户请求绑定手机号, THE Auth_System SHALL 验证短信验证码
|
||||
2. WHEN 手机号已被其他用户绑定, THE Auth_System SHALL 合并两个账户(保留手机号用户,迁移openid)
|
||||
3. WHEN 账户合并后, THE Auth_System SHALL 返回新的Token
|
||||
4. WHEN 手机号未被绑定, THE Auth_System SHALL 直接更新当前用户的手机号
|
||||
5. IF 验证码错误, THEN THE Auth_System SHALL 返回"验证码错误"
|
||||
|
||||
### Requirement 6: 登录记录
|
||||
|
||||
**User Story:** As a 系统管理员, I want to 记录用户的登录信息, so that 可以进行安全审计和用户行为分析
|
||||
|
||||
#### Acceptance Criteria
|
||||
|
||||
1. WHEN 用户登录成功, THE Auth_System SHALL 记录登录日志(包括用户ID、设备类型、IP地址、登录时间)
|
||||
2. WHEN 记录登录时, THE IP_Location_Service SHALL 解析IP地址获取省份和城市信息
|
||||
3. THE Auth_System SHALL 更新UserAccount表中的最后登录时间和IP信息
|
||||
4. WHEN 用户调用recordLogin接口, THE Auth_System SHALL 返回用户的uid、昵称和头像
|
||||
|
||||
### Requirement 7: 账号注销
|
||||
|
||||
**User Story:** As a 用户, I want to 注销我的账号, so that 我可以删除我在系统中的所有数据
|
||||
|
||||
#### Acceptance Criteria
|
||||
|
||||
1. WHEN 用户请求注销账号, THE Auth_System SHALL 记录注销请求日志
|
||||
2. THE Auth_System SHALL 返回注销成功的消息
|
||||
3. WHEN type参数为0时表示注销账号,type为1时表示取消注销
|
||||
|
||||
### Requirement 8: API接口文档更新
|
||||
|
||||
**User Story:** As a 开发者, I want to 在迁移完成后更新API接口文档, so that 可以追踪迁移进度和新接口地址
|
||||
|
||||
#### Acceptance Criteria
|
||||
|
||||
1. WHEN 每个接口迁移完成后, THE 开发者 SHALL 在docs/API接口文档.md中标记该接口为"已迁移"
|
||||
2. THE 文档 SHALL 记录新接口的完整地址
|
||||
3. THE 文档 SHALL 保留原接口信息以便对比
|
||||
190
.kiro/specs/user-auth-migration/tasks.md
Normal file
190
.kiro/specs/user-auth-migration/tasks.md
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
# Implementation Plan: 用户认证系统迁移
|
||||
|
||||
## Overview
|
||||
|
||||
本任务列表将PHP用户认证系统迁移到.NET 8,按照接口优先级逐个迁移,每完成一个接口都需要更新API接口文档标记迁移状态。
|
||||
|
||||
## Tasks
|
||||
|
||||
- [ ] 1. 基础设施准备
|
||||
- [ ] 1.1 创建认证相关的DTO和Request/Response模型
|
||||
- 在HoneyBox.Model/Models目录下创建Auth相关的请求响应模型
|
||||
- 包括WechatLoginRequest、MobileLoginRequest、ApiResponse等
|
||||
- _Requirements: 1.1-1.8, 2.1-2.7_
|
||||
- [ ] 1.2 创建服务接口定义
|
||||
- 在HoneyBox.Core/Interfaces目录下创建IAuthService、IJwtService、IWechatService、IUserService、IIpLocationService接口
|
||||
- _Requirements: 1.1-1.8, 2.1-2.7, 3.1-3.6_
|
||||
- [ ] 1.3 配置JWT认证中间件
|
||||
- 在Program.cs中配置JWT Bearer认证
|
||||
- 添加JwtSettings配置类
|
||||
- _Requirements: 3.1-3.6_
|
||||
- [ ] 1.4 配置Redis服务
|
||||
- 添加StackExchange.Redis依赖
|
||||
- 配置Redis连接和服务注入
|
||||
- _Requirements: 1.6, 2.1, 2.2, 2.6_
|
||||
|
||||
- [ ] 2. JWT服务实现
|
||||
- [ ] 2.1 实现JwtService
|
||||
- 实现Token生成、验证、刷新功能
|
||||
- 实现从Token中提取用户ID
|
||||
- _Requirements: 3.1-3.5_
|
||||
- [ ] 2.2 编写JwtService单元测试
|
||||
- 测试Token生成和验证
|
||||
- **Property 3: 登录成功Token生成**
|
||||
- **Validates: Requirements 3.1, 3.2**
|
||||
- [ ] 2.3 编写Token验证属性测试
|
||||
- **Property 7: Token验证与授权**
|
||||
- **Validates: Requirements 3.3, 3.4**
|
||||
|
||||
- [ ] 3. 用户服务实现
|
||||
- [ ] 3.1 实现UserService基础功能
|
||||
- 实现用户查找(ByOpenId、ByUnionId、ByMobile)
|
||||
- 实现用户创建
|
||||
- 实现UID生成策略
|
||||
- _Requirements: 1.2, 1.3, 2.3_
|
||||
- [ ] 3.2 实现用户信息获取和更新
|
||||
- 实现GetUserInfoAsync
|
||||
- 实现UpdateUserAsync
|
||||
- 实现VIP等级计算
|
||||
- _Requirements: 4.1-4.5_
|
||||
- [ ] 3.3 编写UserService属性测试
|
||||
- **Property 2: 新用户创建完整性**
|
||||
- **Property 9: 用户信息完整性**
|
||||
- **Property 10: 昵称更新验证**
|
||||
- **Property 11: VIP等级计算**
|
||||
- **Validates: Requirements 1.3, 2.3, 4.1, 4.2, 4.4, 4.5**
|
||||
|
||||
- [ ] 4. 微信服务实现
|
||||
- [ ] 4.1 实现WechatService
|
||||
- 实现GetOpenIdAsync(调用微信API获取openid/unionid)
|
||||
- 实现GetMobileAsync(获取微信授权手机号)
|
||||
- _Requirements: 1.1, 5.1_
|
||||
- [ ] 4.2 编写WechatService单元测试
|
||||
- Mock微信API测试
|
||||
- _Requirements: 1.1, 1.7_
|
||||
|
||||
- [ ] 5. IP地理位置服务实现
|
||||
- [ ] 5.1 实现IpLocationService
|
||||
- 调用高德地图API解析IP地址
|
||||
- 返回省份、城市、区域编码
|
||||
- _Requirements: 6.2_
|
||||
|
||||
- [ ] 6. 认证服务实现
|
||||
- [ ] 6.1 实现AuthService - 微信登录
|
||||
- 实现WechatMiniProgramLoginAsync
|
||||
- 包含防抖机制、用户查找/创建、Token生成
|
||||
- _Requirements: 1.1-1.8_
|
||||
- [ ] 6.2 实现AuthService - 手机号登录
|
||||
- 实现MobileLoginAsync
|
||||
- 包含验证码验证、用户查找/创建、Token生成
|
||||
- _Requirements: 2.1-2.7_
|
||||
- [ ] 6.3 实现AuthService - 手机号绑定
|
||||
- 实现BindMobileAsync和WechatBindMobileAsync
|
||||
- 包含账户合并逻辑
|
||||
- _Requirements: 5.1-5.5_
|
||||
- [ ] 6.4 实现AuthService - 登录记录
|
||||
- 实现RecordLoginAsync
|
||||
- 记录登录日志、更新UserAccount
|
||||
- _Requirements: 6.1, 6.3, 6.4_
|
||||
- [ ] 6.5 实现AuthService - 账号注销
|
||||
- 实现LogOffAsync
|
||||
- _Requirements: 7.1-7.3_
|
||||
- [ ] 6.6 编写AuthService属性测试
|
||||
- **Property 1: 微信登录用户查找优先级**
|
||||
- **Property 4: 登录防抖机制**
|
||||
- **Property 5: 推荐关系记录**
|
||||
- **Property 6: 验证码验证与清理**
|
||||
- **Property 8: 数据库Token兼容存储**
|
||||
- **Validates: Requirements 1.2, 1.6, 1.8, 2.1, 2.2, 2.6, 2.7, 3.6**
|
||||
- [ ] 6.7 编写手机号绑定属性测试
|
||||
- **Property 12: 手机号绑定验证码验证**
|
||||
- **Property 13: 账户合并正确性**
|
||||
- **Property 14: 直接绑定手机号**
|
||||
- **Validates: Requirements 5.1-5.5**
|
||||
- [ ] 6.8 编写登录记录属性测试
|
||||
- **Property 15: 登录日志记录**
|
||||
- **Property 16: recordLogin接口返回值**
|
||||
- **Property 17: 账号注销类型处理**
|
||||
- **Validates: Requirements 6.1, 6.3, 6.4, 7.1-7.3**
|
||||
|
||||
- [ ] 7. Checkpoint - 服务层测试验证
|
||||
- 确保所有服务层单元测试通过
|
||||
- 确保所有属性测试通过
|
||||
- 如有问题请询问用户
|
||||
|
||||
- [ ] 8. 控制器实现 - AuthController
|
||||
- [ ] 8.1 实现微信小程序登录接口 POST /login
|
||||
- 调用AuthService.WechatMiniProgramLoginAsync
|
||||
- 更新API接口文档标记迁移状态
|
||||
- _Requirements: 1.1-1.8_
|
||||
- [ ] 8.2 实现手机号登录接口 POST /mobileLogin
|
||||
- 调用AuthService.MobileLoginAsync
|
||||
- 更新API接口文档标记迁移状态
|
||||
- _Requirements: 2.1-2.7_
|
||||
- [ ] 8.3 实现微信授权绑定手机号接口 POST /login_bind_mobile
|
||||
- 调用AuthService.WechatBindMobileAsync
|
||||
- 更新API接口文档标记迁移状态
|
||||
- _Requirements: 5.1-5.5_
|
||||
- [ ] 8.4 实现验证码绑定手机号接口 POST /bindMobile
|
||||
- 调用AuthService.BindMobileAsync
|
||||
- 更新API接口文档标记迁移状态
|
||||
- _Requirements: 5.1-5.5_
|
||||
- [ ] 8.5 实现登录记录接口 GET|POST /login_record
|
||||
- 调用AuthService.RecordLoginAsync
|
||||
- 更新API接口文档标记迁移状态
|
||||
- _Requirements: 6.1-6.4_
|
||||
|
||||
- [ ] 9. 控制器实现 - UserController
|
||||
- [ ] 9.1 实现获取用户信息接口 POST /user
|
||||
- 调用UserService.GetUserInfoAsync
|
||||
- 更新API接口文档标记迁移状态
|
||||
- _Requirements: 4.1-4.5_
|
||||
- [ ] 9.2 实现更新用户信息接口 POST /update_userinfo
|
||||
- 调用UserService.UpdateUserAsync
|
||||
- 支持Base64头像上传到腾讯云COS
|
||||
- 更新API接口文档标记迁移状态
|
||||
- _Requirements: 4.2, 4.3_
|
||||
- [ ] 9.3 实现账号注销接口 POST /user_log_off
|
||||
- 调用AuthService.LogOffAsync
|
||||
- 更新API接口文档标记迁移状态
|
||||
- _Requirements: 7.1-7.3_
|
||||
|
||||
- [ ] 10. Checkpoint - 控制器测试验证
|
||||
- 确保所有控制器接口可正常访问
|
||||
- 使用Postman或HTTP文件测试各接口
|
||||
- 如有问题请询问用户
|
||||
|
||||
- [ ] 11. 集成测试
|
||||
- [ ] 11.1 编写微信登录集成测试
|
||||
- 测试完整的微信登录流程
|
||||
- _Requirements: 1.1-1.8_
|
||||
- [ ] 11.2 编写手机号登录集成测试
|
||||
- 测试完整的手机号登录流程
|
||||
- _Requirements: 2.1-2.7_
|
||||
- [ ] 11.3 编写用户信息接口集成测试
|
||||
- 测试用户信息获取和更新流程
|
||||
- _Requirements: 4.1-4.5_
|
||||
|
||||
- [ ] 12. 文档更新和最终验证
|
||||
- [ ] 12.1 更新API接口文档
|
||||
- 确认所有迁移接口都已标记
|
||||
- 记录新接口地址
|
||||
- _Requirements: 8.1-8.3_
|
||||
- [ ] 12.2 创建HTTP测试文件
|
||||
- 在HoneyBox.Api目录下创建auth.http测试文件
|
||||
- 包含所有认证相关接口的测试请求
|
||||
|
||||
- [ ] 13. Final Checkpoint - 完整功能验证
|
||||
- 确保所有测试通过
|
||||
- 确保API文档已更新
|
||||
- 确保与前端兼容性
|
||||
- 如有问题请询问用户
|
||||
|
||||
## Notes
|
||||
|
||||
- All tasks are required for comprehensive testing from the start
|
||||
- Each task references specific requirements for traceability
|
||||
- Checkpoints ensure incremental validation
|
||||
- Property tests validate universal correctness properties
|
||||
- Unit tests validate specific examples and edge cases
|
||||
- 每迁移完成一个接口,都需要在docs/API接口文档.md中标记迁移状态和新接口地址
|
||||
Loading…
Reference in New Issue
Block a user