Sdílet prostřednictvím


Kurz: Přihlášení uživatelů v mobilní aplikaci pro iOS (Swift)

Toto je třetí kurz série kurzů, který vás provede přihlašováním uživatelů pomocí Microsoft Entra ID.

Než začnete, pomocí selektoru Zvolte typ nájemce v horní části této stránky vyberte typ nájemce. Microsoft Entra ID poskytuje dvě konfigurace tenantů, pracovní síly a externí. Konfigurace tenanta pracovních sil je určená pro zaměstnance, interní aplikace a další organizační prostředky. Externí tenant je určený pro vaše aplikace určené pro zákazníky.

V tomto kurzu:

  • Přihlaste se uživatele.
  • Odhlaste se od uživatele.
  • Vytvoření uživatelského rozhraní aplikace

Požadavky

Přihlášení uživatele

Máte dvě hlavní možnosti pro přihlašování uživatelů pomocí knihovny MICROSOFT Authentication Library (MSAL) pro iOS: interaktivní nebo tiché získání tokenů.

  1. Pokud se chcete přihlásit uživatele interaktivně, použijte následující kód:

    func acquireTokenInteractively() {
    
        guard let applicationContext = self.applicationContext else { return }
        guard let webViewParameters = self.webViewParameters else { return }
    
        // #1
        let parameters = MSALInteractiveTokenParameters(scopes: kScopes, webviewParameters: webViewParameters)
        parameters.promptType = .selectAccount
    
        // #2
        applicationContext.acquireToken(with: parameters) { (result, error) in
    
            // #3
            if let error = error {
    
                self.updateLogging(text: "Could not acquire token: \(error)")
                return
            }
    
            guard let result = result else {
    
                self.updateLogging(text: "Could not acquire token: No result returned")
                return
            }
    
            // #4
            self.accessToken = result.accessToken
            self.updateLogging(text: "Access token is \(self.accessToken)")
            self.updateCurrentAccount(account: result.account)
            self.getContentWithToken()
        }
    }
    

    Vlastnost promptType v rámci MSALInteractiveTokenParameters konfiguruje chování výzvy k ověření a vyjádření souhlasu. Podporují se následující hodnoty:

    • .promptIfNecessary (výchozí) – Uživateli se zobrazí výzva pouze v případě potřeby. Prostředí SSO je určeno přítomností souborů cookie ve webovém zobrazení a typem účtu. Pokud je přihlášeno více uživatelů, zobrazí se prostředí pro výběr účtu. Toto je výchozí chování.
    • .selectAccount – Pokud není zadaný žádný uživatel, zobrazí ověřovací webové zobrazení seznam aktuálně přihlášených účtů, ze které má uživatel vybírat.
    • .login – Vyžaduje, aby se uživatel ověřil ve webovém zobrazení. Pokud tuto hodnotu zadáte, může být současně přihlášen pouze jeden účet.
    • .consent – Vyžaduje, aby uživatel souhlasil s aktuální sadou oborů pro požadavek.
  2. Pokud chcete uživatele přihlásit bezobslužně, použijte následující kód:

    
        func acquireTokenSilently(_ account : MSALAccount!) {
    
            guard let applicationContext = self.applicationContext else { return }
    
            /**
    
             Acquire a token for an existing account silently
    
             - forScopes:           Permissions you want included in the access token received
             in the result in the completionBlock. Not all scopes are
             guaranteed to be included in the access token returned.
             - account:             An account object that we retrieved from the application object before that the
             authentication flow will be locked down to.
             - completionBlock:     The completion block that will be called when the authentication
             flow completes, or encounters an error.
             */
    
            let parameters = MSALSilentTokenParameters(scopes: kScopes, account: account)
    
            applicationContext.acquireTokenSilent(with: parameters) { (result, error) in
    
                if let error = error {
    
                    let nsError = error as NSError
    
                    // interactionRequired means we need to ask the user to sign-in. This usually happens
                    // when the user's Refresh Token is expired or if the user has changed their password
                    // among other possible reasons.
    
                    if (nsError.domain == MSALErrorDomain) {
    
                        if (nsError.code == MSALError.interactionRequired.rawValue) {
    
                            DispatchQueue.main.async {
                                self.acquireTokenInteractively()
                            }
                            return
                        }
                    }
    
                    self.updateLogging(text: "Could not acquire token silently: \(error)")
                    return
                }
    
                guard let result = result else {
    
                    self.updateLogging(text: "Could not acquire token: No result returned")
                    return
                }
    
                self.accessToken = result.accessToken
                self.updateLogging(text: "Refreshed Access token is \(self.accessToken)")
                self.updateSignOutButton(enabled: true)
                self.getContentWithToken()
            }
        }
    

    Metoda acquireTokenSilently se pokusí bezobslužně získat přístupový token pro existující účet MSAL. Používá applicationContext k vyžádání tokenu se zadanými rozsahy. Pokud dojde k chybě, zkontroluje, jestli je vyžadována interakce uživatele, a pokud ano, zahájí interaktivní získání tokenu. Po úspěšném dokončení aktualizuje přístupový token, zaznamená výsledek, povolí tlačítko odhlášení a načte obsah pomocí tokenu.

