Öğretici: iOS veya macOS uygulamasından kullanıcılarla oturum açma ve Microsoft Graph'ı çağırma

Bu öğreticide, kullanıcıları imzalamak ve Microsoft Graph API çağırmak için erişim belirteci almak için Microsoft kimlik platformu ile tümleşen bir iOS veya macOS uygulaması oluşturacaksınız.

Öğreticiyi tamamladığınızda uygulamanız kişisel Microsoft hesaplarının (outlook.com, live.com ve diğerleri dahil) ve Azure Active Directory kullanan herhangi bir şirket veya kuruluştaki iş veya okul hesaplarının oturum açmalarını kabul eder. Bu öğretici hem iOS hem de macOS uygulamaları için geçerlidir. Bazı adımlar iki platform arasında farklıdır.

Bu öğreticide:

  • Xcode'da iOS veya macOS uygulama projesi oluşturma
  • Uygulamayı Azure portal kaydetme
  • Kullanıcı oturum açma ve oturumu kapatmayı desteklemek için kod ekleme
  • Microsoft Graph API çağırmak için kod ekleme
  • Uygulamayı test etme

Önkoşullar

Öğretici uygulaması nasıl çalışır?

Bu öğretici tarafından oluşturulan örnek uygulamanın nasıl çalıştığını gösterir

Bu öğreticideki uygulama, kullanıcılarda oturum açabilir ve kendi adlarına Microsoft Graph'tan veri alabilir. Bu verilere yetkilendirme gerektiren ve Microsoft kimlik platformu tarafından korunan bir korumalı API (bu örnekte Microsoft Graph API) üzerinden erişilir.

Daha ayrıntılı belirtmek gerekirse:

  • Uygulamanız bir tarayıcı veya Microsoft Authenticator aracılığıyla kullanıcıda oturum açar.
  • Son kullanıcı, uygulamanızın istediği izinleri kabul eder.
  • Uygulamanıza Microsoft Graph API için bir erişim belirteci verilir.
  • Erişim belirteci, web API'sine yapılan HTTP isteğine dahil edilecek.
  • Microsoft Graph yanıtını işleme.

Bu örnek, Kimlik Doğrulaması uygulamak için Microsoft Kimlik Doğrulama Kitaplığı'nı (MSAL) kullanır. MSAL belirteçleri otomatik olarak yeniler, cihazdaki diğer uygulamalar arasında çoklu oturum açma (SSO) sunar ve hesapları yönetir.

Bu öğreticide oluşturduğunuz uygulamanın tamamlanmış bir sürümünü indirmek isterseniz her iki sürümü de GitHub'da bulabilirsiniz:

Yeni proje oluşturma

  1. Xcode'u açın ve Yeni bir Xcode projesi oluştur'u seçin.
  2. iOS uygulamaları için iOS>Tek görünüm Uygulaması'nı ve ardından İleri'yi seçin.
  3. macOS uygulamaları için macOS>Cocoa Uygulaması'nı ve ardından İleri'yi seçin.
  4. Ürün adı girin.
  5. Dil'iSwift olarak ayarlayın ve İleri'yi seçin.
  6. Uygulamanızı oluşturmak için bir klasör seçin ve Oluştur'u seçin.

