mirror of
https://github.com/easychen/pushdeer.git
synced 2025-02-23 00:14:56 +08:00
Merge pull request #148 from Hext123/main
获取用户信息时增加了simple_token字段,存下来,token过期以后调用 /login/simple_token 重新获得新的认证token
This commit is contained in:
commit
8e5292acfb
@ -49,4 +49,4 @@ SPEC CHECKSUMS:
|
||||
|
||||
PODFILE CHECKSUM: 42e3d8abd976589c1043ff9f9e864c275a490160
|
||||
|
||||
COCOAPODS: 1.11.2
|
||||
COCOAPODS: 1.11.3
|
||||
|
@ -97,6 +97,9 @@
|
||||
52EB90B32778DA4E0048E0ED /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52EB90B22778DA4E0048E0ED /* Line.swift */; };
|
||||
52EED71E27C9394D0086A804 /* WXDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52EED71D27C9394D0086A804 /* WXDelegate.swift */; };
|
||||
52EED71F27C93B960086A804 /* WXDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52EED71D27C9394D0086A804 /* WXDelegate.swift */; };
|
||||
52EF0AFC28CE081A00C99E4F /* CommonUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52EF0AFB28CE081A00C99E4F /* CommonUtils.swift */; };
|
||||
52EF0AFD28CE081A00C99E4F /* CommonUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52EF0AFB28CE081A00C99E4F /* CommonUtils.swift */; };
|
||||
52EF0AFE28CE08EC00C99E4F /* CommonUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52EF0AFB28CE081A00C99E4F /* CommonUtils.swift */; };
|
||||
52F0243F277737470071D861 /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52F0243E277737470071D861 /* LoginView.swift */; };
|
||||
52F2C223277961D7006F08DC /* SettingsItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52F2C222277961D7006F08DC /* SettingsItemView.swift */; };
|
||||
52F40D2F277CA05600766C24 /* MessageItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52F40D2E277CA05600766C24 /* MessageItemView.swift */; };
|
||||
@ -218,6 +221,7 @@
|
||||
52EB90AF2778D67F0048E0ED /* KeyItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyItemView.swift; sourceTree = "<group>"; };
|
||||
52EB90B22778DA4E0048E0ED /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = "<group>"; };
|
||||
52EED71D27C9394D0086A804 /* WXDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WXDelegate.swift; sourceTree = "<group>"; };
|
||||
52EF0AFB28CE081A00C99E4F /* CommonUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommonUtils.swift; sourceTree = "<group>"; };
|
||||
52F0243C277733CE0071D861 /* PushDeer.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = PushDeer.entitlements; sourceTree = "<group>"; };
|
||||
52F0243E277737470071D861 /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = "<group>"; };
|
||||
52F2C222277961D7006F08DC /* SettingsItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsItemView.swift; sourceTree = "<group>"; };
|
||||
@ -367,6 +371,7 @@
|
||||
527872C327CE0EE800AD79AD /* Info-SelfHosted.plist */,
|
||||
52E317DA279305BB000B8BB1 /* Localizable.strings */,
|
||||
52E317D7279305BB000B8BB1 /* InfoPlist.strings */,
|
||||
52EF0AFA28CE07A600C99E4F /* Tool */,
|
||||
52450F362784822C003652D8 /* Service */,
|
||||
52B8CF5D277DE5FF004CB680 /* Common */,
|
||||
52450F3D27849228003652D8 /* Model */,
|
||||
@ -447,6 +452,14 @@
|
||||
path = Common;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
52EF0AFA28CE07A600C99E4F /* Tool */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
52EF0AFB28CE081A00C99E4F /* CommonUtils.swift */,
|
||||
);
|
||||
path = Tool;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
52F0243D2777370F0071D861 /* View */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -776,6 +789,7 @@
|
||||
5206009E27CF76BC00188431 /* PushDeerApi.swift in Sources */,
|
||||
520600A627D0AE2300188431 /* Line.swift in Sources */,
|
||||
5206009D27CF74C100188431 /* HttpRequest.swift in Sources */,
|
||||
52EF0AFE28CE08EC00C99E4F /* CommonUtils.swift in Sources */,
|
||||
520600A127CF770600188431 /* Env.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -810,6 +824,7 @@
|
||||
52EED71E27C9394D0086A804 /* WXDelegate.swift in Sources */,
|
||||
52EB90AE2778AFD60048E0ED /* BaseNavigationView.swift in Sources */,
|
||||
524E99E627B3CD0F00292396 /* EndpointView.swift in Sources */,
|
||||
52EF0AFC28CE081A00C99E4F /* CommonUtils.swift in Sources */,
|
||||
52EB90AC2778ADF80048E0ED /* CardView.swift in Sources */,
|
||||
52EB90B02778D67F0048E0ED /* KeyItemView.swift in Sources */,
|
||||
52AC5C2827B7FE1D00EEB185 /* ViewExtension.swift in Sources */,
|
||||
@ -853,6 +868,7 @@
|
||||
52FBA09427874879003308C2 /* ContentView.swift in Sources */,
|
||||
52B8CF85277E0C12004CB680 /* Line.swift in Sources */,
|
||||
52AC5C2927B7FE1D00EEB185 /* ViewExtension.swift in Sources */,
|
||||
52EF0AFD28CE081A00C99E4F /* CommonUtils.swift in Sources */,
|
||||
52450F402784923D003652D8 /* Result.swift in Sources */,
|
||||
526A1E712791E00400BA2177 /* PushDeerData.xcdatamodeld in Sources */,
|
||||
52450F432784943F003652D8 /* HttpRequest.swift in Sources */,
|
||||
|
@ -29,6 +29,7 @@ struct UserInfoContent: Codable{
|
||||
let level: Int
|
||||
let created_at: String
|
||||
let updated_at: String
|
||||
let simple_token: String?
|
||||
}
|
||||
|
||||
struct DeviceItem: Codable, Identifiable{
|
||||
@ -78,6 +79,12 @@ struct ResultContent: Codable{
|
||||
let result: Array<String>
|
||||
}
|
||||
|
||||
|
||||
struct STokenContent: Codable{
|
||||
let stoken: String?
|
||||
}
|
||||
|
||||
|
||||
let dateFormatter = DateFormatter()
|
||||
|
||||
extension KeyItem {
|
||||
|
@ -125,6 +125,35 @@ class AppState: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
func loginAfter() {
|
||||
Task {
|
||||
// 查询 UserInfo
|
||||
self.userInfo = try await HttpRequest.getUserInfo()
|
||||
var stoken = self.userInfo?.simple_token
|
||||
if isEmpty(stoken) {
|
||||
// UserInfo 中的 stoken 为空, 就重新生成一个
|
||||
stoken = try await HttpRequest.stokenRegen().stoken
|
||||
}
|
||||
if isNotEmpty(stoken) {
|
||||
// 最后 stoken 不为空, 就保存到本地
|
||||
self.saveSTokenToLocal(stoken: stoken)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func saveSTokenToLocal(stoken: String?) -> Void {
|
||||
let key = "stoken_\(self.api_endpoint)"
|
||||
getUserDefaults().set(stoken, forKey: key)
|
||||
}
|
||||
func getLocalSToken() -> String? {
|
||||
let key = "stoken_\(self.api_endpoint)"
|
||||
return getUserDefaults().string(forKey: key)
|
||||
}
|
||||
func deleteLocalSToken() -> Void {
|
||||
let key = "stoken_\(self.api_endpoint)"
|
||||
getUserDefaults().removeObject(forKey: key)
|
||||
}
|
||||
|
||||
func appleIdLogin(_ result: Result<ASAuthorization, Error>) async throws -> TokenContent {
|
||||
switch result {
|
||||
case let .success(authorization):
|
||||
|
@ -8,13 +8,63 @@
|
||||
import Foundation
|
||||
import Moya
|
||||
|
||||
struct TokenAuthorizationPlugin: PluginType {
|
||||
|
||||
func prepare(_ request: URLRequest, target: TargetType) -> URLRequest {
|
||||
if
|
||||
let url = request.url,
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true),
|
||||
let queryItems = components.queryItems
|
||||
{
|
||||
let queryItems_new = queryItems.map { item -> URLQueryItem in
|
||||
if item.name == "token" {
|
||||
// 把请求参数中的 token 都换成最新的
|
||||
return URLQueryItem(name: "token", value: AppState.shared.token)
|
||||
}
|
||||
return item
|
||||
}
|
||||
components.queryItems = queryItems_new
|
||||
var request_mutable = request
|
||||
request_mutable.url = components.url
|
||||
return request_mutable
|
||||
}
|
||||
return request
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
struct HttpRequest {
|
||||
|
||||
static let provider = MoyaProvider<PushDeerApi>(callbackQueue: DispatchQueue.main)
|
||||
static let provider = MoyaProvider<PushDeerApi>(callbackQueue: DispatchQueue.main, plugins: [TokenAuthorizationPlugin()])
|
||||
|
||||
/// 统一处理接口请求, 并且封装成 Swift Concurrency 模式 (async / await)
|
||||
static func request<T: Codable>(_ targetType: PushDeerApi, resultType: T.Type) async throws -> T {
|
||||
do {
|
||||
return try await _request(targetType, resultType: resultType)
|
||||
} catch {
|
||||
if (error as NSError).code == 80403 {
|
||||
// token 失效处理
|
||||
let stoken = AppState.shared.getLocalSToken() // 取本地 stoken
|
||||
if isNotEmpty(stoken) {
|
||||
let token = try? await stokenLogin(stoken: stoken!).token // 用 stoken 登录换 token
|
||||
if isNotEmpty(token) {
|
||||
AppState.shared.token = token! // 更新 token
|
||||
do {
|
||||
return try await _request(targetType, resultType: resultType) // 用新 token 再次请求原接口
|
||||
} catch {
|
||||
throw error // 再次请求报错
|
||||
}
|
||||
}
|
||||
AppState.shared.deleteLocalSToken() // 到这来说明 stoken 已经失效, 删掉 stoken
|
||||
}
|
||||
// 退出登录
|
||||
AppState.shared.token = "" // 到这来 说明 stoken 不存在 或 已经失效, 清空 token 使其切换到登录界面
|
||||
}
|
||||
throw error // 抛出原请求的 error (stoken流程失败, 或者不是token失效的错误, 会到这儿来)
|
||||
}
|
||||
}
|
||||
|
||||
static func _request<T: Codable>(_ targetType: PushDeerApi, resultType: T.Type) async throws -> T {
|
||||
return try await withCheckedThrowingContinuation { continuation in
|
||||
provider.request(targetType) { result in
|
||||
switch result {
|
||||
@ -31,7 +81,6 @@ struct HttpRequest {
|
||||
if let content = result.content, result.code == 0 {
|
||||
continuation.resume(returning: content)
|
||||
} else if result.code == 80403 {
|
||||
AppState.shared.token = ""
|
||||
continuation.resume(throwing: NSError(domain: result.error ?? NSLocalizedString("登录过期", comment: "token失效时提示"), code: result.code, userInfo: [NSLocalizedDescriptionKey: result.error ?? NSLocalizedString("登录过期", comment: "token失效时提示")]))
|
||||
} else {
|
||||
continuation.resume(throwing: NSError(domain: result.error ?? NSLocalizedString("接口报错", comment: "接口报错时提示"), code: result.code, userInfo: [NSLocalizedDescriptionKey: result.error ?? NSLocalizedString("接口报错", comment: "接口报错时提示")]))
|
||||
@ -139,4 +188,17 @@ struct HttpRequest {
|
||||
static func rmAllMessage() async throws -> ActionContent {
|
||||
return try await request(.rmAllMessage(token: AppState.shared.token), resultType: ActionContent.self)
|
||||
}
|
||||
|
||||
|
||||
static func stokenLogin(stoken: String) async throws -> TokenContent {
|
||||
return try await request(.stokenLogin(stoken: stoken), resultType: TokenContent.self)
|
||||
}
|
||||
|
||||
static func stokenRegen() async throws -> STokenContent {
|
||||
return try await request(.stokenRegen(token: AppState.shared.token), resultType: STokenContent.self)
|
||||
}
|
||||
|
||||
static func stokenRemove() async throws -> STokenContent {
|
||||
return try await request(.stokenRemove(token: AppState.shared.token), resultType: STokenContent.self)
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,9 @@ enum PushDeerApi {
|
||||
case rmMessage(token: String, id: Int)
|
||||
case rmAllMessage(token: String)
|
||||
|
||||
case stokenLogin(stoken: String)
|
||||
case stokenRegen(token: String)
|
||||
case stokenRemove(token: String)
|
||||
}
|
||||
|
||||
extension PushDeerApi: TargetType {
|
||||
@ -94,6 +97,13 @@ extension PushDeerApi: TargetType {
|
||||
return "/message/remove"
|
||||
case .rmAllMessage:
|
||||
return "/message/clean"
|
||||
|
||||
case .stokenLogin:
|
||||
return "/login/simple_token"
|
||||
case .stokenRegen:
|
||||
return "/simple_token/regen"
|
||||
case .stokenRemove:
|
||||
return "/simple_token/remove"
|
||||
}
|
||||
}
|
||||
var method: Moya.Method {
|
||||
@ -145,6 +155,12 @@ extension PushDeerApi: TargetType {
|
||||
case let .rmAllMessage(token):
|
||||
return .requestParameters(parameters: ["token": token],encoding: URLEncoding.queryString)
|
||||
|
||||
case let .stokenLogin(stoken):
|
||||
return .requestParameters(parameters: ["stoken": stoken],encoding: URLEncoding.queryString)
|
||||
case let .stokenRegen(token):
|
||||
return .requestParameters(parameters: ["token": token],encoding: URLEncoding.queryString)
|
||||
case let .stokenRemove(token):
|
||||
return .requestParameters(parameters: ["token": token],encoding: URLEncoding.queryString)
|
||||
}
|
||||
}
|
||||
var headers: [String: String]? {
|
||||
|
@ -30,6 +30,9 @@ class WXDelegate: NSObject, WXApiDelegate {
|
||||
if state == "login" {
|
||||
AppState.shared.token = try await HttpRequest.wechatLogin(code: code).token
|
||||
// 给 AppState 的 token 赋值后, SwiftUI 写的 ContentView 页面会监听到并自动进入主页
|
||||
// 登录成功后的处理
|
||||
AppState.shared.loginAfter()
|
||||
|
||||
} else if state == "bind" {
|
||||
_ = try await HttpRequest.mergeUser(type: "wechat", tokenorcode: code)
|
||||
// 合并成功, 更新数据
|
||||
|
26
ios/PushDeer-iOS/PushDeer/Tool/CommonUtils.swift
Normal file
26
ios/PushDeer-iOS/PushDeer/Tool/CommonUtils.swift
Normal file
@ -0,0 +1,26 @@
|
||||
//
|
||||
// CommonUtils.swift
|
||||
// PushDeer
|
||||
//
|
||||
// Created by HEXT on 2022/9/11.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// 判断一个集合 **为空**
|
||||
/// - Parameter emptiable: 一个可能为空的集合, 需要实现了 Collection 协议, 如: String / Array / Dictionary / Set / Data 等
|
||||
/// - Returns: nil 或 空 为 true
|
||||
func isEmpty<T: Collection>(_ emptiable: T?) -> Bool {
|
||||
if emptiable == nil || emptiable!.isEmpty {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/// 判断一个集合 **不为空**
|
||||
/// - Parameter emptiable: 一个可能为空的集合, 需要实现了 Collection 协议, 如: String / Array / Dictionary / Set / Data 等
|
||||
/// - Returns: nil 或 空 为 false
|
||||
func isNotEmpty<T: Collection>(_ emptiable: T?) -> Bool {
|
||||
return !isEmpty(emptiable)
|
||||
}
|
@ -41,6 +41,8 @@ struct LoginView: View {
|
||||
showLoading = true
|
||||
store.token = try await store.appleIdLogin(result).token
|
||||
// 获取成功去主页
|
||||
// 登录成功后的处理
|
||||
store.loginAfter()
|
||||
} catch {
|
||||
showLoading = false
|
||||
if (error as NSError).code == 1001 {
|
||||
|
@ -21,6 +21,7 @@ struct SettingsView: View {
|
||||
VStack {
|
||||
SettingsItemView(title: NSLocalizedString("登录为", comment: "") + " " + userName(), button: NSLocalizedString("退出", comment: "退出登录按钮上的文字")) {
|
||||
store.token = ""
|
||||
store.deleteLocalSToken()
|
||||
HToast.showText(NSLocalizedString("退出", comment: "退出登录按钮上的文字"))
|
||||
}
|
||||
.padding(EdgeInsets(top: 18, leading: 20, bottom: 0, trailing: 20))
|
||||
@ -37,6 +38,7 @@ struct SettingsView: View {
|
||||
SettingsItemView(title: NSLocalizedString("API endpoint", comment: ""), button: NSLocalizedString("重置", comment: "")) {
|
||||
store.api_endpoint = ""
|
||||
store.token = ""
|
||||
store.deleteLocalSToken()
|
||||
}
|
||||
.padding(EdgeInsets(top: 18, leading: 20, bottom: 0, trailing: 20))
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user