Zpracujte zpětné volání přihlášení (pouze pro iOS)

Otevřete soubor AppDelegate.swift. Pokud chcete zpracovat zpětné volání po přihlášení, přidejte MSALPublicClientApplication.handleMSALResponse do třídy appDelegate takto:

// Inside AppDelegate...
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {

        return MSALPublicClientApplication.handleMSALResponse(url, sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String)
}

Pokud používáte Xcode 11, měli byste místo toho umístit zpětné volání MSAL do SceneDelegate.swift. Pokud podporujete JAK UISceneDelegate, tak UIApplicationDelegate kvůli kompatibilitě se starším iOSem, bude nutné zpětné volání MSAL umístit do obou souborů.

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {

        guard let urlContext = URLContexts.first else {
            return
        }

        let url = urlContext.url
        let sourceApp = urlContext.options.sourceApplication

        MSALPublicClientApplication.handleMSALResponse(url, sourceApplication: sourceApp)
    }

Odhlásit uživatele

Důležitý

Odhlášení pomocí MSAL odebere všechny známé informace o uživateli z aplikace a také odstraní aktivní relaci na zařízení, pokud to umožní konfigurace zařízení. Uživatele můžete také volitelně odhlásit z prohlížeče.

Pokud chcete přidat funkci odhlášení, přidejte do třídy ViewController následující kód.

@objc func signOut(_ sender: AnyObject) {

        guard let applicationContext = self.applicationContext else { return }

        guard let account = self.currentAccount else { return }

        do {

            /**
             Removes all tokens from the cache for this application for the provided account

             - account:    The account to remove from the cache
             */

            let signoutParameters = MSALSignoutParameters(webviewParameters: self.webViewParameters!)
            signoutParameters.signoutFromBrowser = false // set this to true if you also want to signout from browser or webview

            applicationContext.signout(with: account, signoutParameters: signoutParameters, completionBlock: {(success, error) in

                if let error = error {
                    self.updateLogging(text: "Couldn't sign out account with error: \(error)")
                    return
                }

                self.updateLogging(text: "Sign out completed successfully")
                self.accessToken = ""
                self.updateCurrentAccount(account: nil)
            })

        }
    }

Vytvoření uživatelského rozhraní aplikace

Teď vytvořte uživatelské rozhraní, které obsahuje tlačítko pro volání rozhraní Microsoft Graph API, jiného pro odhlášení a textové zobrazení, které zobrazí nějaký výstup přidáním následujícího kódu do třídy ViewController:

Uživatelské rozhraní iOS

var loggingText: UITextView!
var signOutButton: UIButton!
var callGraphButton: UIButton!
var usernameLabel: UILabel!

