Skip to content

Commit

Permalink
Merge pull request #173 from Nexters/feature/#165-애플-로그인-구현
Browse files Browse the repository at this point in the history
Feature/#165 애플 로그인 추가 구현
  • Loading branch information
leemhyungyu authored Aug 21, 2024
2 parents da54a6a + e35f43a commit ab091b1
Show file tree
Hide file tree
Showing 23 changed files with 215 additions and 169 deletions.
17 changes: 0 additions & 17 deletions Projects/App/Sources/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,6 @@ final class AppDelegate: UIResponder, UIApplicationDelegate, MessagingDelegate {
store.send(.appDelegate(.didFinishLunching))
return true
}

func application(
_ application: UIApplication,
configurationForConnecting connectingSceneSession: UISceneSession,
options: UIScene.ConnectionOptions
) -> UISceneConfiguration {
let configuration = UISceneConfiguration(
name: nil,
sessionRole: connectingSceneSession.role
)

if connectingSceneSession.role == .windowApplication {
configuration.delegateClass = SceneDelegate.self
}

return configuration
}
}

extension AppDelegate: UNUserNotificationCenterDelegate {
Expand Down
23 changes: 0 additions & 23 deletions Projects/App/Sources/SceneDelegate.swift

This file was deleted.

7 changes: 7 additions & 0 deletions Projects/Domain/Auth/Interface/Sources/API/AuthAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public enum AuthAPI {
case withdraw
case logout(_ logOutRequestDTO: LogOutRequestDTO)
case revoke
case profile(_ requestDTO: ProfileRequestDTO)
}

extension AuthAPI: BaseTargetType {
Expand All @@ -32,6 +33,8 @@ extension AuthAPI: BaseTargetType {
return "api/v1/auth/logout"
case .revoke:
return "api/v1/auth/apple/revoke"
case .profile:
return "api/v2/auth/profile"
}
}

Expand All @@ -47,6 +50,8 @@ extension AuthAPI: BaseTargetType {
return .post
case .revoke:
return .get
case .profile:
return .post
}
}

Expand All @@ -62,6 +67,8 @@ extension AuthAPI: BaseTargetType {
return .requestJSONEncodable(logOutRequestDTO)
case .revoke:
return .requestPlain
case .profile(let requestDTO):
return .requestJSONEncodable(requestDTO)
}
}
}
21 changes: 14 additions & 7 deletions Projects/Domain/Auth/Interface/Sources/AuthClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,28 @@
import Foundation

