Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FIX] #246 - 자동 로그인 버그 해결 #251

Merged
merged 8 commits into from
Dec 29, 2021
2 changes: 1 addition & 1 deletion NADA-iOS-forRelease/Resouces/Constants/Const.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
import Foundation

struct Const {

static let headerToken: String = UserDefaults.standard.string(forKey: Const.UserDefaultsKey.accessToken) ?? ""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

선배 덕에 도약이야. 크

}
3 changes: 2 additions & 1 deletion NADA-iOS-forRelease/Resouces/Constants/Header.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@
import Foundation

extension Const {

struct Header {
static var bearerHeader = ["Authorization": "Bearer " + UserDefaults.standard.string(forKey: Const.UserDefaultsKey.accessToken)!]

static var basicHeader = ["Content-Type": "application/json",
"Authorization": "Bearer " + UserDefaults.standard.string(forKey: Const.UserDefaultsKey.accessToken)!]
"Authorization": "Bearer " + headerToken]
Comment on lines 13 to +16
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요부분도 동일하게 적용해주어야할거 같아요!
어차피 로그인에서는 basicHeader 만 쓰겠지만 같은 값을 다르게 표시한 부분을 피할 수 있을거 같아요!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요부분이라면 bearerHeder 말씀하시는건가요 선배??

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵!

}
}
2 changes: 2 additions & 0 deletions NADA-iOS-forRelease/Resouces/Constants/UserDefaults.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,7 @@ extension Const {
static let isFirstCard = "isFirstCard"
static let isOnboarding = "isOnboarding"
static let firstCardID = "firstCardID"
static let isAppleLogin = "isAppleLogin"
static let isKakaoLogin = "isKakaoLogin"
Comment on lines +19 to +20
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋았다 선배야

}
}
76 changes: 50 additions & 26 deletions NADA-iOS-forRelease/Sources/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,39 +7,66 @@

import UIKit
import KakaoSDKCommon
import KakaoSDKAuth
import KakaoSDKUser
import AuthenticationServices

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

// var isLogin = false
var isLogin = false

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
// removeKeychainAtFirstLaunch()

KakaoSDKCommon.initSDK(appKey: "5b8dd8cc878344bb7532eeca4365a4aa")
let acToken = UserDefaults.standard.string(forKey: Const.UserDefaultsKey.accessToken)

// let appleIDProvider = ASAuthorizationAppleIDProvider()
// appleIDProvider.getCredentialState(forUserID: Const.UserDefaults.userID) { (credentialState, error) in
// switch credentialState {
// case .authorized:
// print("해당 ID는 연동되어있습니다.")
// self.isLogin = true
// case .revoked:
// print("해당 ID는 연동되어있지않습니다.")
// self.isLogin = false
// case .notFound:
// print("해당 ID를 찾을 수 없습니다.")
// self.isLogin = false
// default:
// break
// }
// }

// NotificationCenter.default.addObserver(forName: ASAuthorizationAppleIDProvider.credentialRevokedNotification, object: nil, queue: nil) { (Notification) in
// print("Revoked Notification")
// self.isLogin = false
// }
if acToken != nil {
if UserDefaults.standard.bool(forKey: Const.UserDefaultsKey.isAppleLogin) {
// 애플 로그인으로 연동되어 있을 때, -> 애플 ID와의 연동상태 확인 로직
let appleIDProvider = ASAuthorizationAppleIDProvider()
appleIDProvider.getCredentialState(forUserID: UserDefaults.standard.string(forKey: Const.UserDefaultsKey.userID) ?? "") { (credentialState, error) in
switch credentialState {
case .authorized:
print("해당 ID는 연동되어있습니다.")
self.isLogin = true
case .revoked:
print("해당 ID는 연동되어있지않습니다.")
self.isLogin = false
case .notFound:
print("해당 ID를 찾을 수 없습니다.")
self.isLogin = false
default:
break
}
}
} else {
if AuthApi.hasToken() { // 유효한 토큰 존재
UserApi.shared.accessTokenInfo { (_, error) in
if let error = error {
if let sdkError = error as? SdkError, sdkError.isInvalidTokenError() == true {
self.isLogin = false
}
} else {
// 토큰 유효성 체크 성공(필요 시 토큰 갱신됨)
self.isLogin = true
}
}
} else {
// 카카오 토큰 없음 -> 로그인 필요
self.isLogin = false
}
}
} else {
self.isLogin = false // acToken 값이 nil일 때 -> 로그인 뷰로
}

