Sign In With Apple에 관한

E_H·2021년 8월 31일
0

Goal

애플 로그인과 그 방식에 대한 이해

WWDC19에서 발표된 애플 사용자를 위한 새로운 SSO 서비스입니다

애플 로그인은 iOS 13.0 이상부터 사용할 수 있습니다

타 SNS 로그인 방식을 구현하여 앱에 적용할 경우
애플 로그인은 필수로 구현되어야 합니다

Sign In With Apple 의 특징으로는

유저가 이중인증으로 로그인하면 ID, Full Name, Verified email address를 받아올 수 있습니다

또한 원본 이메일을 공유하거나 private한 이메일을 제공할것인지 유저가 선택할 수 있습니다

원리

인증과정으로는 아래 그림과 같습니다

  • 앱에서 API로 로그인 요청합니다
  • API는 유저 정보를 요청합니다
  • Apple ID server에 유저를 확인하고 토큰을 받습니다
  • Apple ID server로부터 유저 정보와 에메일을 반환받습니다

앱에서의 동작방식

구현

구현 방식은 애플 Sample code 문서인
Implementing User Authentication with Sign in with Apple 를 참고했습니다

let authorizationButton = ASAuthorizationAppleIDButton()
authorizationButton.addTarget(self, action: #selector(handleAuthorizationAppleIDButtonPress), for: .touchUpInside)

self.loginProviderStackView.addArrangedSubview(authorizationButton)

먼저 버튼을 구현합니다

@objc
func handleAuthorizationAppleIDButtonPress() {
    let appleIDProvider = ASAuthorizationAppleIDProvider()
    let request = appleIDProvider.createRequest()
    request.requestedScopes = [.fullName, .email]
    
    let authorizationController = ASAuthorizationController(authorizationRequests: [request])
    authorizationController.delegate = self
    authorizationController.presentationContextProvider = self
    authorizationController.performRequests()
}

이 함수는 Sign In With Apple 버튼이 클리되었을 때 호출되는데
fullName과 email 정보를 요구할 수 있습니다

func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
    return self.view.window!
}

인증창을 어느화면에 보여줄지 정하는 메서드입니다

인증결과를 다루기 위해 ASAuthorizationControllerDelegate 를 채택합니다

func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {}

func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {}

그러면 인증이 성공했을 때와 실패했을 경우 처리할 수 있는 메서드들이 있습니다

func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
    switch authorization.credential {
    case let appleIDCredential as ASAuthorizationAppleIDCredential:
        
        // Create an account in your system.
        let userIdentifier = appleIDCredential.user
        let fullName = appleIDCredential.fullName
        let email = appleIDCredential.email
        
        // For the purpose of this demo app, store the `userIdentifier` in the keychain.
        self.saveUserInKeychain(userIdentifier)
        
        // For the purpose of this demo app, show the Apple ID credential information in the `ResultViewController`.
        self.showResultViewController(userIdentifier: userIdentifier, fullName: fullName, email: email)
    
    case let passwordCredential as ASPasswordCredential:
    
        // Sign in using an existing iCloud Keychain credential.
        let username = passwordCredential.user
        let password = passwordCredential.password
        
        // For the purpose of this demo app, show the password credential as an alert.
        DispatchQueue.main.async {
            self.showPasswordCredentialAlert(username: username, password: password)
        }
        
    default:
        break
    }
}

문서의 코드를 빌려, 인증에 성공하면 요청한 정보들인 UserID와 fullName, email 등을 받을 수 있습니다.
UserID는 고정값이기 때문에 바뀌지 않습니다.

이 UserID를 키체인에 저장하고 getCredentialState메서드 파라미터에 값을 넣는 방식으로 자동로그인을 구현할 수 있습니다.

let appleIDProvider = ASAuthorizationAppleIDProvider()
    appleIDProvider.getCredentialState(forUserID: KeychainItem.currentUserIdentifier) { (credentialState, error) in
        switch credentialState {
        case .authorized:
            break // The Apple ID credential is valid.
        case .revoked, .notFound:
            // The Apple ID credential is either revoked or was not found, so show the sign-in UI.
            DispatchQueue.main.async {
                self.window?.rootViewController?.showLoginViewController()
            }
        default:
            break
        }
    }

또한 appleIDCredential을 통해 identityToken을 받아올 수 있는데
토큰은 JWT형식으로 구성되어있으며 많은 claim들을 포함하고 있습니다

iss : 토큰 발급자로 애플 로그인이기 때문에 https://appleid.apple.com 값을 가진다.
sub : 토큰 제목, 사용자를 위한 유일 값을 가진다. user identity가 sub 값으로 존재한다.
aud : 토큰 대상자
iat : 토큰이 발급된 시간 (UTC)
exp : 토큰 만료 시간 (UTC), 토큰을 확인할 때 값이 현재 날짜/시간보다 커야한다.
nonce : 클라이언트 세션과 ID 토큰을 연결하는 데 사용되는 문자열 값이다.
nonce_supported : 트랜잭션이 지원되지 않는 플랫폼에 있는지 여부를 나타내는 부울 값입니다.
email : 사용자 이메일 주소를 나타낸다. 비공개 이메일이면 privaterelay가 붙는다.
email_verified : 이메일이 검증되었는지 여부를 나타낸다. Bool 값을 String으로 전달한다.
is_private_email : 이메일이 비공개인지 여부를 나타낸다. Bool 값을 String으로 전달한다.
real_user_status : 사용자가 실제 사람인지를 포함한 값을 정수 형태로 나타낸다.

String(data: appleIDCredetial.identityToken!, encoding: .utf8)

이 값을 https://jwt.io 에서 encoded에 넣으면 decoded된
clames를 볼 수 있습니다

참고자료

애플의 SSO

SSO란 무엇인가

타 SNS 로그인 제공 시 Apple login 제공

HIG_Sign In With Apple

Sign in with apple Intruduce WWDC19

Sign In With Apple 구현 문서

IdentityToken 변환

0개의 댓글