public struct AuthClient {
private let signInWithKakao: () async throws -> SignInResponseDTO
private let signInWithApple: () async throws -> SignInResponseDTO
private let signInWithKakao: () async throws -> UserInfo
private let signInWithApple: () async throws -> UserInfo
private let saveToken: (Token) -> Void
private let _checkTokenIsExist: () -> Bool
private let withdraw: () async throws -> Void
private let logout: () async throws -> Void
private let refreshAppleToken: () async throws -> AppleToken
private let _revokeAppleLogin: () async throws -> Void
private let fetchAppleClientSecret: () async throws -> String
private let registerUserProfile: (String) async throws -> Void

public init(
signInWithKakao: @escaping () async throws -> SignInResponseDTO,
signInWithApple: @escaping () async throws -> SignInResponseDTO,
signInWithKakao: @escaping () async throws -> UserInfo,
signInWithApple: @escaping () async throws -> UserInfo,
saveToken: @escaping (Token) -> Void,
checkTokenIsExist: @escaping () -> Bool,
withdraw: @escaping () async throws -> Void,
logout: @escaping () async throws -> Void,
refreshAppleToken: @escaping () async throws -> AppleToken,
revokeAppleLogin: @escaping () async throws -> Void,
fetchAppleClientSecret: @escaping () async throws -> String
fetchAppleClientSecret: @escaping () async throws -> String,
registerUserProfile: @escaping (String) async throws -> Void
) {
self.signInWithKakao = signInWithKakao
self.signInWithApple = signInWithApple
Expand All @@ -38,13 +40,14 @@ public struct AuthClient {
self.refreshAppleToken = refreshAppleToken
self._revokeAppleLogin = revokeAppleLogin
self.fetchAppleClientSecret = fetchAppleClientSecret
self.registerUserProfile = registerUserProfile
}

public func signInWithKakao() async throws -> SignInResponseDTO {
public func signInWithKakao() async throws -> UserInfo {
try await signInWithKakao()
}

public func signInWithApple() async throws -> SignInResponseDTO {
public func signInWithApple() async throws -> UserInfo {
try await signInWithApple()
}
public func saveToken(token: Token) {
Expand Down Expand Up @@ -74,5 +77,9 @@ public struct AuthClient {
public func fetchAppleClientSecret() async throws -> String {
try await fetchAppleClientSecret()
}

public func registerUserProfile(userName: String) async throws {
try await registerUserProfile(userName)
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// ProfileRequestDTO.swift
// DomainAuth
//
// Created by 임현규 on 8/21/24.
//

import Foundation

public struct ProfileRequestDTO: Encodable {
let birthDay: Int?
let birthMonth: Int?
let birthYear: Int?
let gender: String?
let name: String

public init(
birthDay: Int? = nil,
birthMonth: Int? = nil,
birthYear: Int? = nil,
gender: String? = nil,
name: String
) {
self.birthDay = birthDay
self.birthMonth = birthMonth
self.birthYear = birthYear
self.gender = gender
self.name = name
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,18 @@ public struct UserInfo {
public let token: Token
public let isSignUp: Bool
public let isCompletedOnboardingIntroduction: Bool
public var userName: String?

public init(
token: Token,
isSignUp: Bool,
isCompletedOnboardingIntroduction: Bool
isCompletedOnboardingIntroduction: Bool,
userName: String? = nil
) {
self.token = token
self.isSignUp = isSignUp
self.isCompletedOnboardingIntroduction = isCompletedOnboardingIntroduction
self.userName = userName
}
}

Expand Down
18 changes: 18 additions & 0 deletions Projects/Domain/Auth/Interface/Sources/Entity/SignInResult.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// SignInResult.swift
// DomainAuth
//
// Created by 임현규 on 8/21/24.
//

import Foundation

public struct SignInResult {
public let accessToken: String
public let userName: String?

public init(accessToken: String, userName: String? = nil) {
self.accessToken = accessToken
self.userName = userName
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ public struct LoginManager {
case sms
}

private var signIn: (_ loginType: LoginType) async throws -> String
private var signIn: (_ loginType: LoginType) async throws -> SignInResult

public init(signIn: @escaping (_ loginType: LoginType) async throws -> String) {
public init(signIn: @escaping (_ loginType: LoginType) async throws -> SignInResult) {
self.signIn = signIn
}

/// 로그인 타입에 따라 Provider로 부터 받은 AuthToken & AccessToken을 반환합니다.
/// - Parameters:
/// - loginType: 로그인하는 Type
public func signIn(loginType: LoginType) async throws -> String {
public func signIn(loginType: LoginType) async throws -> SignInResult {
try await signIn(loginType)
}
}
19 changes: 15 additions & 4 deletions Projects/Domain/Auth/Sources/AuthClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,35 @@ extension AuthClient: DependencyKey {

return .init(
signInWithKakao: {
let accessToken = try await loginManager.signIn(loginType: .kakao)
let signInResult = try await loginManager.signIn(loginType: .kakao)
let accessToken = signInResult.accessToken
guard let fcmToken = UserDefaults.standard.string(forKey: "fcmToken")
else {
Log.fault("no fcm token")
fatalError()
}
let data = SignInRequestDTO(code: accessToken, fcmDeviceToken: fcmToken)
let responseData = try await networkManager.reqeust(api: .apiType(AuthAPI.kakao(data)), dto: SignInResponseDTO.self)
return responseData
let userInfo = responseData.toDomain()
return userInfo
},

signInWithApple: {
// TODO: apple Login API로 수정
let accessToken = try await loginManager.signIn(loginType: .apple)
let signInResult = try await loginManager.signIn(loginType: .apple)
let accessToken = signInResult.accessToken
let userName = signInResult.userName

guard let fcmToken = UserDefaults.standard.string(forKey: "fcmToken")
else {
Log.fault("no fcm token")
fatalError()
}
let data = SignInRequestDTO(code: accessToken, fcmDeviceToken: fcmToken)
let responseData = try await networkManager.reqeust(api: .apiType(AuthAPI.apple(data)), dto: SignInResponseDTO.self)
return responseData
var userInfo = responseData.toDomain()
userInfo.userName = userName
return userInfo
},
saveToken: { token in
LocalAuthDataSourceImpl.saveToken(token: token)
Expand Down Expand Up @@ -73,6 +80,10 @@ extension AuthClient: DependencyKey {
let responseData = try await networkManager.reqeust(api: .apiType(AuthAPI.revoke), dto: ClientSecretResponseDTO.self)
let clientSecret = responseData.clientSecret
return clientSecret
},
registerUserProfile: { userName in
let requestDTO = ProfileRequestDTO(name: userName)
try await networkManager.reqeust(api: .apiType(AuthAPI.profile(requestDTO)))
}
)
}
Expand Down
17 changes: 12 additions & 5 deletions Projects/Domain/Auth/Sources/LoginManager/AppleLoginManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,16 @@
import Foundation
import AuthenticationServices

import DomainAuthInterface
import CoreKeyChainStore

final class AppleLoginManager: NSObject, ASAuthorizationControllerDelegate {
typealias IdentityCode = String

private var continuation: CheckedContinuation<IdentityCode, Error>?
private var continuation: CheckedContinuation<SignInResult, Error>?

func signInWithApple() async throws -> IdentityCode {
try await withCheckedThrowingContinuation { continuation in
func signInWithApple() async throws -> SignInResult {
try await withCheckedThrowingContinuation { [weak self] continuation in
guard let self = self else { return }
let request = ASAuthorizationAppleIDProvider().createRequest()
request.requestedScopes = [.fullName, .email]
let controller = ASAuthorizationController(authorizationRequests: [request])
Expand Down Expand Up @@ -58,10 +59,16 @@ final class AppleLoginManager: NSObject, ASAuthorizationControllerDelegate {
return
}


let user = credential.user
let fullName = credential.fullName
let name = ((fullName?.familyName ?? "") + (fullName?.givenName ?? ""))

KeyChainTokenStore.shared.save(property: .AppleUserID, value: user)
KeyChainTokenStore.shared.save(property: .AppleAuthCode, value: authorizationCodeString)
continuation?.resume(returning: decodedIdentityToken)

let signInResult = SignInResult(accessToken: decodedIdentityToken, userName: name == "" ? nil : name)
continuation?.resume(returning: signInResult)
continuation = nil
}

Expand Down
12 changes: 6 additions & 6 deletions Projects/Domain/Auth/Sources/LoginManager/LoginManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ extension LoginManager: DependencyKey {
case .apple:
return try await signInWithApple()
case .sms:
return ""
return .init(accessToken: "")
}
}
)
Expand All @@ -43,15 +43,15 @@ extension DependencyValues {
// MARK: - Kakao SignIn Methods
extension LoginManager {
@MainActor
private static func signInWithKakao() async throws -> String {
private static func signInWithKakao() async throws -> SignInResult {
var accessToken = ""
if UserApi.isKakaoTalkLoginAvailable() {
accessToken = try await loginWithKakaoTalk()
} else {
accessToken = try await loginWithKakaoAccount()
}

return accessToken
return .init(accessToken: accessToken)
}

@MainActor
Expand Down Expand Up @@ -93,10 +93,10 @@ extension LoginManager {

// MARK: - Apple Login Methods
private extension LoginManager {
static func signInWithApple() async throws -> String {
static func signInWithApple() async throws -> SignInResult {
let appleLoginManager = AppleLoginManager()
let identityToken = try await appleLoginManager.signInWithApple()
return identityToken
let signInResult = try await appleLoginManager.signInWithApple()
return signInResult
}
}

Loading

0 comments on commit ab091b1

Please sign in to comment.