Uygulamanızı kaydetme

  1. Azure Portal’ında oturum açın.
  2. Birden çok kiracıya erişiminiz varsa, uygulamayı kaydetmek istediğiniz kiracıya geçmek için üst menüdeki Dizinler + abonelikler filtresini kullanın.
  3. Azure Active Directory'yi bulun ve seçin.
  4. Yönet'in altında Uygulama kayıtları>Yeni kayıt'ı seçin.
  5. Uygulamanız için bir Ad girin. Uygulamanızın kullanıcıları bu adı görebilir ve daha sonra değiştirebilirsiniz.
  6. Desteklenen hesap türlerialtında herhangi bir kuruluş dizininde (Herhangi bir Azure AD dizini - Çok kiracılı) ve kişisel Microsoft hesaplarında (örneğin Skype, Xbox) Hesaplar'ı seçin.
  7. Kaydet’i seçin.
  8. Yönet'in altında Kimlik Doğrulaması>Platform> ekleiOS/macOS'i seçin.
  9. Projenizin Paket Kimliğini girin. Kod örneği indirildiyse Paket Kimliği şeklindedir com.microsoft.identitysample.MSALiOS. Kendi projenizi oluşturuyorsanız, Xcode'da projenizi seçin ve Genel sekmesini açın. Paket tanımlayıcısı Kimlik bölümünde görünür.
  10. Yapılandır'ı seçin ve daha sonra uygulamanızı yapılandırırken girebilmeniz için MSAL yapılandırma sayfasında görüntülenen MSALYapılandırmasını kaydedin.
  11. Bitti seçeneğini belirleyin.

MSAL Ekleme

Uygulamanıza MSAL kitaplığını yüklemenin aşağıdaki yollarından birini seçin:

CocoaPods

  1. CocoaPods kullanıyorsanız, önce projenizin .xcodeproj dosyasıyla aynı klasörde podfile adlı boş bir dosya oluşturarak yükleyinMSAL. Podfile'a aşağıdakileri ekleyin:

    use_frameworks!
    
    target '<your-target-here>' do
       pod 'MSAL'
    end
    
  2. değerini projenizin adıyla değiştirin <your-target-here> .

  3. Terminal penceresinde, oluşturduğunuz pod dosyasını içeren klasöre gidin ve MSAL kitaplığını yüklemek için çalıştırın pod install .

  4. Projeyi Xcode'da yeniden yüklemek için Xcode'ı kapatın ve açın <your project name>.xcworkspace .

Kartaca

Kartaj kullanıyorsanız Kartfile'ınıza ekleyerek yükleyinMSAL:

github "AzureAD/microsoft-authentication-library-for-objc" "master"

Güncelleştirilmiş Cartfile ile aynı dizinde bir terminal penceresinden aşağıdaki komutu çalıştırarak Carthage'ın projenizdeki bağımlılıkları güncelleştirmesini sağlayın.

iOS:

carthage update --platform iOS

Macos:

carthage update --platform macOS

El ile

Ayrıca Git Alt Modül'ünüzü kullanabilir veya uygulamanızda çerçeve olarak kullanmak için en son sürümü gözden geçirin.

Uygulama kaydınızı ekleme

Ardından uygulama kaydınızı kodunuza ekleyeceğiz.

İlk olarak, ViewController.swift dosyasının ve AppDelegate.swift veya SceneDelegate.swift dosyasının en üstüne aşağıdaki içeri aktarma deyimini ekleyin:

import MSAL

Ardından, aşağıdaki kodu viewcontroller.swift'eviewDidLoad()ekleyin:

// Update the below to your client ID you received in the portal. The below is for running the demo only
let kClientID = "Your_Application_Id_Here"
let kGraphEndpoint = "https://graph.microsoft.com/" // the Microsoft Graph endpoint
let kAuthority = "https://login.microsoftonline.com/common" // this authority allows a personal Microsoft account and a work or school account in any organization's Azure AD tenant to sign in

let kScopes: [String] = ["user.read"] // request permission to read the profile of the signed-in user

var accessToken = String()
var applicationContext : MSALPublicClientApplication?
var webViewParameters : MSALWebviewParameters?
var currentAccount: MSALAccount?

Yukarıda değiştirdiğiniz tek değer, Uygulama Kimliğiniz olmak üzere kClientID atanan değerdir. Bu değer, uygulamayı Azure portal kaydetmek için bu öğreticinin başındaki adımda kaydettiğiniz MSAL Yapılandırma verilerinin bir parçasıdır.

Xcode proje ayarlarını yapılandırma

