forked from DDD-Community/DDD11-SClass-iOS
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Feat] - DDD-Community#44 애플 로그인, 카카오 로그인 로직 추가
- Loading branch information
Showing
8 changed files
with
366 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,14 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
<plist version="1.0"> | ||
<dict> | ||
<key>keychain-access-groups</key> | ||
<array> | ||
<string>$(AppIdentifierPrefix)group.com.DDD.OnboardingKit</string> | ||
</array> | ||
</dict> | ||
<dict> | ||
<key>com.apple.developer.applesignin</key> | ||
<array> | ||
<string>Default</string> | ||
</array> | ||
<key>keychain-access-groups</key> | ||
<array> | ||
<string>$(AppIdentifierPrefix)group.com.DDD.OnboardingKit</string> | ||
</array> | ||
</dict> | ||
</plist> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// | ||
// SocialLoginInfo.swift | ||
// CoreDomain | ||
// | ||
// Created by 현수빈 on 1/15/25. | ||
// | ||
|
||
import Foundation | ||
|
||
public struct SocialLoginInfo: Equatable { | ||
public let idToken: String | ||
public let nonce: String? | ||
public let provider: Socialtype | ||
|
||
public init( | ||
idToken: String, | ||
nonce: String? = nil, | ||
provider: Socialtype | ||
) { | ||
self.idToken = idToken | ||
self.nonce = nonce | ||
self.provider = provider | ||
} | ||
} | ||
|
||
extension SocialLoginInfo { | ||
public enum Socialtype: String { | ||
case kakao = "Kakao" | ||
case apple = "Apple" | ||
} | ||
} |
93 changes: 93 additions & 0 deletions
93
Projects/Core/Network/Sources/Services/Login/AppleLogin.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
// | ||
// SocialLogin.swift | ||
// CoreNetwork | ||
// | ||
// Created by 현수빈 on 1/15/25. | ||
// | ||
|
||
import AuthenticationServices | ||
import Foundation | ||
|
||
import CoreDomain | ||
|
||
public enum AppleErrorType: Error { | ||
case invalidToken | ||
case invalidAuthorizationCode | ||
case dismissASAuthorizationController | ||
} | ||
|
||
final class AppleLogin: NSObject, ASAuthorizationControllerDelegate { | ||
private var continuation: CheckedContinuation<SocialLoginInfo, Error>? = nil | ||
|
||
/// 애플 로그인 | ||
@MainActor | ||
func appleLogin() async throws -> SocialLoginInfo { | ||
return try await withCheckedThrowingContinuation { continuation in | ||
let appleIDProvider = ASAuthorizationAppleIDProvider() | ||
let request = appleIDProvider.createRequest() | ||
request.requestedScopes = [.fullName, .email] | ||
|
||
let authorizationController = ASAuthorizationController(authorizationRequests: [request]) | ||
authorizationController.delegate = self | ||
authorizationController.performRequests() | ||
|
||
if self.continuation == nil { | ||
self.continuation = continuation | ||
} | ||
} | ||
} | ||
|
||
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) { | ||
switch authorization.credential { | ||
case let appleIDCredential as ASAuthorizationAppleIDCredential: | ||
let email = appleIDCredential.email | ||
debugPrint("appleLogin email: \(email ?? "")") | ||
let fullName = appleIDCredential.fullName | ||
debugPrint("appleLogin fullName: \(fullName?.description ?? "")") | ||
|
||
guard let tokenData = appleIDCredential.identityToken, | ||
let token = String(data: tokenData, encoding: .utf8) else { | ||
continuation?.resume(throwing: AppleErrorType.invalidToken) | ||
continuation = nil | ||
return | ||
} | ||
|
||
debugPrint("appleLogin token: \(token)") | ||
|
||
guard let authorizationCode = appleIDCredential.authorizationCode, | ||
let authorizationCodeString = String(data: authorizationCode, encoding: .utf8) else { | ||
continuation?.resume(throwing: AppleErrorType.invalidAuthorizationCode) | ||
continuation = nil | ||
return | ||
} | ||
|
||
debugPrint("appleLogin authorizationCode: \(authorizationCodeString)") | ||
|
||
let userIdentifier = appleIDCredential.user | ||
debugPrint("appleLogin authenticated user: \(userIdentifier)") | ||
|
||
let info = SocialLoginInfo(idToken: token, provider: .apple) | ||
|
||
continuation?.resume(returning: info) | ||
continuation = nil | ||
|
||
default: | ||
break | ||
} | ||
} | ||
|
||
@MainActor | ||
func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) { | ||
if let authError = error as? ASAuthorizationError { | ||
switch authError.code { | ||
case .canceled: | ||
continuation?.resume(throwing: AppleErrorType.dismissASAuthorizationController) | ||
continuation = nil | ||
|
||
default: | ||
continuation?.resume(throwing: authError) | ||
continuation = nil | ||
} | ||
} | ||
} | ||
} |
98 changes: 98 additions & 0 deletions
98
Projects/Core/Network/Sources/Services/Login/KakaoLogin.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
// | ||
// KakaoLogin.swift | ||
// CoreNetwork | ||
// | ||
// Created by 현수빈 on 1/15/25. | ||
// | ||
|
||
import Foundation | ||
|
||
import CoreDomain | ||
|
||
import KakaoSDKAuth | ||
import KakaoSDKCommon | ||
import KakaoSDKUser | ||
|
||
enum KakaoErrorType: Error { | ||
case invalidToken | ||
} | ||
|
||
final class KakaoLogin { | ||
private var continuation: CheckedContinuation<SocialLoginInfo, Error>? = nil | ||
|
||
|
||
func initSDK() { | ||
if let appkey = Bundle.main.infoDictionary?["KAKAO_NATIVE_APP_KEY"] as? String { | ||
KakaoSDK.initSDK(appKey: appkey) | ||
} | ||
} | ||
|
||
/// Handle KakaoTalkLoginUrl | ||
func handleKakaoTalkLoginUrl(url: URL) { | ||
guard AuthApi.isKakaoTalkLoginUrl(url) else { return } | ||
_ = AuthController.handleOpenUrl(url: url) | ||
} | ||
|
||
/// 카카오톡 로그인 | ||
@MainActor | ||
func kakaoLogin() async throws -> SocialLoginInfo { | ||
return try await withCheckedThrowingContinuation { continuation in | ||
self.continuation = continuation | ||
let nonce = UUID().uuidString | ||
|
||
if UserApi.isKakaoTalkLoginAvailable() { | ||
loginWithKakaoTalk(nonce: nonce) | ||
} else { | ||
loginWithKakaoWeb(nonce: nonce) | ||
} | ||
} | ||
} | ||
|
||
/// 카카오톡(앱)으로 로그인 | ||
private func loginWithKakaoTalk(nonce: String) { | ||
UserApi.shared.loginWithKakaoTalk(nonce: nonce) { [weak self] OAuthToken, error in | ||
guard let self else { return } | ||
|
||
if let error { | ||
self.continuation?.resume(throwing: error) | ||
self.continuation = nil | ||
debugPrint("\(error)") | ||
return | ||
} else if let token = OAuthToken?.idToken { | ||
self.setSocialLoginData(idToken: token, nonce: nonce) | ||
debugPrint("loginWithKakaoTalk() success., \(#function), \(#line)") | ||
} else { | ||
self.continuation?.resume(throwing: KakaoErrorType.invalidToken) | ||
self.continuation = nil | ||
return | ||
} | ||
} | ||
} | ||
|
||
/// 웹에서 카카오 계정 Access | ||
private func loginWithKakaoWeb(nonce: String) { | ||
UserApi.shared.loginWithKakaoAccount(nonce: nonce) { [weak self] OAuthToken, error in | ||
guard let self else { return } | ||
|
||
if let error { | ||
self.continuation?.resume(throwing: error) | ||
self.continuation = nil | ||
debugPrint("\(error)") | ||
return | ||
} else if let token = OAuthToken?.idToken { | ||
self.setSocialLoginData(idToken: token, nonce: nonce) | ||
debugPrint("loginWithWeb() success., \(#function), \(#line)") | ||
} else { | ||
self.continuation?.resume(throwing: KakaoErrorType.invalidToken) | ||
self.continuation = nil | ||
return | ||
} | ||
} | ||
} | ||
|
||
private func setSocialLoginData(idToken: String, nonce: String) { | ||
let info = SocialLoginInfo(idToken: idToken, nonce: nonce, provider: .kakao) | ||
continuation?.resume(returning: info) | ||
continuation = nil | ||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
Projects/Core/Network/Sources/Services/Login/SocialLoginClient.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// | ||
// SocialLoginClient.swift | ||
// CoreNetwork | ||
// | ||
// Created by 현수빈 on 1/15/25. | ||
// | ||
|
||
import Foundation | ||
|
||
import CoreDomain | ||
|
||
import ComposableArchitecture | ||
|
||
public struct SocialLoginClient { | ||
public var initKakaoSDK: @Sendable () -> Void | ||
public var handleKakaoUrl: @Sendable (URL) -> Void | ||
public var kakaoLogin: @Sendable () async throws -> SocialLoginInfo | ||
public var appleLogin: @Sendable () async throws -> SocialLoginInfo | ||
} | ||
|
||
extension SocialLoginClient: DependencyKey { | ||
public static var liveValue: SocialLoginClient { | ||
let kakaoLogin = KakaoLogin() | ||
let appleLogin = AppleLogin() | ||
|
||
return Self( | ||
initKakaoSDK: { | ||
kakaoLogin.initSDK() | ||
}, | ||
handleKakaoUrl: { | ||
kakaoLogin.handleKakaoTalkLoginUrl(url: $0) | ||
}, | ||
kakaoLogin: { | ||
try await kakaoLogin.kakaoLogin() | ||
}, | ||
appleLogin: { | ||
try await appleLogin.appleLogin() | ||
} | ||
) | ||
} | ||
} | ||
|
||
public extension DependencyValues { | ||
var socialLogin: SocialLoginClient { | ||
get { self[SocialLoginClient.self] } | ||
set { self[SocialLoginClient.self] = newValue } | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
Projects/Core/Network/Sources/Services/Login/TokenInfo.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// | ||
// TokenInfo.swift | ||
// CoreNetwork | ||
// | ||
// Created by 현수빈 on 1/15/25. | ||
// | ||
|
||
import Foundation | ||
|
||
public struct TokenInfo { | ||
public let accessToken: String | ||
public let refreshToken: String | ||
|
||
public init(accessToken: String, refreshToken: String) { | ||
self.accessToken = accessToken | ||
self.refreshToken = refreshToken | ||
} | ||
} |
Oops, something went wrong.