forked from AcaMate/AcaMate_iOS
189 lines
6.7 KiB
Swift
189 lines
6.7 KiB
Swift
//
|
|
// LoginController.swift
|
|
// AcaMate
|
|
//
|
|
// Created by Sean Kim on 11/26/24.
|
|
//
|
|
|
|
import Combine
|
|
|
|
import KakaoSDKCommon
|
|
import KakaoSDKAuth
|
|
import KakaoSDKUser
|
|
|
|
import Foundation
|
|
|
|
class LoginController {
|
|
private var cancellables = Set<AnyCancellable>()
|
|
|
|
func login(_ type: SNSLoginType) -> AnyPublisher<SNSID,Error> {
|
|
switch type {
|
|
case .Kakao:
|
|
return self.checkKakaoToken()
|
|
.handleEvents(receiveCompletion: { completion in
|
|
switch completion {
|
|
case .failure(let error) :
|
|
printLog("KAKAO LOGIN ERROR: \(error)")
|
|
case .finished: break
|
|
}
|
|
})
|
|
.eraseToAnyPublisher()
|
|
|
|
case .Apple:
|
|
return Fail(error: NSError(domain: "Apple login not implemented", code: 1, userInfo: nil))
|
|
.eraseToAnyPublisher()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func logout(type: SNSLoginType) {
|
|
switch type {
|
|
case .Kakao:
|
|
UserApi.shared.logout { error in
|
|
if let error = error {
|
|
printLog(error)
|
|
}
|
|
else {
|
|
printLog("LOGOUT SUCCESS")
|
|
}
|
|
}
|
|
case .Apple: break
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//MARK: - KAKAO LOGIN
|
|
extension LoginController {
|
|
/// 토큰을 가지고 있나 확인
|
|
private func checkKakaoToken() -> Future<SNSID, Error> {
|
|
return Future { promise in
|
|
// 토큰 확인
|
|
if AuthApi.hasToken() {
|
|
printLog("토큰 있음")
|
|
self.analysisKakaoToken()
|
|
.flatMap{ token in
|
|
self.generateSNSID(token)
|
|
}
|
|
.sink { completion in
|
|
switch completion {
|
|
case .failure(let error):
|
|
promise(.failure(error))
|
|
case .finished: break
|
|
}
|
|
} receiveValue: { data in
|
|
promise(.success(data))
|
|
}
|
|
.store(in: &self.cancellables)
|
|
}
|
|
else {
|
|
// 처음 설치하거나 하면 여기로 들어오게 됨 -> 당연히 없으니까 바로
|
|
printLog("토큰 없음")
|
|
self.loginKakao()
|
|
.flatMap { token in
|
|
self.generateSNSID(token)
|
|
}
|
|
.sink { completion in
|
|
switch completion {
|
|
case .failure(let error):
|
|
promise(.failure(error))
|
|
case .finished: break
|
|
}
|
|
} receiveValue: { data in
|
|
promise(.success(data))
|
|
}
|
|
.store(in: &self.cancellables)
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
private func generateSNSID(_ token: String) -> Future<SNSID, Error> {
|
|
return Future { promise in
|
|
var snsId = SNSID()
|
|
UserApi.shared.me { user, error in
|
|
if let error = error {
|
|
promise(.failure(error))
|
|
}
|
|
else if let user = user, let id = user.id{
|
|
snsId.acctType = "kakao"
|
|
snsId.snsId = "\(id)"
|
|
snsId.snsToken = "\(token)"
|
|
if let email = user.kakaoAccount?.email {
|
|
snsId.snsEmail = email
|
|
}
|
|
promise(.success(snsId))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// access 토큰의 유효성을 검증
|
|
private func analysisKakaoToken() -> Future<String, Error> {
|
|
return Future { promise in
|
|
UserApi.shared.accessTokenInfo { tokenInfo, error in
|
|
if let error = error {
|
|
printLog("토큰 유효성 체크 실패 - 로그인 동작 필요")
|
|
if let sdkError = error as? SdkError, sdkError.isInvalidTokenError() == true {
|
|
// 로그인이 필요
|
|
self.loginKakao()
|
|
// 로그인 후 동작이 sink에서 처리 될것
|
|
.sink { completion in
|
|
switch completion {
|
|
case .failure(let error):
|
|
promise(.failure(error))
|
|
case .finished: break
|
|
// 로그 인 후 추가 동작 할 거 있나? 일단 토큰 받아서 만들어 보내는건 Value에서 함
|
|
}
|
|
} receiveValue: { token in
|
|
printLog("로그인 완료 - 토큰 받아옴 : \(token)")
|
|
promise(.success(token))
|
|
}
|
|
.store(in: &self.cancellables)
|
|
}
|
|
else {
|
|
// 그 외 기타 에러
|
|
promise(.failure(error))
|
|
}
|
|
}
|
|
else {
|
|
printLog("토큰 유효성 체크 성공")
|
|
// 토큰 유효성이 체크 성공, 로그인 불필요 - 해당 토큰으로 카카오 API 호출 가능
|
|
if let tokenInfo = tokenInfo,
|
|
let token = Auth.shared.tokenManager.getToken()?.accessToken {
|
|
promise(.success(token))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private func loginKakao() -> Future<String, Error> {
|
|
return Future { promise in
|
|
if (UserApi.isKakaoTalkLoginAvailable()) { // 카카오톡 앱 실행 가능
|
|
UserApi.shared.loginWithKakaoTalk { oauthToken, error in
|
|
if let error = error { // 로그인과정에서 오류 발생
|
|
promise(.failure(error))
|
|
}
|
|
else if let oauthToken = oauthToken { // 정상 로그인 완료
|
|
promise(.success(oauthToken.accessToken))
|
|
}
|
|
}
|
|
}
|
|
else { // 카카오톡 앱 실행 불가
|
|
UserApi.shared.loginWithKakaoAccount { oauthToken, error in
|
|
if let error = error { // 로그인과정에서 오류 발생
|
|
promise(.failure(error))
|
|
}
|
|
else if let oauthToken = oauthToken { // 정상 로그인 완료
|
|
promise(.success(oauthToken.accessToken))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|