Open Suyeon9911 opened 2 years ago
카카오와 애플 등의 소셜플랫폼에 이미 가입된 사용자의 계정들이 존재 이 계정들에는 고유한 userID가 있는데 소셜 api와의 연동을 통해서 이 userID를 받아오는 것이다. -> 이렇게 받아온 userID로 앱의 회원을 판별하는 고유한 값으로 사용 !
소셜에서 받아온 userID를 이용해서 Authentication 시스템을 구축하기 위해서 서버에서 제공해야할 API는 2가지 !
class SplashViewController: UIViewController {
private weak var appDelegate = UIApplication.shared.delegate as? Appdelegate
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
if self.appDelegate?.isLogin {
self.presentToMain()
} else {
self.presentToLogin
}
}
}
}
스플래시에서 자동로그인을 판별해서 로그인 된 상태이면 메인으로 안되어있으면 로그인 화면으로 간다. -> 앱딜리게이트에서 자동로그인 구현해주자 !!!
AuthenticationServices랑 kakaoSDKUser 모듈을 import 해주고 버튼을 눌렀을 때 로직을 연결시킨다 !
private func signupWithKakao() {
if UserApi.isKakaoTalkLoginAvailable() {
loginWithKakaoApp()
} else {
loginWithWeb()
}
}
private func loginWithKakaoApp() {
UserApi.shared.loginWithKakaoTalk { _, error in
if let error = error {
print(error)
} else {
print("loginWithKakaoApp() success.")
self.getUserID()
}
}
}
private func loginWithWeb() {
UserApi.shared.loginWithKakaoAccount { _, error in
if let error = error {
print(error)
} else {
print("loginWithKakaoAccount() success.")
self.getUserID()
}
}
}
여기서 에러가 없을 경우 getUserID라는 함수를 호출한다 !
private func getUserID() {
UserApi.shared.me {(user, error) in
if let error = error {
print(error)
} else {
if let userID = user?.id {
UserDefaults.standard.set(String(userID), forKey: Const.UserDefaultsKey.userID)
UserDefaults.standard.set(false, forKey: Const.UserDefaultsKey.isAppleLogin)
self.loginWithAPI(userID: String("Kakao@\(userID)"))
}
}
}
}
이 함수는 카카오의 UserAPI에 접근하여 Userid를 불러오고, userdefault에 저장한다. 동시에 애플로그인을 막기 위해 isAppleLogin을 false로 설정 !
이후 loginWithAPI를 호출하는데 여기서 서버통신이 시작되는 것 ! 카카오와 애플의 유저아이디가 중복될 수 있기 때문에 구분하기 위해서 Kakao@(userID) 이렇게 처리해준다.
애플로그인을 찾아봤을때 거의 요런 방식들이 나오는데 해빗의 경우 파이어베이스를 이용하는 것 같다. request로 파베 uid를 보내줘야하는데 요걸 연결하는 방법은 더 찾아봐야할 것 같다
private func signupWithApple() {
let appleIDProvider = ASAuthorizationAppleIDProvider()
let request = appleIDProvider.createRequest()
request.requestedScopes = [.fullName, .email]
let authorizationController = ASAuthorizationController(authorizationRequests: [request])
authorizationController.delegate = self
authorizationController.presentationContextProvider = self
authorizationController.performRequests()
}
일단 바로 애플아이디 로그인을 하려면 IDProvider 객체를 생성하고, request를 만들고, request에서 받을 정보의 범위를 설정해준다. authorizationController 객체를 생성하는데, 위에서 만들어준 request를 주입하여 생성한다 !! 이후 컨트롤러 객체에서 performRequests를 수행하면 애플과의 서버통신을 시작한다
애플로그인은 한가지 더 프로토콜을 채택하여 메서드를 구현해주어야한다.
// MARK: - AppleSignIn
extension LoginVC: ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding {
func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
return self.view.window!
}
// Apple ID 연동 성공 시
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
switch authorization.credential {
case let appleIDCredential as ASAuthorizationAppleIDCredential:
let userIdentifier = appleIDCredential.user
UserDefaults.standard.set(userIdentifier, forKey: Const.UserDefaultsKey.userID)
UserDefaults.standard.set(true, forKey: Const.UserDefaultsKey.isAppleLogin)
loginWithAPI(userID: "Apple@\(userIdentifier)")
default:
break
}
}
// Apple ID 연동 실패 시
func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
// Handle error.
}
}
extension LoginVC {
private func loginWithAPI(userID: String) {
AuthAPI.shared.login(socialID: userID, fcmToken: UserDefaults.standard.string(forKey: Const.UserDefaultsKey.fcmToken) ?? "") { response in
switch response {
case .success(let data):
if let data = data as? Login {
if data.isNew {
// 회원가입을 하지 않은 사용자입니다.
guard let nextVC = UIStoryboard(name: Const.Storyboard.Name.profileSetting, bundle: nil).instantiateViewController(withIdentifier: Const.ViewController.Identifier.profileSetting) as? ProfileSettingVC else { return }
nextVC.modalPresentationStyle = .fullScreen
self.present(nextVC, animated: true, completion: nil)
} else {
// 회원 정보를 불러왔습니다.
UserDefaults.standard.set(data.accesstoken, forKey: Const.UserDefaultsKey.accessToken)
self.presentToMainTBC()
}
}
case .requestErr(let message):
print("loginWithAPI - requestErr: \(message)")
case .pathErr:
print("loginWithAPI - pathErr")
case .serverErr:
print("loginWithAPI - serverErr")
case .networkFail:
print("loginWithAPI - networkFail")
}
}
}
}
이제 프로젝트 서버와의 통신을 하는데 여기서는 파라미터로 유저아이디랑 fcmToken을 보내주고 있다 !
로그인 통신을 하게 되면 기존유저인지 신규유저인지 판별이 가능하다 !
로그인은 이 사람이 기존에 가입한 사람이고, 서버의 DB에 저장된 사람인지를 판별하여 앱의 메인 플로우로 넘어가게 해주는 기능으로, 서버에 존재하는 데이터를 변동시키지 않는다.
반면 회원가입 API는 새로운 userID를 서버의 DB에 저장하는 POST 메서드이다. 이를 통해 다음 로그인 API 호출 시 자동으로 넘어가게 되는 것이다.
회원가입은 로그인 하면서 받아온 유저아이디와 프로필 설정 내용을 바탕으로 post 요청을 한다
성공하면 로그인과 동일하게 token을 보내주고 이를 userDefalut에 저장한다.
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var isLogin = false
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
KakaoSDK.initSDK(appKey: "d51e83bca123750446afc70ab65225b9")
let accessToken = UserDefaults.standard.string(forKey: Const.UserDefaultsKey.accessToken)
if accessToken != nil {
if UserDefaults.standard.bool(forKey: Const.UserDefaultsKey.isAppleLogin) {
// 애플 로그인으로 연동되어 있을 때, -> 애플 ID와의 연동상태 확인 로직
let appleIDProvider = ASAuthorizationAppleIDProvider()
appleIDProvider.getCredentialState(forUserID: UserDefaults.standard.string(forKey: Const.UserDefaultsKey.userID) ?? "") { credentialState, _ 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 {
// access token 이 없는 경우.
self.isLogin = false
}
return true
}
}
isLogin이라는 Bool 값으로 자동로그인 기능을 만들자 ! 카카오 SDK에 대한 설정도 해주고, 유저디폴트의 엑세스 토큰을 받아오는데 엑세스 토큰이 없을 경우 -> 애플로그인이면 애플 ID와의 연동상태를 확인한다
카카오 로그인의 경우에도 유효성 검사를 해준다 유효하다면 앞서 구현해둔 스플래시 화면에서 자동으로 메인으로 넘어간다 !
해빗 프로젝트의 경우 FirebaseAuth 클래스에서 애플로그인을 구현해주는 것 같다...
파베로 보내고... 파베에서.. 난 왤케 감자일까....? 눈무리 난다..
소셜로그인 플로우 정리
로그인 API 명세
=> 일단 서버랑 연결을 시켜놓고 값들을 어떻게 처리를 할지.. 생각을 해보자..
회원가입 API 명세
전체적인 플로우 - 일단 카카오로그인 먼저.. 카카오 로그인 버튼 -> 클라 내에서 카카오SDK 로 카카오로그인을 띄운다 -> 앱이 있으면 카톡으로 없으면 웹으로 연결시킨다 -> 성공 시 카카오에서 발급하는 토큰 저장 -> 저장한 토큰으로 서버에 Post 요청을 한다 -> 기존 유저일 경우 : 로그인이 된다 !
신규 유저일 경우? 카카오에서 발급한 토큰 + 카카오에서 가져온 정보 + 프로필 설정 뷰에서 가져온 정보로 회원가입 POST 연결 ㅋㅋ -> 로그인 된다