func initUI() {

    usernameLabel = UILabel()
    usernameLabel.translatesAutoresizingMaskIntoConstraints = false
    usernameLabel.text = ""
    usernameLabel.textColor = .darkGray
    usernameLabel.textAlignment = .right

    self.view.addSubview(usernameLabel)

    usernameLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 50.0).isActive = true
    usernameLabel.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -10.0).isActive = true
    usernameLabel.widthAnchor.constraint(equalToConstant: 300.0).isActive = true
    usernameLabel.heightAnchor.constraint(equalToConstant: 50.0).isActive = true

    // Add call Graph button
    callGraphButton  = UIButton()
    callGraphButton.translatesAutoresizingMaskIntoConstraints = false
    callGraphButton.setTitle("Call Microsoft Graph API", for: .normal)
    callGraphButton.setTitleColor(.blue, for: .normal)
    callGraphButton.addTarget(self, action: #selector(callGraphAPI(_:)), for: .touchUpInside)
    self.view.addSubview(callGraphButton)

    callGraphButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    callGraphButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 120.0).isActive = true
    callGraphButton.widthAnchor.constraint(equalToConstant: 300.0).isActive = true
    callGraphButton.heightAnchor.constraint(equalToConstant: 50.0).isActive = true

    // Add sign out button
    signOutButton = UIButton()
    signOutButton.translatesAutoresizingMaskIntoConstraints = false
    signOutButton.setTitle("Sign Out", for: .normal)
    signOutButton.setTitleColor(.blue, for: .normal)
    signOutButton.setTitleColor(.gray, for: .disabled)
    signOutButton.addTarget(self, action: #selector(signOut(_:)), for: .touchUpInside)
    self.view.addSubview(signOutButton)

    signOutButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    signOutButton.topAnchor.constraint(equalTo: callGraphButton.bottomAnchor, constant: 10.0).isActive = true
    signOutButton.widthAnchor.constraint(equalToConstant: 150.0).isActive = true
    signOutButton.heightAnchor.constraint(equalToConstant: 50.0).isActive = true

    let deviceModeButton = UIButton()
    deviceModeButton.translatesAutoresizingMaskIntoConstraints = false
    deviceModeButton.setTitle("Get device info", for: .normal);
    deviceModeButton.setTitleColor(.blue, for: .normal);
    deviceModeButton.addTarget(self, action: #selector(getDeviceMode(_:)), for: .touchUpInside)
    self.view.addSubview(deviceModeButton)

    deviceModeButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    deviceModeButton.topAnchor.constraint(equalTo: signOutButton.bottomAnchor, constant: 10.0).isActive = true
    deviceModeButton.widthAnchor.constraint(equalToConstant: 150.0).isActive = true
    deviceModeButton.heightAnchor.constraint(equalToConstant: 50.0).isActive = true

    // Add logging textfield
    loggingText = UITextView()
    loggingText.isUserInteractionEnabled = false
    loggingText.translatesAutoresizingMaskIntoConstraints = false

    self.view.addSubview(loggingText)

    loggingText.topAnchor.constraint(equalTo: deviceModeButton.bottomAnchor, constant: 10.0).isActive = true
    loggingText.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 10.0).isActive = true
    loggingText.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: -10.0).isActive = true
    loggingText.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 10.0).isActive = true
}

func platformViewDidLoadSetup() {

    NotificationCenter.default.addObserver(self,
                        selector: #selector(appCameToForeGround(notification:)),
                        name: UIApplication.willEnterForegroundNotification,
                        object: nil)

}

@objc func appCameToForeGround(notification: Notification) {
    self.loadCurrentAccount()
}

uživatelské rozhraní macOS


var callGraphButton: NSButton!
var loggingText: NSTextView!
var signOutButton: NSButton!

var usernameLabel: NSTextField!