Projenizin İmzalama & Özellikleri'ne yeni bir anahtarlık grubu ekleyin. Anahtarlık grubu iOS ve com.microsoft.identity.universalstorage macOS üzerinde olmalıdırcom.microsoft.adalcache.

Anahtarlık grubunun nasıl ayarlanması gerektiğini gösteren Xcode kullanıcı arabirimi

Yalnızca iOS için URL düzenlerini yapılandırın

Bu adımda, kullanıcının oturum açma sonrasında uygulamaya geri yönlendirebilmesi için kaydolacaksınız CFBundleURLSchemes . Bu arada, LSApplicationQueriesSchemes uygulamanızın Microsoft Authenticator'ı kullanmasına da izin verir.

Xcode'da Info.plist dosyasını kaynak kod dosyası olarak açın ve bölümün <dict> içine aşağıdakileri ekleyin. değerini Azure portal kullandığınız değerle değiştirin[BUNDLE_ID]. Kodu indirdiyseniz paket tanımlayıcısı şeklindedir com.microsoft.identitysample.MSALiOS. Kendi projenizi oluşturuyorsanız, Xcode'da projenizi seçin ve Genel sekmesini açın. Paket tanımlayıcısı Kimlik bölümünde görünür.

<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>msauth.[BUNDLE_ID]</string>
        </array>
    </dict>
</array>
<key>LSApplicationQueriesSchemes</key>
<array>
    <string>msauthv2</string>
    <string>msauthv3</string>
</array>

Yalnızca macOS için Uygulama Korumalı Alanını yapılandırın

  1. Xcode Proje Ayarları >Özellikleri sekmesi>Uygulama Korumalı Alanı'na gidin
  2. Giden Bağlantılar (İstemci) onay kutusunu seçin.

Uygulamanızın kullanıcı arabirimini oluşturma

Şimdi microsoft Graph API çağırmak için bir düğme, oturumu kapatmak için başka bir düğme ve sınıfa aşağıdaki kodu ViewController ekleyerek bazı çıkışları görmek için bir metin görünümü içeren bir kullanıcı arabirimi oluşturun:

iOS kullanıcı arabirimi

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()
}

macOS kullanıcı arabirimi


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() {}

Ardından, sınıfının içinde ViewController de yöntemini şununla viewDidLoad() değiştirin:

    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()
    }

MSAL kullanma

MSAL'ı başlatma

sınıfına ViewController yöntemini ekleyin initMSAL :

    func initMSAL() throws {

        guard let authorityURL = URL(string: kAuthority) else {
            self.updateLogging(text: "Unable to create authority URL")
            return
        }

        let authority = try MSALAADAuthority(url: authorityURL)

        let msalConfiguration = MSALPublicClientApplicationConfig(clientId: kClientID, redirectUri: nil, authority: authority)
        self.applicationContext = try MSALPublicClientApplication(configuration: msalConfiguration)
        self.initWebViewParams()
    }

ViewController Hala sınıfında ve yönteminden initMSAL sonra yöntemini ekleyininitWebViewParams:

iOS kodu:

func initWebViewParams() {
        self.webViewParameters = MSALWebviewParameters(authPresentationViewController: self)
    }

macOS kodu:

func initWebViewParams() {
        self.webViewParameters = MSALWebviewParameters()
    }

Oturum açma geri aramasını işleme (yalnızca iOS)

AppDelegate.swift dosyasını açın. Oturum açma sonrasında geri çağırmayı işlemek için sınıfına appDelegate şu şekilde ekleyinMSALPublicClientApplication.handleMSALResponse:

// 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)
}

Xcode 11 kullanıyorsanız, bunun yerine SceneDelegate.swift'e MSAL geri çağırması yerleştirmeniz gerekir. Eski iOS ile uyumluluk için hem UISceneDelegate hem de UIApplicationDelegate'i destekliyorsanız, MSAL geri çağırmanın her iki dosyaya da yerleştirilmesi gerekir.

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)
    }

