Skip to content

Latest commit

 

History

History
312 lines (246 loc) · 10.8 KB

File metadata and controls

312 lines (246 loc) · 10.8 KB

Flida iOS SDK

Официальный iOS SDK для интеграции аутентификации Flida в ваши iOS приложения.

Установка

Swift Package Manager

  1. В Xcode откройте File > Add Package Dependencies...
  2. Введите URL репозитория: https://github.com/flida-dev/ios-sdk
  3. Выберите нужную версию.

Настройка

1. Настройка Info.plist

Добавьте ключ FlidaAuthHost в ваш Info.plist:

<key>FlidaAuthHost</key>
<string>YOUR_CLIENT_ID.api.flida.dev</string>

Формат: {clientId}.api.{domain}

Примеры:

  • 019b650a-156e-77f3-ad1d-df2e2d8c2a5c.api.flida.dev
  • 019b650a-156e-77f3-ad1d-df2e2d8c2a5c.api.flida.ru

SDK автоматически извлекает из FlidaAuthHost:

  • Client ID — первая часть строки
  • API Endpointhttps://api.{domain}
  • Auth Endpointhttps://{domain}
  • Redirect URIflida{clientId}://auth

2. URL Scheme

Добавьте URL scheme для обработки OAuth callback в Info.plist:

<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>flida{YOUR_CLIENT_ID}</string>
        </array>
    </dict>
</array>

3. Инициализация

SDK инициализируется автоматически из Info.plist при первом обращении к FlidaIDSDK.shared. Никаких дополнительных действий не требуется.

Использование

Авторизация

Для запуска флоу авторизации вызовите signIn. Необходимо передать ASWebAuthenticationPresentationContextProviding (обычно ваш view controller).

import AuthenticationServices
import FlidaIDSDK

class ViewController: UIViewController, ASWebAuthenticationPresentationContextProviding {

    func signIn() {
        FlidaIDSDK.shared.signIn(
            presenting: self,
            scopes: ["openid", "name", "e-mail-address", "phone-number"]
        ) { result in
            switch result {
            case .success(let tokenResponse):
                print("Access Token: \(tokenResponse.token.accessToken)")
            case .failure(let error):
                print("Ошибка: \(error.localizedDescription)")
            }
        }
    }

    // ASWebAuthenticationPresentationContextProviding
    func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
        return self.view.window!
    }
}

Получение информации о пользователе

После авторизации можно получить данные пользователя:

FlidaIDSDK.shared.getUserInfo(accessToken: accessToken) { result in
    switch result {
    case .success(let user):
        print("Имя: \(user.name)")
        print("ID: \(user.id)")
    case .failure(let error):
        print("Ошибка: \(error.localizedDescription)")
    }
}

Обновление токена

Для обновления access token:

FlidaIDSDK.shared.refreshTokens(refreshToken: refreshToken) { result in
    switch result {
    case .success(let tokenResponse):
        print("Новый Access Token: \(tokenResponse.token.accessToken)")
    case .failure(let error):
        print("Ошибка: \(error.localizedDescription)")
    }
}

Выход

FlidaIDSDK.shared.logout()

Стрим событий

SDK предоставляет стрим событий на основе Combine для реактивного программирования. Подписывайтесь на события, чтобы получать уведомления об изменениях состояния аутентификации.

Доступные события

Событие Описание
signedIn(user:accessToken:) Пользователь успешно авторизовался
signInFailed(error:) Ошибка авторизации
tokensRefreshed(accessToken:) Токены успешно обновлены
tokenRefreshFailed(error:) Ошибка обновления токенов
loggedOut(reason:) Пользователь вышел из системы
userInfoFetched(user:) Информация о пользователе получена
userInfoFetchFailed(error:) Ошибка получения информации о пользователе

Причины выхода (LogoutReason)

Причина Описание
.userInitiated Пользователь вызвал logout() явно
.sessionExpired Refresh token истёк (404)
.unauthorized Сервер вернул 401 при обновлении токена

Подписка на события

import Combine
import FlidaIDSDK

class AuthManager {
    private var cancellables = Set<AnyCancellable>()
    