func initUI() {

    usernameLabel = NSTextField()
    usernameLabel.translatesAutoresizingMaskIntoConstraints = false
    usernameLabel.stringValue = ""
    usernameLabel.isEditable = false
    usernameLabel.isBezeled = false
    self.view.addSubview(usernameLabel)

    usernameLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 30.0).isActive = true
    usernameLabel.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -10.0).isActive = true

    // Add call Graph button
    callGraphButton  = NSButton()
    callGraphButton.translatesAutoresizingMaskIntoConstraints = false
    callGraphButton.title = "Call Microsoft Graph API"
    callGraphButton.target = self
    callGraphButton.action = #selector(callGraphAPI(_:))
    callGraphButton.bezelStyle = .rounded
    self.view.addSubview(callGraphButton)

    callGraphButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    callGraphButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 50.0).isActive = true
    callGraphButton.heightAnchor.constraint(equalToConstant: 34.0).isActive = true

    // Add sign out button
    signOutButton = NSButton()
    signOutButton.translatesAutoresizingMaskIntoConstraints = false
    signOutButton.title = "Sign Out"
    signOutButton.target = self
    signOutButton.action = #selector(signOut(_:))
    signOutButton.bezelStyle = .texturedRounded
    self.view.addSubview(signOutButton)

    signOutButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    signOutButton.topAnchor.constraint(equalTo: callGraphButton.bottomAnchor, constant: 10.0).isActive = true
    signOutButton.heightAnchor.constraint(equalToConstant: 34.0).isActive = true
    signOutButton.isEnabled = false

    // Add logging textfield
    loggingText = NSTextView()
    loggingText.translatesAutoresizingMaskIntoConstraints = false

    self.view.addSubview(loggingText)

    loggingText.topAnchor.constraint(equalTo: signOutButton.bottomAnchor, constant: 10.0).isActive = true
    loggingText.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 10.0).isActive = true
    loggingText.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: -10.0).isActive = true
    loggingText.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: -10.0).isActive = true
    loggingText.widthAnchor.constraint(equalToConstant: 500.0).isActive = true
    loggingText.heightAnchor.constraint(equalToConstant: 300.0).isActive = true
}

func platformViewDidLoadSetup() {}

Dále také uvnitř třídy ViewController nahraďte metodu viewDidLoad() následujícím kódem:

    override func viewDidLoad() {

        super.viewDidLoad()

        initUI()

        do {
            try self.initMSAL()
        } catch let error {
            self.updateLogging(text: "Unable to create Application Context \(error)")
        }

        self.loadCurrentAccount()
        self.platformViewDidLoadSetup()
    }

Další kroky

Návod: Volání chráněného webového rozhraní API v aplikaci pro iOS (Swift)

Toto je třetí kurz série kurzů, který vás provede přihlašováním uživatelů pomocí Microsoft Entra ID.

Než začnete, pomocí selektoru Zvolte typ nájemce v horní části této stránky vyberte typ nájemce. Microsoft Entra ID poskytuje dvě konfigurace tenantů, pracovní síly a externí. Konfigurace tenanta pracovních sil je určená pro zaměstnance, interní aplikace a další organizační prostředky. Externí tenant je určený pro vaše aplikace určené pro zákazníky.

V tomto kurzu:

  • Přihlaste se uživatele.
  • Odhlaste se od uživatele.

Požadavky

Přihlášení uživatele