Belirteçleri Alma

Artık uygulamanın kullanıcı arabirimi işleme mantığını uygulayabilir ve MSAL aracılığıyla etkileşimli olarak belirteçler alacağız.

MSAL, belirteçleri almak için iki birincil yöntemi kullanıma sunar: acquireTokenSilently() ve acquireTokenInteractively().

  • acquireTokenSilently() bir hesap mevcut olduğu sürece kullanıcı etkileşimi olmadan bir kullanıcı oturumu açmaya ve belirteçleri almaya çalışır. acquireTokenSilently() MSAL'nin hesap numaralandırma API'lerinden biri kullanılarak alınabilecek geçerli MSALAccount bir değer gerektirir. Bu öğreticide geçerli hesabı almak için kullanılır applicationContext.getCurrentAccount(with: msalParameters, completionBlock: {}) .

  • acquireTokenInteractively() kullanıcı oturum açmaya çalışırken her zaman kullanıcı arabirimini gösterir. Etkileşimli bir SSO deneyimi sağlamak için tarayıcıda oturum tanımlama bilgilerini veya Microsoft kimlik doğrulayıcıdaki bir hesabı kullanabilir.

Sınıfına ViewController aşağıdaki kodu ekleyin:

    func getGraphEndpoint() -> String {
        return kGraphEndpoint.hasSuffix("/") ? (kGraphEndpoint + "v1.0/me/") : (kGraphEndpoint + "/v1.0/me/");
    }

    @objc func callGraphAPI(_ sender: AnyObject) {

        self.loadCurrentAccount { (account) in

            guard let currentAccount = account else {

                // We check to see if we have a current logged in account.
                // If we don't, then we need to sign someone in.
                self.acquireTokenInteractively()
                return
            }

            self.acquireTokenSilently(currentAccount)
        }
    }

    typealias AccountCompletion = (MSALAccount?) -> Void

    func loadCurrentAccount(completion: AccountCompletion? = nil) {

        guard let applicationContext = self.applicationContext else { return }

        let msalParameters = MSALParameters()
        msalParameters.completionBlockQueue = DispatchQueue.main

        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.updateLogging(text: "Found a signed in account \(String(describing: currentAccount.username)). Updating data for that account...")

                self.updateCurrentAccount(account: currentAccount)

                if let completion = completion {
                    completion(self.currentAccount)
                }

                return
            }

            self.updateLogging(text: "Account signed out. Updating UX")
            self.accessToken = ""
            self.updateCurrentAccount(account: nil)

            if let completion = completion {
                completion(nil)
            }
        })
    }

Etkileşimli olarak belirteç alma

Aşağıdaki kod parçacığı, bir nesnesi oluşturup çağırarak acquireTokenilk kez bir MSALInteractiveTokenParameters belirteç alır. Ardından şu kodu ekleyeceksiniz:

  1. Kapsamlarla oluşturur MSALInteractiveTokenParameters .
  2. Oluşturulan parametrelerle çağrılar acquireToken() .
  3. Hataları işler. Daha fazla ayrıntı için iOS ve macOS için MSAL hata işleme kılavuzuna bakın.
  4. Başarılı olayı işler.

Aşağıdaki kodu ViewController sınıfına ekleyin.

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()
    }
}

promptType özelliğiMSALInteractiveTokenParameters, kimlik doğrulaması ve onay istemi davranışını yapılandırmaktadır. Aşağıdaki değerler desteklenir:

  • .promptIfNecessary (varsayılan) - Kullanıcıdan yalnızca gerekirse istenir. SSO deneyimi, web görünümünde tanımlama bilgilerinin bulunmasına ve hesap türüne göre belirlenir. Birden çok kullanıcı oturum açtıysa hesap seçimi deneyimi sunulur. Bu varsayılan davranıştır.
  • .selectAccount - Kullanıcı belirtilmezse, kimlik doğrulama web görünümü kullanıcının seçebilmek için şu anda oturum açmış olan hesapların listesini sunar.
  • .login - Kullanıcının web görünümünde kimlik doğrulamasını gerektirir. Bu değeri belirtirseniz aynı anda yalnızca bir hesap oturum açabilir.
  • .consent - Kullanıcının istek için geçerli kapsam kümesini onaylamasını gerektirir.

