Tutorial: Inicie sessão em utilizadores e chame o Microsoft Graph a partir de uma aplicação iOS ou macOS
Neste tutorial, você cria um aplicativo iOS ou macOS que se integra à plataforma de identidade da Microsoft para assinar usuários e obter um token de acesso para chamar a API do Microsoft Graph.
Depois de concluir o tutorial, seu aplicativo aceita entradas de contas pessoais da Microsoft (incluindo outlook.com, live.com e outras) e contas corporativas ou de estudante de qualquer empresa ou organização que use o Microsoft Entra ID. Este tutorial é aplicável a aplicativos iOS e macOS. Algumas etapas são diferentes entre as duas plataformas.
Neste tutorial:
- Criar um projeto de aplicativo iOS ou macOS no Xcode
- Registar a aplicação no centro de administração do Microsoft Entra
- Adicionar código para dar suporte ao login e logout do usuário
- Adicionar código para chamar a API do Microsoft Graph
- Testar a aplicação
Pré-requisitos
Como funciona o aplicativo tutorial
O aplicativo neste tutorial pode entrar usuários e obter dados do Microsoft Graph em seu nome. Esses dados são acessados por meio de uma API protegida (Microsoft Graph API, neste caso) que requer autorização e é protegida pela plataforma de identidade da Microsoft.
Mais especificamente:
- Seu aplicativo entra no usuário por meio de um navegador ou do Microsoft Authenticator.
- O usuário final aceita as permissões solicitadas pelo aplicativo.
- Seu aplicativo recebe um token de acesso para a API do Microsoft Graph.
- O token de acesso é incluído na solicitação HTTP para a API da Web.
- Processe a resposta do Microsoft Graph.
Este exemplo usa a Microsoft Authentication Library (MSAL) para implementar a autenticação. A MSAL renovará automaticamente os tokens, fornecerá logon único (SSO) entre outros aplicativos no dispositivo e gerenciará a(s) conta(s).
Se você quiser baixar uma versão completa do aplicativo que você cria neste tutorial, você pode encontrar ambas as versões no GitHub:
- Exemplo de código do iOS (GitHub)
- Exemplo de código do macOS (GitHub)
Criar um novo projeto
- Abra o Xcode e selecione Criar um novo projeto Xcode.
- Para aplicativos iOS, selecione Aplicativo de visualização única do iOS e selecione Avançar>.
- Para aplicativos macOS, selecione macOS>Cocoa App e selecione Next.
- Forneça um nome de produto.
- Defina o idioma como Swift e selecione Avançar.
- Selecione uma pasta para criar seu aplicativo e selecione Criar.
Registar a candidatura
Gorjeta
As etapas neste artigo podem variar ligeiramente com base no portal a partir do qual você começou.
- Entre no centro de administração do Microsoft Entra como pelo menos um desenvolvedor de aplicativos.
- Se você tiver acesso a vários locatários, use o ícone Configurações no menu superior para alternar para o locatário no qual deseja registrar o aplicativo no menu Diretórios + assinaturas.
- Navegue até Registros do aplicativo Identity>Applications>.
- Selecione Novo registo.
- Introduza um Nome para a sua aplicação. Os usuários do seu aplicativo podem ver esse nome e você pode alterá-lo mais tarde.
- Selecione Contas em qualquer diretório organizacional (Qualquer diretório Microsoft Entra - Multilocatário) e contas pessoais da Microsoft (por exemplo, Skype, Xbox) em Tipos de conta suportados.
- Selecione Registar.
- Em Gerir, selecione Autenticação>Adicionar uma plataforma>iOS/macOS.
- Insira o ID do pacote do seu projeto. Se tiver baixado o exemplo de código, o ID do pacote é
com.microsoft.identitysample.MSALiOS
. Se você estiver criando seu próprio projeto, selecione seu projeto no Xcode e abra a guia Geral . O identificador do pacote aparece na seção Identidade . - Selecione Configurar e salvar a Configuração do MSAL que aparece na página de configuração do MSAL para que você possa inseri-la quando configurar seu aplicativo mais tarde.
- Selecionar Concluído.
Adicionar MSAL
Escolha uma das seguintes maneiras de instalar a biblioteca MSAL em seu aplicativo:
CacauPods
Se você estiver usando o CocoaPods, instale
MSAL
primeiro criando um arquivo vazio chamado podfile na mesma pasta do arquivo .xcodeproj do seu projeto. Adicione o seguinte ao podfile:use_frameworks! target '<your-target-here>' do pod 'MSAL' end
Substitua
<your-target-here>
pelo nome do seu projeto.Em uma janela do terminal, navegue até a pasta que contém o podfile que você criou e execute
pod install
para instalar a biblioteca MSAL.Feche o Xcode e abra
<your project name>.xcworkspace
para recarregar o projeto no Xcode.
Cartago
Se você estiver usando Carthage, instale MSAL
adicionando-o ao seu Cartfile:
github "AzureAD/microsoft-authentication-library-for-objc" "master"
Em uma janela de terminal, no mesmo diretório que o Cartfile atualizado, execute o seguinte comando para que Carthage atualize as dependências em seu projeto.
iOS:
carthage update --platform iOS
macOS:
carthage update --platform macOS
Manualmente
Você também pode usar o Submódulo Git ou verificar a versão mais recente para usar como uma estrutura em seu aplicativo.
Adicionar o registo da aplicação
Em seguida, adicionamos o registro do aplicativo ao seu código.
Primeiro, adicione a seguinte instrução import à parte superior do arquivo ViewController.swift e AppDelegate.swift ou SceneDelegate.swift:
import MSAL
Em seguida, adicione o seguinte código a ViewController.swift antes de viewDidLoad()
:
// Update the below to your client ID. 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?
O único valor que você modifica é o valor atribuído para kClientID
ser sua ID do aplicativo. Esse valor faz parte dos dados de Configuração do MSAL que você salvou durante a etapa no início deste tutorial para registrar o aplicativo.
Definir configurações do projeto Xcode
Adicione um novo grupo de chaveiros ao seu projeto Assinatura & Capacidades. O grupo de chaves deve estar com.microsoft.adalcache
no iOS e com.microsoft.identity.universalstorage
no macOS.
Apenas para iOS, configure esquemas de URL
Nesta etapa, você se registrará CFBundleURLSchemes
para que o usuário possa ser redirecionado de volta ao aplicativo após entrar. A propósito, LSApplicationQueriesSchemes
também permite que seu aplicativo use o Microsoft Authenticator.
No Xcode, abra Info.plist como um arquivo de código-fonte e adicione o seguinte dentro da <dict>
seção . Substitua [BUNDLE_ID]
pelo valor que você usou anteriormente. Se você baixou o código, o identificador do pacote é com.microsoft.identitysample.MSALiOS
. Se você estiver criando seu próprio projeto, selecione seu projeto no Xcode e abra a guia Geral . O identificador do pacote aparece na seção Identidade .
<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>
Apenas para macOS, configure o App Sandbox
- Vá para a guia>Capacidades das Configurações do >Projeto Xcode Sandbox do aplicativo
- Marque a caixa de seleção Conexões de saída (cliente ).
Crie a interface do usuário do seu aplicativo
Agora, crie uma interface do usuário que inclua um botão para chamar a API do Microsoft Graph, outro para sair e uma exibição de texto para ver alguma saída, adicionando o seguinte código à ViewController
classe:
Interface do usuário do 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()
}
Interface do usuário do 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() {}
Em seguida, também dentro da ViewController
classe, substitua o viewDidLoad()
método por:
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()
}
Usar MSAL
Inicializar MSAL
Para a ViewController
classe, adicione o initMSAL
método:
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()
}
Ainda na classe e após o ViewController
initMSAL
método, adicione o initWebViewParams
método:
Código iOS:
func initWebViewParams() {
self.webViewParameters = MSALWebviewParameters(authPresentationViewController: self)
}
Código macOS:
func initWebViewParams() {
self.webViewParameters = MSALWebviewParameters()
}
Manipular o retorno de chamada de entrada (somente iOS)
Abra o arquivo AppDelegate.swift . Para lidar com o retorno de chamada após o login, adicione MSALPublicClientApplication.handleMSALResponse
à appDelegate
classe da seguinte forma:
// 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)
}
Se você estiver usando o Xcode 11, você deve colocar o retorno de chamada MSAL no SceneDelegate.swift . Se você oferecer suporte a UISceneDelegate e UIApplicationDelegate para compatibilidade com iOS mais antigo, o retorno de chamada MSAL precisará ser colocado em ambos os arquivos.
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)
}
Adquira Tokens
Agora, podemos implementar a lógica de processamento da interface do usuário do aplicativo e obter tokens interativamente por meio do MSAL.
MSAL expõe dois métodos principais para obter tokens: acquireTokenSilently()
e acquireTokenInteractively()
.
acquireTokenSilently()
Tenta iniciar sessão num utilizador e obter tokens sem interação do utilizador, desde que exista uma conta.acquireTokenSilently()
exigem umMSALAccount
arquivo , que pode ser recuperado usando uma das APIs de enumeração de conta da MSAL. Este tutorial usaapplicationContext.getCurrentAccount(with: msalParameters, completionBlock: {})
para recuperar a conta atual.acquireTokenInteractively()
sempre mostra a interface do usuário ao tentar entrar no usuário. Ele pode usar cookies de sessão no navegador ou uma conta no autenticador da Microsoft para fornecer uma experiência de SSO interativo.
Adicione o seguinte código à ViewController
classe:
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)
}
})
}
Obtenha um token interativamente
O trecho de código a seguir obtém um token pela primeira vez criando um MSALInteractiveTokenParameters
objeto e chamando acquireToken
. Em seguida, você adiciona um código que:
- Cria
MSALInteractiveTokenParameters
com escopos. - Chamadas
acquireToken()
com os parâmetros criados. - Lida com erros. Para obter mais detalhes, consulte o guia de tratamento de erros do MSAL para iOS e macOS.
- Lida com o caso de sucesso.
Adicione o seguinte código à classe ViewController
.
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()
}
}
A promptType
propriedade de configura o comportamento do prompt de MSALInteractiveTokenParameters
autenticação e consentimento. Os seguintes valores são suportados:
.promptIfNecessary
(padrão) - O usuário é solicitado somente se necessário. A experiência de SSO é determinada pela presença de cookies na visualização da web e pelo tipo de conta. Se vários usuários estiverem conectados, a experiência de seleção de conta será apresentada. Este é o comportamento padrão..selectAccount
- Se nenhum usuário for especificado, o webview de autenticação apresentará uma lista de contas atualmente conectadas para o usuário selecionar..login
- Requer que o usuário se autentique no webview. Apenas uma conta pode ser conectada de cada vez se você especificar esse valor..consent
- Requer que o usuário consinta com o conjunto atual de escopos para a solicitação.
Obtenha um token silenciosamente
Para adquirir um token atualizado silenciosamente, adicione o seguinte código à ViewController
classe. Ele cria um MSALSilentTokenParameters
objeto e chama 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()
}
}
Chamar a API do Microsoft Graph
Depois de ter um token, seu aplicativo pode usá-lo no cabeçalho HTTP para fazer uma solicitação autorizada ao Microsoft Graph:
chave de cabeçalho | valor |
---|---|
Autorização | Token de acesso ao portador <> |
Adicione o seguinte código à ViewController
classe:
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()
}
Consulte API do Microsoft Graph para saber mais sobre a API do Microsoft Graph.
Usar o MSAL para sair
Em seguida, adicione suporte para sair.
Importante
Sair com o MSAL remove todas as informações conhecidas sobre um usuário do aplicativo, bem como remover uma sessão ativa em seu dispositivo quando permitido pela configuração do dispositivo. Opcionalmente, você também pode sair do usuário do navegador.
Para adicionar a capacidade de saída, adicione o seguinte código dentro da ViewController
classe.
@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)
})
}
}
Habilitar cache de token
Por padrão, a MSAL armazena em cache os tokens do seu aplicativo nas chaves iOS ou macOS.
Para habilitar o cache de tokens:
- Certifique-se de que o seu pedido está devidamente assinado
- Vá para a guia>Capacidades das Configurações >do Projeto Xcode Ativar Compartilhamento de Chaves
- Selecione + e insira um dos seguintes Grupos de Chaves:
- iOS:
com.microsoft.adalcache
- macOS:
com.microsoft.identity.universalstorage
- iOS:
Adicionar métodos auxiliares
Adicione os seguintes métodos auxiliares à ViewController
classe para concluir o exemplo.
Interface do usuário do iOS:
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)
}
Interface do usuário do macOS:
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)
}
Apenas iOS: obtenha informações adicionais sobre o dispositivo
Use o código a seguir para ler a configuração atual do dispositivo, incluindo se o dispositivo está configurado como compartilhado:
@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.")
}
}
Aplicações multicontas
Este aplicativo foi criado para um cenário de conta única. O MSAL também suporta cenários de várias contas, mas requer mais trabalho de aplicativo. Você precisa criar uma interface do usuário para ajudar os usuários a selecionar qual conta eles desejam usar para cada ação que requer tokens. Como alternativa, seu aplicativo pode implementar uma heurística para selecionar qual conta usar consultando todas as contas do MSAL. Por exemplo, consulte accountsFromDeviceForParameters:completionBlock:
API
Testar a sua aplicação
Crie e implante o aplicativo em um dispositivo ou simulador de teste. Você deve ser capaz de entrar e obter tokens para o Microsoft Entra ID ou contas pessoais da Microsoft.
Na primeira vez que um usuário entrar em seu aplicativo, ele será solicitado pela identidade da Microsoft a consentir com as permissões solicitadas. Embora a maioria dos usuários seja capaz de consentir, alguns locatários do Microsoft Entra desabilitaram o consentimento do usuário, que exige que os administradores consintam em nome de todos os usuários. Para dar suporte a esse cenário, registre os escopos do seu aplicativo.
Depois de entrar, o aplicativo exibirá os dados retornados do ponto de extremidade do Microsoft Graph /me
.
Próximos passos
Saiba mais sobre como criar aplicativos móveis que chamam APIs da Web protegidas em nossa série de cenários com várias partes.