Máte dvě hlavní možnosti pro přihlašování uživatelů pomocí knihovny MICROSOFT Authentication Library (MSAL) pro iOS: interaktivní nebo tiché získání tokenů.

  1. Pokud se chcete přihlásit uživatele interaktivně, použijte následující kód:

    acquireTokenInteractively() {
        guard let applicationContext = self.applicationContext else { return }
        guard let webViewParameters = self.webViewParameters else { return }
    
        updateLogging(text: "Acquiring token interactively...")
    
        let parameters = MSALInteractiveTokenParameters(scopes: Configuration.kScopes, webviewParameters: webViewParameters)
        parameters.promptType = .selectAccount
    
        applicationContext.acquireToken(with: parameters) { (result, error) in
    
            if let error = error {
    
                self.updateLogging(text: "Could not acquire token: \(error)")
                return
            }
    
            guard let result = result else {
    
                self.updateLogging(text: "Could not acquire token: No result returned")
                return
            }
    
            self.accessToken = result.accessToken
            self.updateLogging(text: "Access token is \(self.accessToken)")
            self.updateCurrentAccount(account: result.account)
        }
    }
    

    Kód nejprve zkontroluje, jestli jsou k dispozici kontext aplikace a parametry webového zobrazení. Následně aktualizuje záznam, aby indikoval, že token získává interaktivně. Dále nastaví parametry pro interaktivní získání tokenu a určí rozsahy a parametry webového zobrazení. Nastaví také typ výzvy k výběru účtu.

    Potom volá metodu acquireToken v kontextu aplikace s definovanými parametry. V obsluze dokončení kontroluje případné chyby. Pokud dojde k chybě, aktualizuje protokolování chybovou zprávou. V případě úspěchu načte přístupový token z výsledku, aktualizuje protokolování pomocí tokenu a aktualizuje aktuální účet.

    Jakmile vaše aplikace získá přístupový token, můžete načíst údaje spojené s aktuálním účtem. K tomu použijte následující fragment kódu:

    let claims = result.account.accountClaims
    let preferredUsername = claims?["preferred_username"] as? String
    

    Kód čte nároky z účtu přístupem k vlastnosti accountClaims objektu result.account. Potom načte hodnotu deklarace identity "preferred_username" ze slovníku deklarací identity a přiřadí ji k proměnné preferredUsername.

  2. Pokud chcete uživatele přihlásit bezobslužně, použijte následující kód:

    func acquireTokenSilently() {
        self.loadCurrentAccount { (account) in
    
            guard let currentAccount = account else {
    
                self.updateLogging(text: "No token found, try to acquire a token interactively first")
                return
            }
    
            self.acquireTokenSilently(currentAccount)
        }
    }
    

    Kód zahájí proces získání tokenů bezobslužně. Nejprve se pokusí načíst stávající účet. Pokud je nalezen aktuální účet, pokračuje se v tichém získání tokenu pomocí tohoto účtu. Pokud se nenajde žádný aktuální účet, aktualizuje protokolování tak, aby indikuje, že se nenašel žádný token, a navrhne se nejprve pokus o získání tokenu interaktivně.

    V kódu výše voláme dvě funkce, loadCurrentAccount a acquireTokenSilently. Funkce loadCurrentAccount by měla mít následující kód:

    func loadCurrentAccount(completion: AccountCompletion? = nil) {
    
        guard let applicationContext = self.applicationContext else { return }
    
        let msalParameters = MSALParameters()
        msalParameters.completionBlockQueue = DispatchQueue.main
    
        // Note that this sample showcases an app that signs in a single account at a time
        applicationContext.getCurrentAccount(with: msalParameters, completionBlock: { (currentAccount, previousAccount, error) in
    
            if let error = error {
                self.updateLogging(text: "Couldn't query current account with error: \(error)")
                return
            }
    
            if let currentAccount = currentAccount {
    
                self.updateCurrentAccount(account: currentAccount)
                self.acquireTokenSilently(currentAccount)
    
                if let completion = completion {
                    completion(self.currentAccount)
                }
    
                return
            }
    
            // If testing with Microsoft's shared device mode, see the account that has been signed out from another app. More details here:
            // https://docs.microsoft.com/azure/active-directory/develop/msal-ios-shared-devices
            if let previousAccount = previousAccount {
    
                self.updateLogging(text: "The account with username \(String(describing: previousAccount.username)) has been signed out.")
    
            } else {
    
                self.updateLogging(text: "")
            }
    
            self.accessToken = ""
            self.updateCurrentAccount(account: nil)
    
            if let completion = completion {
                completion(nil)
            }
        })
    }
    

    Kód používá MSAL pro iOS k načtení aktuálního účtu. Kontroluje chyby a odpovídajícím způsobem aktualizuje protokolování. Pokud se najde aktuální účet, aktualizuje ho a pokusí se získat tokeny bezobslužně. Pokud existuje předchozí účet, odhlásí se. Pokud nejsou nalezeny žádné účty, vymaže přístupový token. Nakonec provede blok dokončení, pokud je k dispozici.

    Funkce acquireTokenSilently by měla obsahovat následující kód:

    func acquireTokenSilently(_ account : MSALAccount) {
        guard let applicationContext = self.applicationContext else { return }
    
        /**
    
         Acquire a token for an existing account silently
    
         - forScopes:           Permissions you want included in the access token received
         in the result in the completionBlock. Not all scopes are
         guaranteed to be included in the access token returned.
         - account:             An account object that we retrieved from the application object before that the
         authentication flow will be locked down to.
         - completionBlock:     The completion block that will be called when the authentication
         flow completes, or encounters an error.
         */
    
        updateLogging(text: "Acquiring token silently...")
    
        let parameters = MSALSilentTokenParameters(scopes: Configuration.kScopes, account: account)
    
        applicationContext.acquireTokenSilent(with: parameters) { (result, error) in
    
            if let error = error {
    
                let nsError = error as NSError
    
                // interactionRequired means we need to ask the user to sign-in. This usually happens
                // when the user's Refresh Token is expired or if the user has changed their password
                // among other possible reasons.
    
                if (nsError.domain == MSALErrorDomain) {
    
                    if (nsError.code == MSALError.interactionRequired.rawValue) {
    
                        DispatchQueue.main.async {
                            self.acquireTokenInteractively()
                        }
                        return
                    }
                }
    
                self.updateLogging(text: "Could not acquire token silently: \(error)")
                return
            }
    
            guard let result = result else {
    
                self.updateLogging(text: "Could not acquire token: No result returned")
                return
            }
    
            self.accessToken = result.accessToken
            self.updateLogging(text: "Refreshed Access token is \(self.accessToken)")
            self.updateSignOutButton(enabled: true)
        }
    }
    
    

    Tato funkce používá msAL pro iOS k tichému získání tokenu pro existující účet. Po ověření applicationContextprotokoluje proces získání tokenu. Pomocí MSALSilentTokenParametersdefinuje nezbytné parametry. Pak se pokusí získat token tiše. Pokud dojde k chybám, zkontroluje požadavky na interakci uživatelů a v případě potřeby zahájí interaktivní proces. Po úspěchu aktualizuje vlastnost accessToken, zaznamená obnovený token a nakonec povolí tlačítko pro odhlášení.

