feat: 1 2
This commit is contained in:
parent
112912a6d3
commit
44c1ed4d60
@ -4,7 +4,7 @@ import Security
|
|||||||
/// 用于安全存储和检索敏感信息(如令牌)的 Keychain 帮助类
|
/// 用于安全存储和检索敏感信息(如令牌)的 Keychain 帮助类
|
||||||
public class KeychainHelper {
|
public class KeychainHelper {
|
||||||
// Keychain 键名
|
// Keychain 键名
|
||||||
private enum KeychainKey: String {
|
private enum KeychainKey: String, CaseIterable {
|
||||||
case accessToken = "com.memorywake.accessToken"
|
case accessToken = "com.memorywake.accessToken"
|
||||||
case refreshToken = "com.memorywake.refreshToken"
|
case refreshToken = "com.memorywake.refreshToken"
|
||||||
}
|
}
|
||||||
@ -35,6 +35,38 @@ public class KeychainHelper {
|
|||||||
delete(for: .refreshToken)
|
delete(for: .refreshToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 清除所有存储的 Keychain 数据
|
||||||
|
public static func clearAll() {
|
||||||
|
// 清除所有已知的 keychain 项
|
||||||
|
KeychainKey.allCases.forEach { key in
|
||||||
|
delete(for: key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 额外清理:删除所有通用密码项(作为安全措施)
|
||||||
|
let query: [String: Any] = [
|
||||||
|
kSecClass as String: kSecClassGenericPassword,
|
||||||
|
kSecReturnAttributes as String: true,
|
||||||
|
kSecMatchLimit as String: kSecMatchLimitAll
|
||||||
|
]
|
||||||
|
|
||||||
|
var result: AnyObject?
|
||||||
|
let status = SecItemCopyMatching(query as CFDictionary, &result)
|
||||||
|
|
||||||
|
if status == errSecSuccess, let items = result as? [[String: Any]] {
|
||||||
|
for item in items {
|
||||||
|
if let account = item[kSecAttrAccount as String] as? String,
|
||||||
|
let service = item[kSecAttrService as String] as? String {
|
||||||
|
let deleteQuery: [String: Any] = [
|
||||||
|
kSecClass as String: kSecClassGenericPassword,
|
||||||
|
kSecAttrAccount as String: account,
|
||||||
|
kSecAttrService as String: service
|
||||||
|
]
|
||||||
|
SecItemDelete(deleteQuery as CFDictionary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - 私有方法
|
// MARK: - 私有方法
|
||||||
|
|
||||||
private static func save(_ string: String, for key: KeychainKey) -> Bool {
|
private static func save(_ string: String, for key: KeychainKey) -> Bool {
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import SwiftUI
|
|||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
enum AppRoute: Hashable {
|
enum AppRoute: Hashable {
|
||||||
|
case login
|
||||||
case avatarBox
|
case avatarBox
|
||||||
case feedbackView
|
case feedbackView
|
||||||
case feedbackDetail(type: FeedbackView.FeedbackType)
|
case feedbackDetail(type: FeedbackView.FeedbackType)
|
||||||
@ -12,6 +13,8 @@ enum AppRoute: Hashable {
|
|||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
var view: some View {
|
var view: some View {
|
||||||
switch self {
|
switch self {
|
||||||
|
case .login:
|
||||||
|
LoginView()
|
||||||
case .avatarBox:
|
case .avatarBox:
|
||||||
AvatarBoxView()
|
AvatarBoxView()
|
||||||
case .feedbackView:
|
case .feedbackView:
|
||||||
|
|||||||
@ -56,6 +56,7 @@ public struct AvatarPicker: View {
|
|||||||
SVGImage(svgName: "IP")
|
SVGImage(svgName: "IP")
|
||||||
.frame(width: avatarSize, height: avatarSize)
|
.frame(width: avatarSize, height: avatarSize)
|
||||||
.contentShape(Rectangle())
|
.contentShape(Rectangle())
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 20))
|
||||||
.overlay(
|
.overlay(
|
||||||
RoundedRectangle(cornerRadius: 20)
|
RoundedRectangle(cornerRadius: 20)
|
||||||
.stroke(style: StrokeStyle(
|
.stroke(style: StrokeStyle(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user