단어장 프로젝트 (6)
Apple Login 구현.
먼저 애플 개발자 계정에서 해야하는것이 있다.
해당 내용은 출처를 보고 작성한다.
App Id로 들어가서 추가.
그다음 바로 continue를 하면
다음과 같이 나오는데 프로젝트 번들 identifier를 입력하고
밑에 내려가면 Sign in with Apple이 있다.
이걸 체크해주고 continue를 하자.
그러면 생성이 된다.
그리고 좌측에 있는 Key로 가서 키를 만들면
다음과 같이 뜨는데 키이름을 입력하고
sign in을 체크한뒤 configure를 클릭,
그럼 이렇게 우리가 등록한 앱이 나온다.
그리고 쭉 진행하면 다운로드 하라고 뜨는데, 키를 다운로드 해준다.
그리고 done을 누르면 끝.
프로젝트로 간다.
다음과 같이 추가를 해준다.
해당 내용은 출처
Firebase를 통해 프로젝트를 하나 만들어 준다.
해당내용은 pass
Firebase Auth페이지로 간다.
도메인처럼 생긴 값을 별도로 저장을 해둔다.
그리고 저장을 꼭 클릭하자.
Apple 개발자 사이트로 간다.
그리고
Identifier에다가 현재 bundleIdentifier뒤에 하나를 더 적어주었다.
위에 App id로 만든것과 중복이 발생하기 때문.
continue를 해서 넘어가면
이렇게 나오는데
도메인은
여기에 있고,
auth url은 아까 위에 언급한 녀석이다.
저장하면 끝났다.
이제 로그인 기능을 구현해보도록 하겠다.
Apple Docs와 Firebase 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) {
}
인증실패와, 성공에 관한 함수.
실패할때는 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
}
}
그리고 유저 정보를 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
}
}
}
}