Odhlásit uživatele

Pokud chcete odhlásit uživatele z aplikace pro iOS (Swift) pomocí MSAL, použijte následující kód:

   @IBAction func signOut(_ sender: UIButton) {

        guard let applicationContext = self.applicationContext else { return }

        guard let account = self.currentAccount else { return }

        guard let webViewParameters = self.webViewParameters else { return }

        updateLogging(text: "Signing out...")

        do {

            /**
             Removes all tokens from the cache for this application for the provided account

             - account:    The account to remove from the cache
             */

            let signoutParameters = MSALSignoutParameters(webviewParameters: webViewParameters)

            // If testing with Microsoft's shared device mode, trigger signout from browser. More details here:
            // https://docs.microsoft.com/azure/active-directory/develop/msal-ios-shared-devices

            if (self.currentDeviceMode == .shared) {
                signoutParameters.signoutFromBrowser = true
            } else {
                signoutParameters.signoutFromBrowser = false
            }

            applicationContext.signout(with: account, signoutParameters: signoutParameters, completionBlock: {(success, error) in

                if let error = error {
                    self.updateLogging(text: "Couldn't sign out account with error: \(error)")
                    return
                }

                self.updateLogging(text: "Sign out completed successfully")
                self.accessToken = ""
                self.updateCurrentAccount(account: nil)
            })

        }
    }

Kód ověřuje existenci applicationContext, currentAccounta webViewParameters. Potom protokoluje proces odhlášení. Kód odebere všechny tokeny z mezipaměti pro zadaný účet. V závislosti na aktuálním režimu zařízení určuje, jestli se má odhlásit z prohlížeče. Po dokončení aktualizuje protokolovací text odpovídajícím způsobem. Pokud během procesu odhlášení dojde k chybě, zaznamená chybovou zprávu. Po úspěšném odhlášení aktualizuje přístupový token na prázdný řetězec a vymaže aktuální účet.

Další kroky

Kurz: Volání chráněného webového rozhraní API v aplikaci pro iOS (Swift)