[] 토큰 관련해서 테스트 및 기능 추가 중

This commit is contained in:
김선규 2025-03-17 17:59:15 +09:00
parent 195298dea1
commit fea29d0cb8
7 changed files with 138 additions and 78 deletions

View File

@ -328,7 +328,7 @@
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO; SUPPORTS_MACCATALYST = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited) DEV"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited) DEV LOCAL";
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1; TARGETED_DEVICE_FAMILY = 1;

View File

@ -99,7 +99,7 @@ struct IntroView: View {
private func loadVersion() -> Future<VersionData, Error> { private func loadVersion() -> Future<VersionData, Error> {
return Future { promise in return Future { promise in
loadAPIData(url: "\(API_URL)", APIManager.shared.loadAPIData(url: "\(API_URL)",
path: "/api/v1/in/app/version", path: "/api/v1/in/app/version",
parameters: ["type":"I"], parameters: ["type":"I"],
decodingType: APIResponse<VersionData>.self) decodingType: APIResponse<VersionData>.self)

View File

@ -35,8 +35,10 @@ struct LoginView: View {
Button { Button {
// MARK: - TODO, // MARK: - TODO,
// appVM.naviState.set(act: .ADD, path: .SelectAcademy(bids: ["AA0000", "AA0001"])) // appVM.naviState.set(act: .ADD, path: .SelectAcademy(bids: ["AA0000", "AA0001"]))
loginVM.toggleLoading = true // loginVM.toggleLoading = true
// loginVM.loginTest(type: .Kakao, id: "TestSNSID1@#") // loginVM.loginTest(type: .Kakao, id: "TestSNSID1@#")
loginVM.USERPAITEST()
} label: { } label: {
makeButton(image: Image(.Logo.appleIcon), color: Color(.Text.black), "애플 계정으로 시작하기") makeButton(image: Image(.Logo.appleIcon), color: Color(.Text.black), "애플 계정으로 시작하기")

View File

@ -17,16 +17,57 @@ class LoginViewModel: ObservableObject {
var bidArray: [String] = [] var bidArray: [String] = []
func USERPAITEST() {
@UserDefault(key: "refresh", defaultValue: "refreshToken") var refresh
var acc = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJBTVRlc3RFbWFpbDIwMjUwMzE3IiwianRpIjoiYTQzN2Q4YjUtNzQyMi00NWVhLWFiNTktZWI2MTBkNDMwNWRlIiwiZXhwIjoxNzQyMjAwODQ3LCJpc3MiOiJBY2FNYXRlIiwiYXVkIjoiaHR0cHM6L2RldmFjYW1hdGUuaXBzdGVpbi5teWRzLm1lIn0.Y-xxdQWyu3BX_y5hlwWjAdxG5-QRZyHEgJ6T2pDkFRc"
refresh = "tsLeVEtZTjy8iWDvT9vf7Kv7qQr3WgPjeNkFdMb9Rv4="
APIManager.shared.loadAPIData(url: "\(API_URL)",
path: "/api/v1/in/user/cancel",
parameters: ["token": acc],
decodingType: APIResponse<String>.self)
.flatMap { response -> AnyPublisher<APIResponse<String>, Error> in
switch response.status.code {
case .inputErr(let code) where code == "101":
return APIManager.shared.reloadAccessToken()
.flatMap { newAcc -> AnyPublisher<APIResponse<String>, Error> in
APIManager.shared.loadAPIData(url: "\(API_URL)",
path: "/api/v1/in/user/cancel",
parameters: ["token": (newAcc as! Access).access],
decodingType: APIResponse<String>.self)
.eraseToAnyPublisher()
}
.eraseToAnyPublisher()
default:
return Just(response)
.setFailureType(to: Error.self)
.eraseToAnyPublisher()
}
}
.sink { completion in
switch completion {
case .failure(let error):
printLog("최종 \(error)")
case .finished:
break
}
} receiveValue: { response in
printLog("최종: \(response)")
}
.store(in: &cancellables)
}
func loginAction(type: SNSLoginType) { func loginAction(type: SNSLoginType) {
LoginController().login(type) LoginController().login(type)
.flatMap{ snsId in .flatMap{ snsId in
loadAPIData(url: "\(API_URL)", APIManager.shared.loadAPIData(url: "\(API_URL)",
path: "/api/v1/in/user/login", path: "/api/v1/in/user/login",
parameters: [ parameters: [
"acctype": "\(type == .Apple ? "ST00": "ST01")", "acctype": "\(type == .Apple ? "ST00": "ST01")",
"sns_id": "\(snsId.snsId)" "sns_id": "\(snsId.snsId)"
], ],
decodingType: APIResponse<User_Token>.self) decodingType: APIResponse<User_Token>.self)
.map { response in .map { response in
return (snsId: snsId.snsId, response: response) return (snsId: snsId.snsId, response: response)
} }
@ -42,17 +83,17 @@ class LoginViewModel: ObservableObject {
} }
} receiveValue: { [weak self] response in } receiveValue: { [weak self] response in
guard let self = self else { return } guard let self = self else { return }
guard let userToken = response.response as? APIResponse<User_Token> else {return} // let userToken = response.response // as? APIResponse<User_Token> else {return}
var snsId = response.snsId let snsId = response.snsId
switch userToken.status.code { switch response.response.status.code {
case .success(let code): case .success(let code):
if code == "000" { if code == "000" {
@UserDefault(key: "token", defaultValue: "accToken") var accToken @UserDefault(key: "token", defaultValue: "accToken") var accToken
@UserDefault(key: "refresh", defaultValue: "refreshToken") var refreshToken @UserDefault(key: "refresh", defaultValue: "refreshToken") var refreshToken
if let token = userToken.data.toStringDict()["token"], if let token = response.response.data.toStringDict()["token"],
let refresh = userToken.data.toStringDict()["refresh"] { let refresh = response.response.data.toStringDict()["refresh"] {
printLog(token) printLog(token)
printLog(refresh) printLog(refresh)
accToken = token accToken = token
@ -69,7 +110,7 @@ class LoginViewModel: ObservableObject {
// MARK: TO-DO // MARK: TO-DO
// //
printLog("\(apiCode) : 로그인 정보 없음") printLog("\(apiCode) : 로그인 정보 없음")
// self.pathName = .Register(type, id: "\(id)") // self.pathName = .Register(type, id: "\(id)")
default: default:
// //
printLog("ERROR") printLog("ERROR")

View File

@ -18,7 +18,7 @@ class SelectAcademyViewModel: ObservableObject {
func loadAcademy() { func loadAcademy() {
@UserDefault(key: "token", defaultValue: "accToken") var token @UserDefault(key: "token", defaultValue: "accToken") var token
@UserDefault(key: "refresh", defaultValue: "refreshToken") var refresh @UserDefault(key: "refresh", defaultValue: "refreshToken") var refresh
loadAPIData(url: "\(API_URL)", APIManager.shared.loadAPIData(url: "\(API_URL)",
path: "/api/v1/in/user/academy", path: "/api/v1/in/user/academy",
method: .get, method: .get,
parameters: ["token": token, "refresh": refresh], parameters: ["token": token, "refresh": refresh],

View File

@ -10,75 +10,92 @@ import Foundation
import Combine import Combine
import Alamofire import Alamofire
public class APIManager {
private var cancellables = Set<AnyCancellable>()
public static let shared = APIManager()
public func loadAPIData<T: Decodable>(url: String, path: String, private init(cancellables: Set<AnyCancellable> = Set<AnyCancellable>()) {
method: HTTPMethod = .get, self.cancellables = cancellables
parameters: [String: Any],
headers: HTTPHeaders = [:],//["Accept": "application/json"],
decodingType: T.Type) -> Future<Any, Error> {
let encoding: ParameterEncoding = (method == .get) ? URLEncoding.default : JSONEncoding.default
return Future { promise in
printLog(parameters)
AF.request("\(url)\(path)",
method: method,
parameters: parameters,
encoding: encoding,
headers: headers
)
.validate(statusCode: 200 ..< 300)
.responseString { response in
printLog(response)
}
.responseDecodable(of: decodingType) { response in
switch response.result {
case .success(let value):
promise(.success(value))
case .failure(let error):
promise(.failure(error))
}
}
} }
}
public func reloadAccessToken() -> Future<Any, Error> { public func loadAPIData<T: Decodable>(url: String, path: String,
@UserDefault(key: "refresh", defaultValue: "refreshToken") var refresh method: HTTPMethod = .get,
return Future { promise in parameters: [String: Any],
_ = loadAPIData(url: "\(API_URL)", headers: HTTPHeaders = [:],//["Accept": "application/json"],
path: "/api/v1/in/app/retryAccess", decodingType: T.Type) -> Future<T, Error> {
parameters: ["refresh": refresh], let encoding: ParameterEncoding = (method == .get) ? URLEncoding.default : JSONEncoding.default
decodingType: APIResponse<Access>.self) return Future { promise in
.sink { completion in printLog(parameters)
switch completion { AF.request("\(url)\(path)",
case .failure(let error): method: method,
promise(.failure(error)) parameters: parameters,
printLog("\(error)") encoding: encoding,
case .finished: headers: headers
printLog("엑세스 토큰 재발급 완료") )
break .validate(statusCode: 200 ..< 300)
} // .responseString { response in
} receiveValue: { response in // printLog(response)
guard let accToken = response as? APIResponse<Access> else { // }
promise(.failure(ACA_ERROR("Unknown ERROR"))) .responseDecodable(of: decodingType) { response in
return
} switch response.result {
case .success(let value):
printLog("Good: \(value)")
promise(.success(value))
case .failure(let error):
printLog("Bad: \(error))")
promise(.failure(error))
switch accToken.status.code {
case .success(let code):
if code == "000" {
if let tknData = accToken.data { promise(.success(tknData)) }
} }
case .inputErr(let code):
//
promise(.failure(ACA_ERROR("Refresh token ERROR(\(code), \(accToken.status.message)")))
default:
//
promise(.failure(ACA_ERROR("Unknown ERROR")))
} }
} }
} }
public func reloadAccessToken() -> Future<Any, Error> {
@UserDefault(key: "refresh", defaultValue: "refreshToken") var refresh
return Future { [weak self] promise in
guard let self = self else {return}
APIManager.shared.loadAPIData(url: "\(API_URL)",
path: "/api/v1/in/app/retryAccess",
parameters: ["refresh": refresh],
decodingType: APIResponse<Access>.self)
.sink { completion in
switch completion {
case .failure(let error):
promise(.failure(error))
printLog("\(error)")
case .finished:
printLog("엑세스 토큰 재발급 완료")
break
}
} receiveValue: { response in
guard let accToken = response as? APIResponse<Access> else {
promise(.failure(ACA_ERROR("Unknown ERROR")))
return
}
switch accToken.status.code {
case .success(let code):
if code == "000" {
if let tknData = accToken.data { promise(.success(tknData)) }
}
case .inputErr(let code):
//
promise(.failure(ACA_ERROR("Refresh token ERROR(\(code), \(accToken.status.message)")))
default:
//
promise(.failure(ACA_ERROR("Unknown ERROR")))
}
}
.store(in: &self.cancellables)
}
}
} }