feat: 增强邮箱登录功能和密码恢复流程
- 更新邮箱登录相关功能,新增邮箱验证码获取和登录API端点。 - 添加AccountModel以管理用户认证信息,支持会话票据的存储和更新。 - 实现密码恢复功能,支持通过邮箱获取验证码和重置密码。 - 增加本地化支持,更新相关字符串以适应新功能。 - 引入ValidationHelper以验证邮箱和密码格式,确保用户输入的有效性。 - 更新视图以支持邮箱登录和密码恢复的用户交互。
This commit is contained in:
@@ -1,5 +1,75 @@
|
||||
import Foundation
|
||||
|
||||
// MARK: - Account Model
|
||||
/// 账户认证信息模型
|
||||
/// 用于承接 oauth/token 和 oauth/ticket 接口的认证数据
|
||||
/// 参照 OC 版本的 AccountModel 设计
|
||||
struct AccountModel: Codable, Equatable {
|
||||
let uid: String? // 用户唯一标识
|
||||
let jti: String? // JWT ID
|
||||
let tokenType: String? // Token 类型 (bearer)
|
||||
let refreshToken: String? // 刷新令牌
|
||||
let netEaseToken: String? // 网易云信令牌
|
||||
let accessToken: String? // OAuth 访问令牌
|
||||
let expiresIn: Int? // 过期时间(秒)
|
||||
let scope: String? // 权限范围
|
||||
var ticket: String? // 业务会话票据(来自 oauth/ticket)
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case uid
|
||||
case jti
|
||||
case tokenType = "token_type"
|
||||
case refreshToken = "refresh_token"
|
||||
case netEaseToken
|
||||
case accessToken = "access_token"
|
||||
case expiresIn = "expires_in"
|
||||
case scope
|
||||
case ticket
|
||||
}
|
||||
|
||||
/// 检查是否有有效的认证信息
|
||||
var hasValidAuthentication: Bool {
|
||||
return accessToken != nil && !accessToken!.isEmpty
|
||||
}
|
||||
|
||||
/// 检查是否有有效的业务会话
|
||||
var hasValidSession: Bool {
|
||||
return hasValidAuthentication && ticket != nil && !ticket!.isEmpty
|
||||
}
|
||||
|
||||
/// 从 IDLoginData 创建 AccountModel
|
||||
/// - Parameter loginData: 登录响应数据
|
||||
/// - Returns: AccountModel 实例,如果数据无效则返回 nil
|
||||
static func from(loginData: IDLoginData) -> AccountModel? {
|
||||
// 确保至少有 accessToken 和 uid
|
||||
guard let accessToken = loginData.accessToken,
|
||||
let uid = loginData.uid else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return AccountModel(
|
||||
uid: String(uid),
|
||||
jti: loginData.jti,
|
||||
tokenType: loginData.tokenType,
|
||||
refreshToken: loginData.refreshToken,
|
||||
netEaseToken: loginData.netEaseToken,
|
||||
accessToken: accessToken,
|
||||
expiresIn: loginData.expiresIn,
|
||||
scope: loginData.scope,
|
||||
ticket: nil // 初始为空,后续通过 oauth/ticket 填充
|
||||
)
|
||||
}
|
||||
|
||||
/// 更新 ticket 信息
|
||||
/// - Parameter ticket: 从 oauth/ticket 获取的票据
|
||||
/// - Returns: 更新后的 AccountModel
|
||||
func withTicket(_ ticket: String) -> AccountModel {
|
||||
var updatedModel = self
|
||||
updatedModel.ticket = ticket
|
||||
return updatedModel
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - ID Login Request Model
|
||||
struct IDLoginAPIRequest: APIRequestProtocol {
|
||||
typealias Response = IDLoginResponse
|
||||
@@ -234,3 +304,120 @@ struct TicketHelper {
|
||||
|
||||
// MARK: - 兼容旧的LoginResponse(如果需要)
|
||||
typealias LoginResponse = IDLoginResponse
|
||||
|
||||
// MARK: - Email Verification Code Models
|
||||
|
||||
/// 邮箱验证码获取请求
|
||||
struct EmailGetCodeRequest: APIRequestProtocol {
|
||||
typealias Response = EmailGetCodeResponse
|
||||
|
||||
let endpoint = APIEndpoint.emailGetCode.path
|
||||
let method: HTTPMethod = .POST
|
||||
let includeBaseParameters = true
|
||||
let queryParameters: [String: String]?
|
||||
let bodyParameters: [String: Any]? = nil
|
||||
let timeout: TimeInterval = 30.0
|
||||
|
||||
/// 初始化邮箱验证码获取请求
|
||||
/// - Parameters:
|
||||
/// - emailAddress: DES加密后的邮箱地址
|
||||
/// - type: 验证码类型(1=注册/登录)
|
||||
init(emailAddress: String, type: Int = 1) {
|
||||
self.queryParameters = [
|
||||
"emailAddress": emailAddress,
|
||||
"type": String(type)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/// 邮箱验证码获取响应
|
||||
struct EmailGetCodeResponse: Codable, Equatable {
|
||||
let status: String?
|
||||
let message: String?
|
||||
let code: Int?
|
||||
let data: String? // 通常为空,成功时只需要检查状态码
|
||||
|
||||
/// 是否发送成功
|
||||
var isSuccess: Bool {
|
||||
return code == 200 || status?.lowercased() == "success"
|
||||
}
|
||||
|
||||
/// 错误消息(如果有)
|
||||
var errorMessage: String {
|
||||
return message ?? "验证码发送失败,请重试"
|
||||
}
|
||||
}
|
||||
|
||||
/// 邮箱验证码登录请求
|
||||
struct EmailLoginRequest: APIRequestProtocol {
|
||||
typealias Response = IDLoginResponse // 复用ID登录的响应模型
|
||||
|
||||
let endpoint = APIEndpoint.login.path
|
||||
let method: HTTPMethod = .POST
|
||||
let includeBaseParameters = true
|
||||
let queryParameters: [String: String]?
|
||||
let bodyParameters: [String: Any]? = nil
|
||||
let timeout: TimeInterval = 30.0
|
||||
|
||||
/// 初始化邮箱验证码登录请求
|
||||
/// - Parameters:
|
||||
/// - email: DES加密后的邮箱地址
|
||||
/// - code: 验证码
|
||||
/// - clientSecret: 客户端密钥,固定为"uyzjdhds"
|
||||
/// - version: 版本号,固定为"1"
|
||||
/// - clientId: 客户端ID,固定为"erban-client"
|
||||
/// - grantType: 授权类型,固定为"email"
|
||||
init(email: String, code: String, clientSecret: String = "uyzjdhds", version: String = "1", clientId: String = "erban-client", grantType: String = "email") {
|
||||
self.queryParameters = [
|
||||
"email": email,
|
||||
"code": code,
|
||||
"client_secret": clientSecret,
|
||||
"version": version,
|
||||
"client_id": clientId,
|
||||
"grant_type": grantType
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Email Login Helper
|
||||
extension LoginHelper {
|
||||
|
||||
/// 创建邮箱验证码获取请求
|
||||
/// - Parameter email: 原始邮箱地址
|
||||
/// - Returns: 配置好的API请求,如果加密失败返回nil
|
||||
static func createEmailGetCodeRequest(email: String) -> EmailGetCodeRequest? {
|
||||
let encryptionKey = "1ea53d260ecf11e7b56e00163e046a26"
|
||||
|
||||
guard let encryptedEmail = DESEncrypt.encryptUseDES(email, key: encryptionKey) else {
|
||||
print("❌ 邮箱DES加密失败")
|
||||
return nil
|
||||
}
|
||||
|
||||
print("🔐 邮箱DES加密成功")
|
||||
print(" 原始邮箱: \(email)")
|
||||
print(" 加密邮箱: \(encryptedEmail)")
|
||||
|
||||
return EmailGetCodeRequest(emailAddress: email, type: 1)
|
||||
}
|
||||
|
||||
/// 创建邮箱验证码登录请求
|
||||
/// - Parameters:
|
||||
/// - email: 原始邮箱地址
|
||||
/// - code: 验证码
|
||||
/// - Returns: 配置好的API请求,如果加密失败返回nil
|
||||
static func createEmailLoginRequest(email: String, code: String) -> EmailLoginRequest? {
|
||||
let encryptionKey = "1ea53d260ecf11e7b56e00163e046a26"
|
||||
|
||||
guard let encryptedEmail = DESEncrypt.encryptUseDES(email, key: encryptionKey) else {
|
||||
print("❌ 邮箱DES加密失败")
|
||||
return nil
|
||||
}
|
||||
|
||||
print("🔐 邮箱验证码登录DES加密成功")
|
||||
print(" 原始邮箱: \(email)")
|
||||
print(" 加密邮箱: \(encryptedEmail)")
|
||||
print(" 验证码: \(code)")
|
||||
|
||||
return EmailLoginRequest(email: encryptedEmail, code: code)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user