// 앱 실행 중 애플 ID 강제로 연결 취소 시
NotificationCenter.default.addObserver(forName: ASAuthorizationAppleIDProvider.credentialRevokedNotification, object: nil, queue: nil) { (Notification) in
print("Revoked Notification")
self.isLogin = false
}
Comment on lines +65 to +69
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

애플은 이렇게 하면되는데 카카오는 앱에서 연결끊기가 가능하지 카카오에서 연결을 끊으면 알아볼 방법이 없어보여요,,, 일단 전자의 경우 출처임당..

https://developers.kakao.com/docs/latest/ko/kakaologin/ios#unlink

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

맞습니다....

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

허허.. 뭔가 근데 애플은 앱에서 연결을 끊는게 없고 애플에서 끊으면 확인하는게 있고 / 카카오는 앱에서 연결을 끊는게 있고 카카오에서 끊은걸 확인하는게 없고 난리부르스네 일단 요거 생각안하구 되는데로 해두고 얘기해보자구요


return true
}
Expand All @@ -57,7 +84,4 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}


}

Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ extension GroupService: TargetType {
return Const.Header.bearerHeader
case .groupAdd, .groupEdit, .cardAddInGroup, .changeCardGroup:
return Const.Header.bearerHeader
case .groupReset(let token):
return ["Content-Type": "application/json", "Authorization": "Bearer " + token]
case .groupReset:
return Const.Header.basicHeader
Comment on lines +99 to +100
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,8 @@ extension UserSevice: TargetType {
return Const.Header.bearerHeader
case .userSignUp, .userSocialSignUp, .userTokenReissue:
return ["Content-Type": "application/json"]
case .userDelete(let token):
return ["Content-Type": "application/json", "Authorization": "Bearer " + token]
case .userLogout(let token):
return ["Content-Type": "application/json", "Authorization": "Bearer " + token]
case .userDelete, .userLogout:
return Const.Header.basicHeader
}
}
}
54 changes: 1 addition & 53 deletions NADA-iOS-forRelease/Sources/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
window.overrideUserInterfaceStyle = .light
}
}

// 스플래시 지연시간동안 자동 로그인 작업처리
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) {
let acToken = self.defaults.string(forKey: Const.UserDefaultsKey.accessToken)
let rfToken = self.defaults.string(forKey: Const.UserDefaultsKey.refreshToken)

self.postUserTokenReissue(request: UserTokenReissueRequset(accessToken: acToken ?? "", refreshToken: rfToken ?? ""))
}

}

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
Expand All @@ -54,53 +47,8 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
}
}

// MARK: - Network

func postUserTokenReissue(request: UserTokenReissueRequset) {
UserAPI.shared.userTokenReissue(request: request) { response in
switch response {
case .success:
print("postUserTokenReissue - Success")

var rootViewController = UIStoryboard(name: Const.Storyboard.Name.login, bundle: nil)
.instantiateViewController(identifier: Const.ViewController.Identifier.loginViewController)

if self.defaults.string(forKey: Const.UserDefaultsKey.accessToken) != "" {
rootViewController = UIStoryboard(name: Const.Storyboard.Name.tabBar, bundle: nil).instantiateViewController(withIdentifier: Const.ViewController.Identifier.tabBarViewController)
} else {
rootViewController = UIStoryboard(name: Const.Storyboard.Name.login, bundle: nil)
.instantiateViewController(identifier: Const.ViewController.Identifier.loginViewController)
}
self.window?.rootViewController = rootViewController
self.window?.makeKeyAndVisible()
case .requestErr(let message):
print("postUserTokenReissue - requestErr: \(message)")

self.presentToLoginViewController()
case .pathErr:
print("postUserTokenReissue - pathErr")
case .serverErr:
print("postUserTokenReissue - serverErr")
case .networkFail:
print("postUserTokenReissue - networkFail")
}
}
}