    init() {
        FlidaIDSDK.shared.events.events
            .sink { [weak self] event in
                self?.handleEvent(event)
            }
            .store(in: &cancellables)
    }
    
    private func handleEvent(_ event: FlidaEvent) {
        switch event {
        case .signedIn(let user, let accessToken):
            print("Пользователь вошёл: \(user?.name ?? "Неизвестно")")
            
        case .signInFailed(let error):
            print("Ошибка входа: \(error.localizedDescription)")
            
        case .tokensRefreshed(let accessToken):
            print("Токены обновлены")
            
        case .tokenRefreshFailed(let error):
            print("Ошибка обновления токенов: \(error.localizedDescription)")
            
        case .loggedOut(let reason):
            switch reason {
            case .userInitiated:
                print("Пользователь вышел")
            case .sessionExpired:
                print("Сессия истекла")
            case .unauthorized:
                // 401 на refresh — перенаправить на логин
                print("Сессия недействительна, войдите снова")
            }
            
        case .userInfoFetched(let user):
            print("Информация о пользователе: \(user.name)")
            
        case .userInfoFetchFailed(let error):
            print("Ошибка получения информации: \(error.localizedDescription)")
        }
    }
}

Пример использования с SwiftUI

import SwiftUI
import Combine
import FlidaIDSDK

struct ContentView: View {
    @State private var cancellables = Set<AnyCancellable>()
    @State private var isLoggedIn = false
    
    var body: some View {
        Group {
            if isLoggedIn {
                MainView()
            } else {
                LoginView()
            }
        }
        .onAppear {
            FlidaIDSDK.shared.events.events
                .sink { event in
                    switch event {
                    case .signedIn:
                        isLoggedIn = true
                    case .loggedOut:
                        isLoggedIn = false
                    default:
                        break
                    }
                }
                .store(in: &cancellables)
        }
    }
}

Обработка ошибок

Все методы SDK возвращают типизированные ошибки FlidaError:

FlidaIDSDK.shared.signIn(presenting: self, scopes: ["openid"]) { result in
    switch result {
    case .success(let response):
        // Успех
        
    case .failure(let error):
        switch error {
        case .userCancelled:
            // Пользователь отменил — не показываем ошибку
            break
        case .notInitialized:
            print("Настройте FlidaAuthHost в Info.plist")
        case .unauthorized:
            print("Токен истёк, войдите снова")
        case .networkError(let underlyingError):
            print("Ошибка сети: \(underlyingError)")
        default:
            print("Ошибка: \(error.localizedDescription)")
        }
    }
}

Типы ошибок

Ошибка Описание
notInitialized SDK не настроен (отсутствует FlidaAuthHost)
userCancelled Пользователь отменил авторизацию
invalidCallbackURL Неверный callback URL
stateMismatch Несоответствие OAuth state (возможная CSRF атака)
noAuthorizationCode Нет кода авторизации в callback
pkceGenerationFailed Ошибка генерации PKCE challenge
oauthError(String) OAuth ошибка от сервера
unauthorized 401 — Access token истёк
forbidden(String?) 403 — Доступ запрещён
refreshTokenExpired Refresh token истёк
tokenExchangeFailed(String?) Ошибка обмена токена
networkError(Error) Ошибка сетевого запроса
serverError(statusCode:message:) Сервер вернул ошибку
decodingError(Error) Ошибка декодирования ответа
noData Нет данных от сервера

Логирование

SDK включает систему логирования с настраиваемыми уровнями.

Уровни логирования

Уровень Описание
.none Логирование отключено (по умолчанию)
.error Только ошибки
.warning Ошибки и предупреждения
.info Ошибки, предупреждения и информационные сообщения
.debug Всё выше + информация о HTTP запросах/ответах
.verbose Все сообщения, включая тела HTTP запросов

Включение логирования

// Включить debug логирование
FlidaIDSDK.shared.setLogLevel(.debug)

// Или для максимальной детализации
FlidaIDSDK.shared.setLogLevel(.verbose)

⚠️ Важно: На уровне .verbose чувствительные данные автоматически маскируются, но рекомендуется использовать verbose логирование только при разработке.