포스트

단어장 프로젝트 (6)

Apple Login 구현.

먼저 애플 개발자 계정에서 해야하는것이 있다.

해당 내용은 출처를 보고 작성한다.

CleanShot 2024-05-18 at 21 55 13@2x

App Id로 들어가서 추가.

그다음 바로 continue를 하면

CleanShot 2024-05-18 at 21 56 01@2x

다음과 같이 나오는데 프로젝트 번들 identifier를 입력하고

밑에 내려가면 Sign in with Apple이 있다.

이걸 체크해주고 continue를 하자.

그러면 생성이 된다.

그리고 좌측에 있는 Key로 가서 키를 만들면

CleanShot 2024-05-18 at 22 08 23@2x

다음과 같이 뜨는데 키이름을 입력하고

sign in을 체크한뒤 configure를 클릭,

CleanShot 2024-05-18 at 22 09 17@2x

그럼 이렇게 우리가 등록한 앱이 나온다.

그리고 쭉 진행하면 다운로드 하라고 뜨는데, 키를 다운로드 해준다.

그리고 done을 누르면 끝.

프로젝트로 간다.

CleanShot 2024-05-18 at 22 11 19@2x

다음과 같이 추가를 해준다.

해당 내용은 출처

Firebase를 통해 프로젝트를 하나 만들어 준다.

해당내용은 pass

Firebase Auth페이지로 간다.

CleanShot 2024-05-18 at 19 23 06@2x

그리고 Apple을 클릭 CleanShot 2024-05-18 at 19 24 31@2x

도메인처럼 생긴 값을 별도로 저장을 해둔다.

그리고 저장을 꼭 클릭하자.

Apple 개발자 사이트로 간다.

그리고

CleanShot 2024-05-18 at 22 19 39@2x

Identifier에다가 현재 bundleIdentifier뒤에 하나를 더 적어주었다.

위에 App id로 만든것과 중복이 발생하기 때문.

continue를 해서 넘어가면

CleanShot 2024-05-18 at 22 27 55@2x

이렇게 나오는데

도메인은

CleanShot 2024-05-18 at 22 27 27@2x

여기에 있고,

auth url은 아까 위에 언급한 녀석이다.

저장하면 끝났다.

이제 로그인 기능을 구현해보도록 하겠다.

Apple DocsFirebase Docs 를 보면서 만든다.

그리고 거기에 Youtube 영상도 같이 참고를 한다.

lazy var appleBtn = ASAuthorizationAppleIDButton() 우선 버튼을 하나 만든다.

initialize를 할때

lazy var appleBtn = ASAuthorizationAppleIDButton(authorizationButtonType: .signIn, authorizationButtonStyle: .black)

이런식으로 안에 설정이 가능하다.

private var currentNonce: String?그리고 변수를 하나 만들어 주는데 Nonce는 Firebase Auth에도 쓰인다.

1
2
3
4
5
6
7
8
9
func handleAppleIDRequest() {
        let provider = ASAuthorizationAppleIDProvider()
        let request = provider.createRequest()
        request.requestedScopes = [.fullName, .email]
        
        let controller = ASAuthorizationController(authorizationRequests: [request])
        controller.delegate = self
        controller.performRequests()
    }

기본 세팅을 해주고,

Firebase Docs에 있는 코드를 복사해서 가져온다.

가져온다음 코드를 살짝 수정.

1
2
3
4
5
6
7
8
9
10
11
12
func handleAppleIDRequest() {
        let nonce = randomNonceString() // added
        currentNonce = nonce // added
        let provider = ASAuthorizationAppleIDProvider()
        let request = provider.createRequest()
        request.requestedScopes = [.fullName, .email]
        request.nonce = sha256(nonce) // added
        
        let controller = ASAuthorizationController(authorizationRequests: [request])
        controller.delegate = self
        controller.performRequests()
    }

nonce에 관한것만 추가가 되었다.

그리고 다음 함수를 만들어 준다.

1
2
3
4
5
6
7
func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: any Error) {
        
    }
    
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
        
    }

인증실패와, 성공에 관한 함수.

Simulator Screenshot - iPhone 15 Pro - 2024-05-18 at 23 52 42

실패할때는 alert를 띄우게 했다.

구현완료.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// VC
lazy var appleBtn = ASAuthorizationAppleIDButton(authorizationButtonType: .signIn, authorizationButtonStyle: .black)
private var currentNonce: String?

// MARK: - Apple Signin

extension LoginModalViewController: ASAuthorizationControllerDelegate {
    
    @objc func handleAppleIDRequest() {
        let nonce = randomNonceString()
        currentNonce = nonce
        let provider = ASAuthorizationAppleIDProvider()
        let request = provider.createRequest()
        request.requestedScopes = [.fullName, .email]
        request.nonce = sha256(nonce)
        
        let controller = ASAuthorizationController(authorizationRequests: [request])
        controller.delegate = self
        controller.performRequests()
    }
    
    func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: any Error) {
        let alert = alertController.makeNormalAlert(title: "에러발생", message: "로그인 할 수 없습니다.")
        
        self.present(alert, animated: true)
    }
    
    func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
        if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
            
            guard let nonce = currentNonce else {
                fatalError("Invalid state: A login callback was received, but no login request was sent.")
                return
            }
            
            guard let token = appleIDCredential.identityToken else {
                print("Unable to fetch identity token")
                return
            }
            
            guard let tokenString = String(data: token, encoding:  .utf8) else {
                print("Unable to serialize token string from data: \(token.debugDescription)")
                return
            }
            
            let oAuthCredential = OAuthProvider.credential(withProviderID: "apple.com", idToken: tokenString, rawNonce: nonce)
            
            Auth.auth().signIn(with: oAuthCredential) { [weak self] (result, error) in
                
                if let error = error {
                    print(error.localizedDescription)
                    return
                }
                
                self?.dismiss(animated: true)
                
            }
        }
        
        
    }
    
    
    // MARK: - from Firebase Docs
    private func randomNonceString(length: Int = 32) -> String {
        precondition(length > 0)
        var randomBytes = [UInt8](repeating: 0, count: length)
        let errorCode = SecRandomCopyBytes(kSecRandomDefault, randomBytes.count, &randomBytes)
        if errorCode != errSecSuccess {
            fatalError(
                "Unable to generate nonce. SecRandomCopyBytes failed with OSStatus \(errorCode)"
            )
        }
        
        let charset: [Character] =
        Array("0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._")
        
        let nonce = randomBytes.map { byte in
            // Pick a random character from the set, wrapping around if needed.
            charset[Int(byte) % charset.count]
        }
        
        return String(nonce)
    }
    
    @available(iOS 13, *)
    private func sha256(_ input: String) -> String {
        let inputData = Data(input.utf8)
        let hashedData = SHA256.hash(data: inputData)
        let hashString = hashedData.compactMap {
            String(format: "%02x", $0)
        }.joined()
        
        return hashString
    }
    
}

CleanShot 2024-05-19 at 00 55 02@2x

그리고 유저 정보를 Firebase에서 가져오게 했다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
extension MyPageViewController {
    
    func getUserData() {
        if let user = Auth.auth().currentUser {
            let uid = user.uid
            let email = user.email
            
            DispatchQueue.main.async{ [weak self] in
                self?.subLabel.text = uid
                self?.mailLabel.text = email
            }
            
        }
    }
}

스크린샷, 2024-05-19 오전 1 10 47

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.