From 1ffea953bf28dd4245715353e9b4239e506dfd8b Mon Sep 17 00:00:00 2001 From: anlicheng <244108715@qq.com> Date: Mon, 23 Mar 2026 23:54:20 +0800 Subject: [PATCH] fix login --- punchnet/Networking/SDLAPIClient+User.swift | 73 +++++++++++ punchnet/Networking/SDLAPIClient.swift | 6 + punchnet/Views/AppContext.swift | 2 +- punchnet/Views/Login/LoginView.swift | 7 +- punchnet/Views/Network/NetworkModel.swift | 2 +- punchnet/Views/RootView.swift | 2 +- .../Views/Settings/SettingsNetworkView.swift | 2 +- punchnet/Views/UserContext.swift | 123 +++--------------- 8 files changed, 103 insertions(+), 114 deletions(-) create mode 100644 punchnet/Networking/SDLAPIClient+User.swift diff --git a/punchnet/Networking/SDLAPIClient+User.swift b/punchnet/Networking/SDLAPIClient+User.swift new file mode 100644 index 0000000..c565269 --- /dev/null +++ b/punchnet/Networking/SDLAPIClient+User.swift @@ -0,0 +1,73 @@ +// +// NetworkSession.swift +// punchnet +// +// Created by 安礼成 on 2026/3/23. +// +import Foundation + +extension SDLAPIClient { + + // 登陆后的网络会话信息 + struct NetworkSession: Codable { + struct ExitNode: Codable { + let uuid = UUID().uuidString + let nnid: Int + let nodeName: String + + enum CodingKeys: String, CodingKey { + case nnid + case nodeName = "node_name" + } + } + + let accessToken: String + let username: String + let userType: String + let audit: Int + let networkId: Int + let networkName: String + let networkDomain: String + let exitNodes: [ExitNode] + + // TODO + var networkUrl: String { + return "https://www.test.cn/id=\(self.networkId)" + } + + enum CodingKeys: String, CodingKey { + case accessToken = "access_token" + case username + case userType = "user_type" + case audit + case networkId = "network_id" + case networkName = "network_name" + case networkDomain = "network_domain" + case exitNodes = "exit_node" + } + } + + static func loginWithAccountAndPassword(username: String, password: String) async throws -> NetworkSession { + var params: [String: Any] = [ + "username": username, + "password": password, + "system": SystemConfig.systemInfo, + "version": SystemConfig.version_name + ] + params.merge(baseParams) {$1} + + return try await SDLAPIClient.doPost(path: "/auth/login", params: params, as: NetworkSession.self) + } + + static func loginWithToken(token: String) async throws -> NetworkSession { + var params: [String: Any] = [ + "token": token, + "system": SystemConfig.systemInfo, + "version": SystemConfig.version_name + ] + params.merge(baseParams) {$1} + + return try await SDLAPIClient.doPost(path: "/auth/token", params: params, as: NetworkSession.self) + } + +} diff --git a/punchnet/Networking/SDLAPIClient.swift b/punchnet/Networking/SDLAPIClient.swift index d11224c..188096f 100644 --- a/punchnet/Networking/SDLAPIClient.swift +++ b/punchnet/Networking/SDLAPIClient.swift @@ -23,6 +23,12 @@ struct SDLAPIClient { static var baseUrl: String = "https://punchnet.s5s8.com/api" static private let token: String = "H6p*2RfEu4ITcL" + // 基础参数信息 + static let baseParams: [String: Any] = [ + "client_id": SystemConfig.getClientId(), + "mac": SystemConfig.macAddressString(mac: SystemConfig.getMacAddress()) + ] + static func doPost(path: String, params: [String: Any], as: T.Type) async throws -> T { let postData = try! JSONSerialization.data(withJSONObject: params) var request = URLRequest(url: URL(string: baseUrl + path)!) diff --git a/punchnet/Views/AppContext.swift b/punchnet/Views/AppContext.swift index d678f18..f1c3de0 100644 --- a/punchnet/Views/AppContext.swift +++ b/punchnet/Views/AppContext.swift @@ -16,7 +16,7 @@ class AppContext { var networkContext: NetworkContext? // 当前的场景 - enum AppScene { + enum AppScene: Equatable { case login(username: String?) case logined case register diff --git a/punchnet/Views/Login/LoginView.swift b/punchnet/Views/Login/LoginView.swift index 607efcd..b0299c5 100644 --- a/punchnet/Views/Login/LoginView.swift +++ b/punchnet/Views/Login/LoginView.swift @@ -172,7 +172,7 @@ struct LoginAccountView: View { } do { - _ = try await userContext.loginWithAccountAndPassword(username: username, password: password) + _ = try await userContext.loginWith(credit: .accountAndPasword(account: username, password: password)) withAnimation(.spring(duration: 0.6, bounce: 0.2)) { self.appContext.appScene = .logined } @@ -234,10 +234,13 @@ struct LoginTokenView: View { } do { - _ = try await userContext.loginWithToken(token: token) + _ = try await userContext.loginWith(credit: .token(token: token)) withAnimation(.spring(duration: 0.6, bounce: 0.2)) { self.appContext.appScene = .logined } + } catch let err as SDLAPIError { + self.showAlert = true + self.errorMessage = err.message } catch let err { self.showAlert = true self.errorMessage = err.localizedDescription diff --git a/punchnet/Views/Network/NetworkModel.swift b/punchnet/Views/Network/NetworkModel.swift index 444c415..f1a2076 100644 --- a/punchnet/Views/Network/NetworkModel.swift +++ b/punchnet/Views/Network/NetworkModel.swift @@ -111,7 +111,7 @@ class NetworkModel { } } - func connect(networkSession: UserContext.NetworkSession) async throws -> NetworkContext { + func connect(networkSession: SDLAPIClient.NetworkSession) async throws -> NetworkContext { let params: [String: Any] = [ "client_id": SystemConfig.getClientId(), "access_token": networkSession.accessToken diff --git a/punchnet/Views/RootView.swift b/punchnet/Views/RootView.swift index bf57034..56ff052 100644 --- a/punchnet/Views/RootView.swift +++ b/punchnet/Views/RootView.swift @@ -19,7 +19,7 @@ struct RootView: View { Group { switch appContext.appScene { case .login(username: let username): - LoginView() + LoginView(username: username) case .logined: NetworkView() case .register: diff --git a/punchnet/Views/Settings/SettingsNetworkView.swift b/punchnet/Views/Settings/SettingsNetworkView.swift index 1dbf3f5..fa1362f 100644 --- a/punchnet/Views/Settings/SettingsNetworkView.swift +++ b/punchnet/Views/Settings/SettingsNetworkView.swift @@ -10,7 +10,7 @@ struct SettingsNetworkView: View { @Environment(UserContext.self) var userContext: UserContext @Environment(\.openURL) var openURL - @State private var selectedExitNode: UserContext.NetworkSession.ExitNode? + @State private var selectedExitNode: SDLAPIClient.NetworkSession.ExitNode? var body: some View { ScrollView(.vertical, showsIndicators: false) { diff --git a/punchnet/Views/UserContext.swift b/punchnet/Views/UserContext.swift index 5e1a0ea..e0c7407 100644 --- a/punchnet/Views/UserContext.swift +++ b/punchnet/Views/UserContext.swift @@ -11,126 +11,33 @@ import Observation @Observable class UserContext { var loginCredit: Credit? - var networkSession: NetworkSession? + var networkSession: SDLAPIClient.NetworkSession? enum Credit { case token(token: String) case accountAndPasword(account: String, password: String) } - // 登陆后的网络会话信息 - struct NetworkSession: Codable { - struct ExitNode: Codable { - let uuid = UUID().uuidString - let nnid: Int - let nodeName: String - - enum CodingKeys: String, CodingKey { - case nnid - case nodeName = "node_name" + func loginWith(credit: Credit) async throws -> Bool { + switch credit { + case .token(let token): + self.networkSession = try await SDLAPIClient.loginWithToken(token: token) + // 将数据缓存到keychain + if let data = token.data(using: .utf8) { + try KeychainStore.shared.save(data, account: "token") + } + case .accountAndPasword(let username, let password): + self.networkSession = try await SDLAPIClient.loginWithAccountAndPassword(username: username, password: password) + // 将数据缓存到keychain + if let data = "\(username):\(password)".data(using: .utf8) { + try KeychainStore.shared.save(data, account: "accountAndPasword") } } - - let accessToken: String - let username: String - let userType: String - let audit: Int - let networkId: Int - let networkName: String - let networkDomain: String - let exitNodes: [ExitNode] - - var networkUrl: String { - return "https://www.test.cn/id=\(self.networkId)" - } - - enum CodingKeys: String, CodingKey { - case accessToken = "access_token" - case username - case userType = "user_type" - case audit - case networkId = "network_id" - case networkName = "network_name" - case networkDomain = "network_domain" - case exitNodes = "exit_node" - } - } - - private let baseParams: [String: Any] = [ - "client_id": SystemConfig.getClientId(), - "mac": SystemConfig.macAddressString(mac: SystemConfig.getMacAddress()) - ] - - @MainActor - func loginWithAccountAndPassword(username: String, password: String) async throws -> Bool { - var params: [String: Any] = [ - "username": username, - "password": password, - "system": SystemConfig.systemInfo, - "version": SystemConfig.version_name - ] - params.merge(baseParams) {$1} - - self.networkSession = try await SDLAPIClient.doPost(path: "/auth/login", params: params, as: NetworkSession.self) - self.loginCredit = .accountAndPasword(account: username, password: password) - - // 将数据缓存到keychain - if let data = "\(username):\(password)".data(using: .utf8) { - try KeychainStore.shared.save(data, account: "accountAndPasword") - } + self.loginCredit = credit return true } - @MainActor - func loginWithToken(token: String) async throws -> Bool { - var params: [String: Any] = [ - "token": token, - "system": SystemConfig.systemInfo, - "version": SystemConfig.version_name - ] - params.merge(baseParams) {$1} - - self.networkSession = try await SDLAPIClient.doPost(path: "/auth/token", params: params, as: NetworkSession.self) - self.loginCredit = .token(token: token) - - // 将数据缓存到keychain - if let data = token.data(using: .utf8) { - try KeychainStore.shared.save(data, account: "token") - } - - return true - } - -// func sendVerifyCode(username: String) async throws -> String { -// var params: [String: Any] = [ -// "username": username -// ] -// params.merge(baseParams) {$1} -// -// return try await SDLAPIClient.doPost(path: "/auth/sendVerifyCode", params: params, as: String.self) -// } -// -// func submitVerifyCode(username: String, verifyCode: String) async throws -> String { -// var params: [String: Any] = [ -// "username": username, -// "verify_code": verifyCode, -// ] -// params.merge(baseParams) {$1} -// -// return try await SDLAPIClient.doPost(path: "/auth/submitVerifyCode", params: params, as: String.self) -// } -// -// func resetPassword(username: String, password: String) async throws -> String { -// var params: [String: Any] = [ -// "username": username, -// "password": password, -// ] -// params.merge(baseParams) {$1} -// -// return try await SDLAPIClient.doPost(path: "/auth/resetPassword", params: params, as: String.self) -// } - func loadCacheToken() -> String? { if let data = try? KeychainStore.shared.load(account: "token") { return String(data: data, encoding: .utf8)