Belirteci sessizce alma

Güncelleştirilmiş belirteci sessizce almak için sınıfına ViewController aşağıdaki kodu ekleyin. Bir MSALSilentTokenParameters nesnesi oluşturur ve öğesini çağırır acquireTokenSilent():


    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()
        }
    }

Microsoft Graph API'ı çağırma

Bir belirteciniz olduğunda, uygulamanız bunu HTTP üst bilgisinde kullanarak Microsoft Graph'a yetkili bir istekte bulunabilir:

üst bilgi anahtarı değer
Yetkilendirme Taşıyıcı <erişim belirteci>

Sınıfına ViewController aşağıdaki kodu ekleyin:

    func getContentWithToken() {

        // Specify the Graph API endpoint
        let graphURI = getGraphEndpoint()
        let url = URL(string: graphURI)
        var request = URLRequest(url: url!)

        // Set the Authorization header for the request. We use Bearer tokens, so we specify Bearer + the token we got from the result
        request.setValue("Bearer \(self.accessToken)", forHTTPHeaderField: "Authorization")

        URLSession.shared.dataTask(with: request) { data, response, error in

            if let error = error {
                self.updateLogging(text: "Couldn't get graph result: \(error)")
                return
            }

            guard let result = try? JSONSerialization.jsonObject(with: data!, options: []) else {

                self.updateLogging(text: "Couldn't deserialize result JSON")
                return
            }

            self.updateLogging(text: "Result from Graph: \(result))")

            }.resume()
    }

Microsoft Graph API hakkında daha fazla bilgi edinmek için bkz. Microsoft Graph API.

Oturumu Kapatma için MSAL kullanma

Ardından, oturumu kapatma desteği ekleyin.

Önemli

MSAL ile oturum kapatıldığında, kullanıcı hakkında bilinen tüm bilgiler uygulamadan kaldırılır ve cihaz yapılandırmasına izin verildiğinde cihazında etkin bir oturum kaldırılır. İsterseniz kullanıcının tarayıcıdan oturumunu kapatabilirsiniz.

Oturum kapatma özelliği eklemek için sınıfına aşağıdaki kodu ViewController ekleyin.

@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)
            })

        }
    }

Belirteç önbelleğe almayı etkinleştirme

Varsayılan olarak, MSAL uygulamanızın belirteçlerini iOS veya macOS anahtar zincirinde önbelleğe alır.

Belirteç önbelleğe almayı etkinleştirmek için:

  1. Uygulamanızın düzgün imzalandığından emin olun
  2. Xcode Proje Ayarları >Özellikleri sekmenize> gidinAnahtarlık Paylaşımını Etkinleştir
  3. Aşağıdaki Anahtarlık Gruplarından birini seçin + ve girin:
    • Ios: com.microsoft.adalcache
    • Macos: com.microsoft.identity.universalstorage

Yardımcı yöntemler ekleme

Örneği tamamlamak için sınıfına ViewController aşağıdaki yardımcı yöntemleri ekleyin.

iOS kullanıcı arabirimi:


    func updateLogging(text : String) {

        if Thread.isMainThread {
            self.loggingText.text = text
        } else {
            DispatchQueue.main.async {
                self.loggingText.text = text
            }
        }
    }

    func updateSignOutButton(enabled : Bool) {
        if Thread.isMainThread {
            self.signOutButton.isEnabled = enabled
        } else {
            DispatchQueue.main.async {
                self.signOutButton.isEnabled = enabled
            }
        }
    }

    func updateAccountLabel() {

        guard let currentAccount = self.currentAccount else {
            self.usernameLabel.text = "Signed out"
            return
        }

        self.usernameLabel.text = currentAccount.username
    }

    func updateCurrentAccount(account: MSALAccount?) {
        self.currentAccount = account
        self.updateAccountLabel()
        self.updateSignOutButton(enabled: account != nil)
    }