// MARK: - Methods

private func presentToLoginViewController() {
if UserDefaults.standard.object(forKey: Const.UserDefaultsKey.isOnboarding) != nil {
let rootViewController = UIStoryboard(name: Const.Storyboard.Name.login, bundle: nil).instantiateViewController(identifier: Const.ViewController.Identifier.loginViewController)
self.window?.rootViewController = rootViewController
self.window?.makeKeyAndVisible()
} else {
let rootViewController = UIStoryboard(name: Const.Storyboard.Name.onboarding, bundle: nil).instantiateViewController(identifier: Const.ViewController.Identifier.onboardingViewController)
self.window?.rootViewController = rootViewController
self.window?.makeKeyAndVisible()
}
}

func sceneDidDisconnect(_ scene: UIScene) {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ class LoginViewController: UIViewController {
])

let authorizationButton = ASAuthorizationAppleIDButton(type: .signIn, style: .black)
// let authorizationButton = UIButton()
// authorizationButton.setImage(UIImage(named: "appleLogin"), for: .normal)
authorizationButton.addTarget(self, action: #selector(appleSignInButtonPress), for: .touchUpInside)
loginProviderStackView.addSubview(authorizationButton)

Expand Down Expand Up @@ -76,24 +74,16 @@ class LoginViewController: UIViewController {
// 카카오 로그인 버튼 클릭 시
@objc
func kakaoSignInButtonPress() {
if AuthApi.hasToken() { // 유효한 토큰 존재
UserApi.shared.accessTokenInfo { (_, error) in
if let error = error {
if let sdkError = error as? SdkError, sdkError.isInvalidTokenError() == true {
// 로그인 필요
self.signUp()
}
} else {
// 토큰 유효성 체크 성공(필요 시 토큰 갱신됨)
self.signUp()
}
}
// 카카오톡 설치 여부 확인
if UserApi.isKakaoTalkLoginAvailable() {
// 카카오톡 로그인. api 호출 결과를 클로저로 전달.
loginWithApp()
} else {
// 카카오 토큰 없음 -> 로그인 필요
self.signUp()
Comment on lines -79 to -93
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아.. 원래 로직은 버튼 클릭해서 토큰 확인했었군여? 굳굳 깔끔해졌어여

// 만약, 카카오톡이 깔려있지 않을 경우에는 웹 브라우저로 카카오 로그인함.
loginWithWeb()
}
}

// 애플 로그인 버튼 클릭 시
@objc
func appleSignInButtonPress() {
Expand Down Expand Up @@ -124,6 +114,8 @@ extension LoginViewController {
} else {
if let email = user?.kakaoAccount?.email {
self.postUserSignUpWithAPI(request: email)
UserDefaults.standard.set(false, forKey: Const.UserDefaultsKey.isAppleLogin)
UserDefaults.standard.set(true, forKey: Const.UserDefaultsKey.isKakaoLogin)
}
}
}
Expand All @@ -145,6 +137,8 @@ extension LoginViewController {
} else {
if let email = user?.kakaoAccount?.email {
self.postUserSignUpWithAPI(request: email)
UserDefaults.standard.set(false, forKey: Const.UserDefaultsKey.isAppleLogin)
UserDefaults.standard.set(true, forKey: Const.UserDefaultsKey.isKakaoLogin)
}
}
}
Expand Down Expand Up @@ -174,17 +168,13 @@ extension LoginViewController: ASAuthorizationControllerDelegate, ASAuthorizatio
// Apple ID 연동 성공 시
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
switch authorization.credential {
// Apple ID
// Apple ID
case let appleIDCredential as ASAuthorizationAppleIDCredential:

let userIdentifier = appleIDCredential.user
// let fullName = appleIDCredential.fullName
// let email = appleIDCredential.email

// print("User ID : \(userIdentifier)")
// print("User Email : \(email ?? "")")
// print("User Name : \((fullName?.givenName ?? "") + (fullName?.familyName ?? ""))")
postUserSignUpWithAPI(request: userIdentifier)
UserDefaults.standard.set(true, forKey: Const.UserDefaultsKey.isAppleLogin)
UserDefaults.standard.set(false, forKey: Const.UserDefaultsKey.isKakaoLogin)

default:
break
Expand All @@ -206,10 +196,8 @@ extension LoginViewController {
print("postUserSignUpWithAPI - success")
if let userData = loginData as? UserWithTokenRequest {
UserDefaults.standard.set(userData.user.userID, forKey: Const.UserDefaultsKey.userID)
let tokenData = userData.user.token
UserDefaults.standard.set(tokenData.accessToken, forKey: Const.UserDefaultsKey.accessToken)
UserDefaults.standard.set(tokenData.refreshToken, forKey: Const.UserDefaultsKey.refreshToken)

UserDefaults.standard.set(userData.user.token.accessToken, forKey: Const.UserDefaultsKey.accessToken)
UserDefaults.standard.set(userData.user.token.refreshToken, forKey: Const.UserDefaultsKey.refreshToken)
self.presentToMain()
}
case .requestErr(let message):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ extension MoreViewController {
if let acToken = UserDefaults.standard.string(forKey: Const.UserDefaultsKey.accessToken) {
self.logoutUserWithAPI(token: acToken)
self.defaults.removeObject(forKey: Const.UserDefaultsKey.accessToken)
self.defaults.removeObject(forKey: Const.UserDefaultsKey.refreshToken)
self.defaults.removeObject(forKey: Const.UserDefaultsKey.darkModeState)
let nextVC = UIStoryboard(name: Const.Storyboard.Name.login, bundle: nil).instantiateViewController(withIdentifier: Const.ViewController.Identifier.loginViewController)
nextVC.modalPresentationStyle = .overFullScreen
Expand Down Expand Up @@ -147,6 +148,7 @@ extension MoreViewController {
if let acToken = UserDefaults.standard.string(forKey: Const.UserDefaultsKey.accessToken) {
self.deleteUserWithAPI(token: acToken)
self.defaults.removeObject(forKey: Const.UserDefaultsKey.accessToken)
self.defaults.removeObject(forKey: Const.UserDefaultsKey.refreshToken)
self.defaults.removeObject(forKey: Const.UserDefaultsKey.darkModeState)
let nextVC = UIStoryboard(name: Const.Storyboard.Name.login, bundle: nil).instantiateViewController(withIdentifier: Const.ViewController.Identifier.loginViewController)
nextVC.modalPresentationStyle = .overFullScreen
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,24 @@ class SplashViewController: UIViewController {

// MARK: - Properties
private weak var appDelegate = UIApplication.shared.delegate as? AppDelegate

// MARK: - @IBOutlet Properties

let defaults = UserDefaults.standard

// MARK: - View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()

}

override func viewWillAppear(_ animated: Bool) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

스플래쉬는 좋겠다... 뷰 윌 어피어도 되고... 시무룩

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ..ㅜ

super.viewWillAppear(animated)

// Do any additional setup after loading the view.
// postUserTokenReissue(request: UserTokenReissueRequset(accessToken: UserDefaults.standard.string(forKey: Const.UserDefaults.accessToken)!, refreshToken: UserDefaults.standard.string(forKey: Const.UserDefaults.refreshToken)!))
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) {
if self.appDelegate?.isLogin == true {
self.presentToMain()
} else {
self.presentToLogin()
Comment on lines +22 to +29
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

쵝오

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

디패큐!!!!

}
}
}

// MARK: - Functions
Expand All @@ -38,25 +47,3 @@ class SplashViewController: UIViewController {
}

}

// MARK: - Networks
extension SplashViewController {

func postUserTokenReissue(request: UserTokenReissueRequset) {
UserAPI.shared.userTokenReissue(request: request) { response in
switch response {
case .success:
print("postUserTokenReissue - Success")
case .requestErr(let message):
print("postUserTokenReissue - requestErr: \(message)")
self.presentToLogin()
case .pathErr:
print("postUserTokenReissue - pathErr")
case .serverErr:
print("postUserTokenReissue - serverErr")
case .networkFail:
print("postUserTokenReissue - networkFail")
}
}
}
}