На WWDC 2019 Apple в очередной раз нарушила покой iOS разработчиков — представила новую систему авторизации пользователей Sign in with Apple. Теперь все iOS приложения, которые используют сторонние системы авторизации (Facebook, Twitter, etc.), должны в обязательном порядке реализовать Sign in with Apple, иначе выгонят из AppStore. Мы решили не испытывать судьбу и побежали внедрять эту фичу. Как именно мы это сделали — узнаете под катом.
В своей работе мы используем архитектуру VIPER+SOA, поэтому авторизацию через Apple мы сделали как отдельный сервис. Сначала мы оборачиваем данные в enum, чтобы удобно расширять типы авторизации (фейсбук, вк, гугл и т.д.):
Результат наружу будем передавать с помощью Observable из RxSwift:
Реализация протокола:
Статья получилось небольшой, но надеемся что она была полезной для вас.
Благодарим за внимание!
Пишем сервис авторизации через Apple
В своей работе мы используем архитектуру VIPER+SOA, поэтому авторизацию через Apple мы сделали как отдельный сервис. Сначала мы оборачиваем данные в enum, чтобы удобно расширять типы авторизации (фейсбук, вк, гугл и т.д.):
enum AuthToken { case apple(code: String, name: String) }
Результат наружу будем передавать с помощью Observable из RxSwift:
protocol AuthProviderProtocol { var authResult: Observable<AuthToken> { get } func login() func logout() }
Реализация протокола:
import AuthenticationServices import Foundation import RxSwift @available(iOS 13.0, *) class AppleAuthService: AuthProviderProtocol { private let authResultSubject = PublishSubject<AuthToken>() var authResult: Observable<AuthToken> { return authResultSubject.asObservable() } func login() { let appleIDProvider = ASAuthorizationAppleIDProvider() let request = appleIDProvider.createRequest() request.requestedScopes = [.fullName, .email] let authorizationController = ASAuthorizationController(authorizationRequests: [request]) authorizationController.delegate = self authorizationController.performRequests() } } @available(iOS 13.0, *) extension AppleAuthService: ASAuthorizationControllerDelegate { func authorizationController( controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization ) { guard let credential = authorization.credential as? ASAuthorizationAppleIDCredential, let tokenData = credential.authorizationCode, let token = String(data: tokenData, encoding: .utf8) else { return } let firstName = credential.fullName?.givenName let lastName = credential.fullName?.familyName authResultSubject.onNext(.apple(code: token, name: firstName + lastName)) } }
Нюансы, о которых нужно знать
- У Sign in with Apple нету функции logout в классическом понимании этого слова. Библиотека не хранит никакие данные, в отличие от других библиотек входа, поэтому нет необходимости стирать данные, полученные при логине.
- Sign in with Apple получает имя и фамилию пользователя только один раз при самом первом логине. У сервера нет доступа к этим данным. При последующих попытках входа вам будут приходить только authorizationCode из ASAuthorizationAppleIDCredential. Поэтому мы на клиентской стороне храним имя и фамилию пользователя до тех пор, пока регистрация на сервере не завершится успешно.
- Sign in with Apple позволяет пользователю подменить свой e-mail. На подмененный e-mail можно написать только с тех доменов, которые вы укажете в настройках на developer.apple.com

- В этой статье описано то, как мы реализовали back-end часть.
Статья получилось небольшой, но надеемся что она была полезной для вас.
Благодарим за внимание!