macOS kullanıcı arabirimi:

    func updateLogging(text : String) {

        if Thread.isMainThread {
            self.loggingText.string = text
        } else {
            DispatchQueue.main.async {
                self.loggingText.string = text
            }
        }
    }

    func updateSignOutButton(enabled : Bool) {
        if Thread.isMainThread {
            self.signOutButton.isEnabled = enabled
        } else {
            DispatchQueue.main.async {
                self.signOutButton.isEnabled = enabled
            }
        }
    }

     func updateAccountLabel() {

         guard let currentAccount = self.currentAccount else {
            self.usernameLabel.stringValue = "Signed out"
            return
        }

        self.usernameLabel.stringValue = currentAccount.username ?? ""
        self.usernameLabel.sizeToFit()
     }

     func updateCurrentAccount(account: MSALAccount?) {
        self.currentAccount = account
        self.updateAccountLabel()
        self.updateSignOutButton(enabled: account != nil)
    }

Yalnızca iOS: Ek cihaz bilgilerini alma

Cihazın paylaşılan olarak yapılandırılıp yapılandırılmadığı da dahil olmak üzere geçerli cihaz yapılandırmasını okumak için aşağıdaki kodu kullanın:

    @objc func getDeviceMode(_ sender: AnyObject) {

        if #available(iOS 13.0, *) {
            self.applicationContext?.getDeviceInformation(with: nil, completionBlock: { (deviceInformation, error) in

                guard let deviceInfo = deviceInformation else {
                    self.updateLogging(text: "Device info not returned. Error: \(String(describing: error))")
                    return
                }

                let isSharedDevice = deviceInfo.deviceMode == .shared
                let modeString = isSharedDevice ? "shared" : "private"
                self.updateLogging(text: "Received device info. Device is in the \(modeString) mode.")
            })
        } else {
            self.updateLogging(text: "Running on older iOS. GetDeviceInformation API is unavailable.")
        }
    }

Çok hesaplı uygulamalar

Bu uygulama tek bir hesap senaryosu için oluşturulmuş. MSAL, çok hesaplı senaryoları da destekler, ancak daha fazla uygulama çalışması gerektirir. Kullanıcıların belirteç gerektiren her eylem için hangi hesabı kullanmak istediklerini seçmelerine yardımcı olmak için kullanıcı arabirimi oluşturmanız gerekir. Alternatif olarak uygulamanız, MSAL'den tüm hesapları sorgulayarak hangi hesabın kullanılacağını seçmek için bir buluşsal yöntem uygulayabilir. Örneğin, bkz. accountsFromDeviceForParameters:completionBlock:API

Uygulamanızı test etme

Uygulamayı derleyin ve bir test cihazına veya simülatörüne dağıtın. Oturum açabilmeniz ve Azure AD veya kişisel Microsoft hesapları için belirteçler alabilmeniz gerekir.

Bir kullanıcı uygulamanızda ilk kez oturum açtığında, microsoft kimliği tarafından istenen izinleri onaylaması istenir. Kullanıcıların çoğu onay verebilirken, bazı Azure AD kiracıları, yöneticilerin tüm kullanıcılar adına onay vermelerini gerektiren kullanıcı onayını devre dışı bırakmıştır. Bu senaryoyu desteklemek için uygulamanızın kapsamlarını Azure portal kaydedin.

Oturum açtığınızda uygulama, Microsoft Graph /me uç noktasından döndürülen verileri görüntüler.

Sonraki adımlar

Çok parçalı senaryo serimizde korumalı web API'lerini çağıran mobil uygulamalar oluşturma hakkında daha fazla bilgi edinin.