📝

SignInWithAppleに対応する

2021/07/21に公開

SignInWithAppleとは

2019年のWWDCで発表されたAppleが開発した新しい認証方法です。

新規のアプリ申請では対応必須となっており、アップデート申請も7月から対応必須となります。

対応しない場合はリジェクト対象となりますので忘れずに対応しましょう。

準備編

AppleDeveloperでの設定

AppleDeveloperのサイトにアクセスして以下の設定をします。

Certificates, Identifiers & Profiles→Identifiers→対象のアプリ→CapabilitiesからSigninWithAppleにチェック

Xcodeの設定

次にXcodeのCapabilitiesにSignInWithAppleを追加します。

手順は以下です。

TARGET→Signing&Capabilities→Capabilityを選択してSigninWithAppleを追加

実装編

Nonceを取得する

APIでNonceを取得するAPIを叩くか以下の関数を実装してNonceを取得します。

https://firebase.google.com/docs/auth/ios/appleより引用)

func randomNonceString(length: Int = 32) -> Observable<String> {
    precondition(length > 0)
    let charset: Array<Character> = Array("0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._")
    var result = ""
    var remainingLength = length
    
    while remainingLength > 0 {
        let randoms: [UInt8] = (0 ..< 16).map { _ in
            var random: UInt8 = 0
            let errorCode = SecRandomCopyBytes(kSecRandomDefault, 1, &random)
            if errorCode != errSecSuccess {
                fatalError("Unable to generate nonce. SecRandomCopyBytes failed with OSStatus \(errorCode)")
            }
            return random
        }
        
        randoms.forEach { random in
            if length == 0 {
                return
            }
            
            if random < charset.count {
                result.append(charset[Int(random)])
                remainingLength -= 1
            }
        }
    }
    
    return .just(sha256(result))
}

func sha256(_ input: String) -> String {
    let inputData = Data(input.utf8)
    let hashedData = SHA256.hash(data: inputData)
    let hashString = hashedData.compactMap {
        return String(format: "%02x", $0)
    }.joined()
    
    return hashString
}

ViewControllerの実装

ボタンイベント等で以下の処理を実装して認証画面を表示します。

let provider = ASAuthorizationAppleIDProvider()
let request = provider.createRequest()
request.requestedScopes = [.email, .fullName]
request.nonce = nonce
let controller = ASAuthorizationController(authorizationRequests: [request])
controller.delegate = self
controller.presentationContextProvider = self
controller.performRequests()

認証の実装

ログイン画面のViewControllerにASAuthorizationControllerDelegateASAuthorizationControllerPresentationContextProvidingを実装します。

func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
	// 認証成功時の処理
}
    
func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
	// 認証失敗時の処理
}

func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
	// コンテンツを表示するWindowを指定
	// UIViewControllerのwindowを指定する
  return self.view.window!
}

状態監視の実装

AppDelegateのapplicationDidBecomeActive関数で以下のチェック処理を実装します。

let provider = ASAuthorizationAppleIDProvider()
    provider.getCredentialState(forUserID: appleId) { state, error in
        switch state {
				// 認証が無効になった場合
        case .revoked, .notFound:
            // サービスのログアウト処理
        default:
            break
        }
    }
}

実装してみた感想

今回初めて実装してみましたがかなり簡単に実装できて実装もシンプルなのでかなり良い印象でした。

ただ公式ドキュメントが少しわかりにくいのでそのへん改善して欲しいなと思いました。

参考サイト

全く知らない人のためのSign in with Apple

https://tech.mercari.com/entry/2019/12/11/115331

Discussion