MSAL 1.4.2

MSAL 1.4.2

测试已测试
语言语言 Obj-CObjective C
许可 MIT
发布日期最新发布2024年8月

KaiHieu NguyenBrandon WernerOlga DaltonjasoncoolmaxMSAL CocoaPods 发布自动化Serhii DemchenkoMSAL CocoaPods 发布自动化Jason KimRohit Narula维护。



MSAL 1.4.2

Microsoft Authentication Library for iOS and macOS

入门指南 iOS 示例代码 macOS 示例代码 B2C 示例代码 库参考 支持 反馈

适用于 iOS 和 macOS 的 MSAL 库使您的应用程序能够通过支持使用行业标准 OAuth2 和 OpenID Connect 的统一体验,开始使用Microsoft Identity 平台 以及 Azure Active Directory 和 Microsoft 账户。该库还支持使用我们的托管身份管理服务的 Azure AD B2C

快速示例

Swift

let config = MSALPublicClientApplicationConfig(clientId: "<your-client-id-here>")
let scopes = ["your-scope1-here", "your-scope2-here"]
        
if let application = try? MSALPublicClientApplication(configuration: config) {
            
	#if os(iOS)
	let viewController = ... // Pass a reference to the view controller that should be used when getting a token interactively
	let webviewParameters = MSALWebviewParameters(authPresentationViewController: viewController)
	#else
	let webviewParameters = MSALWebviewParameters()
	#endif
	
	let interactiveParameters = MSALInteractiveTokenParameters(scopes: scopes, webviewParameters: webviewParameters)
	application.acquireToken(with: interactiveParameters, completionBlock: { (result, error) in
                
	guard let authResult = result, error == nil else {
		print(error!.localizedDescription)
		return
	}
                
	// Get access token from result
	let accessToken = authResult.accessToken
                
	// You'll want to get the account identifier to retrieve and reuse the account for later acquireToken calls
	let accountIdentifier = authResult.account.identifier
	})
}
else {
	print("Unable to create application.")
}

Objective-C

NSError *msalError = nil;
    
MSALPublicClientApplicationConfig *config = [[MSALPublicClientApplicationConfig alloc] initWithClientId:@"<your-client-id-here>"];
NSArray<NSString *> *scopes = @[@"your-scope1-here", @"your-scope2-here"];
    
MSALPublicClientApplication *application = [[MSALPublicClientApplication alloc] initWithConfiguration:config error:&msalError];
    
#if TARGET_OS_IPHONE
    UIViewController *viewController = ...; // Pass a reference to the view controller that should be used when getting a token interactively
    MSALWebviewParameters *webParameters = [[MSALWebviewParameters alloc] initWithAuthPresentationViewController:viewController];
#else
    MSALWebviewParameters *webParameters = [MSALWebviewParameters new];
#endif
    
MSALInteractiveTokenParameters *interactiveParams = [[MSALInteractiveTokenParameters alloc] initWithScopes:scopes webviewParameters:webParameters];
[application acquireTokenWithParameters:interactiveParams completionBlock:^(MSALResult *result, NSError *error) {
    if (!error)
    {
        // You'll want to get the account identifier to retrieve and reuse the account
        // for later acquireToken calls
        NSString *accountIdentifier = result.account.identifier;
            
        NSString *accessToken = result.accessToken;
    }
    else
    {
        // Check the error
    }
}];

安装

使用 CocoaPods

您可以通过将 MSAL 添加到您的 Podfile 中的 target 来使用 CocoaPods 安装它。

use_frameworks!
 
target 'your-target-here' do
	pod 'MSAL'
end

使用 Carthage

您可以通过将 MSAL 添加到您的 Cartfile 来使用 Carthage 安装它。

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

使用 Swift 包

您可以将 MSAL 作为 swift package 依赖项 添加。对于 MSAL 版本 1.1.14 及以上版本,将 MSAL 二进制框架作为 Swift 包进行分发是可用的。

  1. 在 Xcode 中,点击 文件 → Swift Packages → 添加包依赖项...
  2. 选择添加依赖项的项目
  3. 请输入:https://github.com/AzureAD/microsoft-authentication-library-for-objc 作为包存储库 URL
  4. 选择带有
    1. 规则 → 分支:master(最新 MSAL 发布版)
    2. 规则 → 版本 → 精确:[发布版本 >= 1.1.14](特定发布版本)

对于任何问题,请检查是否存在未解决的 SPM/Xcode 缺陷。一些我们遇到的错误的工作解决方案

  • 如果您在项目中有一个插件,您可能会遇到 CFBundleIdentifier 冲突 错误。每个包必须具有唯一的包标识符。解决方案
  • 在存档时出错:“IPA 处理失败” UserInfo={NSLocalizedDescription=IPA 处理失败}。 解决方案
  • 对于 macOS 应用,“命令码签名失败,非零退出码”错误。 解决方案

手动

您还可以使用 Git Submodule 或检出最新版本并将其作为框架用于您的应用程序。

配置 MSAL

将MSAL添加到您的项目中

  1. Azure门户 注册您的应用
  2. 确保您为您的应用注册了一个重定向URI。它应该采用以下格式

msauth.$(PRODUCT_BUNDLE_IDENTIFIER)://auth

  1. 在您的项目功能中添加一个新的密钥链组。在iOS上密钥链组应该是 com.microsoft.adalcache,在macOS上是 com.microsoft.identity.universalstorage

有关 密钥链组MSAL的静默SSO 的更多信息,请参阅。

仅限iOS步骤

  1. 将应用程序的重定向URI方案添加到您的 Info.plist 文件中
<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>msauth.$(PRODUCT_BUNDLE_IDENTIFIER)</string>
        </array>
    </dict>
</array>
  1. 添加 LSApplicationQueriesSchemes 允许调用已安装的Microsoft Authenticator。

注意,当使用Xcode 11及更高版本编译您的应用时,需要“msauthv3”方案。

<key>LSApplicationQueriesSchemes</key>
<array>
	<string>msauthv2</string>
	<string>msauthv3</string>
</array>

有关 配置MSAL的重定向URI 的更多信息,请参阅。

  1. 要处理回调,请在 appDelegate 中添加以下内容

Swift

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        
	return MSALPublicClientApplication.handleMSALResponse(url, sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String)
}

Objective-C

- (BOOL)application:(UIApplication *)app
            openURL:(NSURL *)url
            options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
    return [MSALPublicClientApplication handleMSALResponse:url 
                                         sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey]];
}

注意,如果您在iOS 13+上采用了UISceneDelegate,MSAL回调必须放在UISceneDelegate的相应委托方法中,而不是AppDelegate中。MSAL的handleMSALResponse:sourceApplication:在每个URL中必须调用一次。如果为了与旧版iOS的兼容性支持UISceneDelegate和UIApplicationDelegate,MSAL回调需要放置在两个文件中。

Swift

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

Objective-C

- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts
{
    UIOpenURLContext *context = URLContexts.anyObject;
    NSURL *url = context.URL;
    NSString *sourceApplication = context.options.sourceApplication;
    
    [MSALPublicClientApplication handleMSALResponse:url sourceApplication:sourceApplication];
}

macOS仅步骤

  1. 确保您的应用程序已使用有效的开发证书签名。虽然MSAL在没有签名的模式下仍然可以工作,但它会在缓存持久性方面表现不同。

使用MSAL

创建应用程序对象

在使用MSALPublicClientApplication对象初始化时使用您的应用程序列表中的客户端ID。

Swift

let config = MSALPublicClientApplicationConfig(clientId: "<your-client-id-here>")
let application = try? MSALPublicClientApplication(configuration: config) 

Objective-C

NSError *msalError = nil;
    
MSALPublicClientApplicationConfig *config = [[MSALPublicClientApplicationConfig alloc] initWithClientId:@"<your-client-id-here>"];
MSALPublicClientApplication *application = [[MSALPublicClientApplication alloc] initWithConfiguration:config error:&msalError];
    

交互式地获取您的第一个令牌

Swift

#if os(iOS)
	let viewController = ... // Pass a reference to the view controller that should be used when getting a token interactively
	let webviewParameters = MSALWebviewParameters(authPresentationViewController: viewController)
#else
	let webviewParameters = MSALWebviewParameters()
#endif
let interactiveParameters = MSALInteractiveTokenParameters(scopes: scopes, webviewParameters: webviewParameters)
application.acquireToken(with: interactiveParameters, completionBlock: { (result, error) in
                
	guard let authResult = result, error == nil else {
		print(error!.localizedDescription)
		return
	}
                
	// Get access token from result
	let accessToken = authResult.accessToken
                
	// You'll want to get the account identifier to retrieve and reuse the account for later acquireToken calls
	let accountIdentifier = authResult.account.identifier
})

Objective-C

#if TARGET_OS_IPHONE
    UIViewController *viewController = ...; // Pass a reference to the view controller that should be used when getting a token interactively
    MSALWebviewParameters *webParameters = [[MSALWebviewParameters alloc] initWithAuthPresentationViewController:viewController];
#else
    MSALWebviewParameters *webParameters = [MSALWebviewParameters new];
#endif 

MSALInteractiveTokenParameters *interactiveParams = [[MSALInteractiveTokenParameters alloc] initWithScopes:scopes webviewParameters:webParameters];
[application acquireTokenWithParameters:interactiveParams completionBlock:^(MSALResult *result, NSError *error) {
	if (!error)	
	{
		// You'll want to get the account identifier to retrieve and reuse the account
		// for later acquireToken calls
		NSString *accountIdentifier = result.account.identifier;
            
		NSString *accessToken = result.accessToken;
	}
  	else
	{
		// Check the error
	}
}];

我们的库默认使用ASWebAuthenticationSession在iOS 12上执行身份验证。请参阅关于默认值和其他iOS版本支持的更多信息。

静默获取更新令牌

Swift

guard let account = try? application.account(forIdentifier: accountIdentifier) else { return }
let silentParameters = MSALSilentTokenParameters(scopes: scopes, account: account)
application.acquireTokenSilent(with: silentParameters) { (result, error) in
            
	guard let authResult = result, error == nil else {
                
	let nsError = error! as NSError
                
		if (nsError.domain == MSALErrorDomain &&
			nsError.code == MSALError.interactionRequired.rawValue) {
                    
			// Interactive auth will be required
			return
		}
		return
	}
            
	// Get access token from result
	let accessToken = authResult.accessToken
}

Objective-C

NSError *error = nil;
MSALAccount *account = [application accountForIdentifier:accountIdentifier error:&error];
if (!account)
{
    // handle error
    return;
}
    
MSALSilentTokenParameters *silentParams = [[MSALSilentTokenParameters alloc] initWithScopes:scopes account:account];
[application acquireTokenSilentWithParameters:silentParams completionBlock:^(MSALResult *result, NSError *error) {
    if (!error)
    {
        NSString *accessToken = result.accessToken;
    }
    else
    {
        // Check the error
        if ([error.domain isEqual:MSALErrorDomain] && error.code == MSALErrorInteractionRequired)
        {
            // Interactive auth will be required
        }
            
        // Other errors may require trying again later, or reporting authentication problems to the user
    }
}];

响应交互所需错误

偶尔需要用户交互来获取新的访问令牌,此时在尝试静默获取新令牌时会收到一个MSALErrorInteractionRequired错误。在这种情况下,调用与失败的acquireTokenSilent:调用相同的帐户和范围进行acquireToken:调用。建议在调用交互式的acquireToken:调用之前,以不引人注目的方式向用户显示状态消息。

有关更多信息,请参阅MSAL错误处理指南

面向苹果设备的Microsoft企业单点登录插件

微软最近发布了一款新插件,该插件使用了苹果最近宣布的新功能企业单点登录。面向苹果设备的Microsoft企业单点登录插件提供了以下优势

  • 自动随Microsoft Authenticator应用提供,并可由任何MDM启用。
  • 为所有支持苹果企业单点登录功能的 uygulamalarda Active Directory加入的账户提供无缝单点登录。
  • 即将推出:在整个设备上的Safari浏览器和应用中提供无缝单点登录。

从版本1.1.0开始的MSAL将自动使用面向苹果设备的Microsoft企业单点登录插件,而不是设备上启用的Microsoft Authenticator应用。要在您的租户中使用面向苹果设备的Microsoft企业单点登录插件,您需要在MDM配置文件中启用它。

有关在设备上配置Microsoft企业单点登录插件的更多信息,请参阅这里

单一账户模式

如果您的应用需要在同一时间只支持一个登录的用户,MSAL提供了读取已登录账户的简单方法。当您构建在共享设备上运行的应用程序时,也必须使用此API,这意味着一个企业设备由多个员工共享。员工可以登录到他们的设备并快速访问客户信息。在他们完成班次或任务后,他们将能够退出共享设备上的所有应用程序。

以下是一个代码片段,说明如何检索当前账户。您必须每次应用进入前台或在进行敏感操作前调用API,以检测任何已登录账户的更改。

Swift

let msalParameters = MSALParameters()
msalParameters.completionBlockQueue = DispatchQueue.main
                
application.getCurrentAccount(with: msalParameters, completionBlock: { (currentAccount, previousAccount, error) in
            
	// currentAccount is the currently signed in account
	// previousAccount is the previously signed in account if any
})

Objective-C

MSALParameters *parameters = [MSALParameters new];
parameters.completionBlockQueue = dispatch_get_main_queue();
        
[application getCurrentAccountWithParameters:parameters
                             completionBlock:^(MSALAccount * _Nullable account, MSALAccount * _Nullable previousAccount, NSError * _Nullable error)
{
	// currentAccount is the currently signed in account
	// previousAccount is the previously signed in account if any
}];

多账户模式

MSAL还提供了一个公共API来查询多个账户,前提是它们存在于MSAL缓存中。

  1. 请确保已导入名为MSAL-umbrella.h的伞形头文件(Swift中的仅为MSAL)

  2. 创建配置文件,然后使用它初始化应用程序对象

  3. 然后使用账户标识符初始化MSALAccount Enumeration Parameters对象。每个MSALAccount对象都有一个名为“identifier”的参数,它表示与给定的MSALAccount对象关联的唯一账户标识符。我们建议将其用作主要搜索标准。

  4. 然后使用枚举参数从应用程序对象中调用“accountsFromDeviceForParameters”API。如果您在MSAL缓存中有多个账户,它将返回包含具有您在上一步骤中指定的账户标识符的MSALAccount的数组。

  5. 一旦检索到MSAL账户,调用获取令牌的静默操作

Swift

#import MSAL //Make sure to import MSAL  

let config = MSALPublicClientApplicationConfig(clientId:clientId
                                           	redirectUri:redirectUri
                                            	authority:authority)
guard let application = MSALPublicClientApplication(configuration: config) else { return }

let accountIdentifier = "9f4880d8-80ba-4c40-97bc-f7a23c703084.f645ad92-e38d-4d1a-b510-d1b09a74a8ca"
let parameters = MSALAccountEnumerationParameters(identifier:accountIdentifier)

var scopeArr = ["https://graph.microsoft.com/.default"]

if #available(macOS 10.15, *)
{
	 application.accountsFromDeviceForParameters(with: parameters, completionBlock:{(accounts, error) in
         if let error = error 
         {
            //Handle error
         }
         
         guard let accountObjs = accounts else {return}
         
         let tokenParameters = MSALSilentTokenParameters(scopes:scopeArr, account: accountObjs[0]);
                                                                                                   
         application.acquireTokenSilentWithParameters(with: tokenParameters, completionBlock:{(result, error) in 
                     if let error = error
                     {
                         //handle error
                     }
                                       
                     guard let resp = result else {return} //process result
                                                                                             
         })                                                               
                                                                                                                                                             
   })
  
}

Objective-C

//import other key libraries  
#import "MSAL-umbrella.h" //Make sure to import umbrella file 

    MSALPublicClientApplicationConfig *config = [[MSALPublicClientApplicationConfig alloc] initWithClientId:clientId
     redirectUri:redirectUri
       authority:authority];

    MSALPublicClientApplication *application = [[MSALPublicClientApplication alloc] initWithConfiguration:config error:&error];
    MSALAccountEnumerationParameters *parameters = [[MSALAccountEnumerationParameters alloc] initWithIdentifier:@"9f4880d8-80ba-4c40-97bc-f7a23c703084.f645ad92-e38d-4d1a-b510-d1b09a74a8ca"]; //init with account identifier

    NSArray<NSString *> *scopeArr = [[NSArray alloc] initWithObjects: @"https://graph.microsoft.com/.default",nil]; //define scope

    if (@available(macOS 10.15, *)) //Currently, this public API requires macOs version 10.15 or greater.
    {
        [application accountsFromDeviceForParameters:parameters
                                     completionBlock:^(NSArray<MSALAccount *> * _Nullable accounts, __unused NSError * _Nullable error)
        {
            if (error)
            {
              //Log error & return 
            }
          
            if (accounts)
            {
                NSLog(@"hi there");
                MSALSilentTokenParameters *tokenParameters = [[MSALSilentTokenParameters alloc] initWithScopes:scopeArr account:accounts[0]];

                [application acquireTokenSilentWithParameters:tokenParameters
                                completionBlock:^(MSALResult * _Nullable result, NSError * _Nullable error)
                 {
                    if (error)
                    {
                        //Log Error & return 
                    }
                    if (result)
                    {
                        //process result
                    }
                }
                 ];
            }
     
        }];
    }

检测共享设备模式

使用以下代码读取当前设备配置,包括设备是否被配置为共享

Swift

application.getDeviceInformation(with: nil, completionBlock: { (deviceInformation, error) in
                
	guard let deviceInfo = deviceInformation else {
		return
	}
                
	let isSharedDevice = deviceInfo.deviceMode == .shared
	// Change your app UX if needed
})

Objective-C

[application getDeviceInformationWithParameters:nil
                                completionBlock:^(MSALDeviceInformation * _Nullable deviceInformation, NSError * _Nullable error)
{
	if (!deviceInformation)
	{
		return;
	}
            
	BOOL isSharedDevice = deviceInformation.deviceMode == MSALDeviceModeShared;
	// Change your app UX if needed
}];

实现注销

要从应用中注销账号,请调用电环的注销API。您也可以选择从浏览器注销。当电环在共享设备上运行时,注销API将全局注销用户设备上的所有应用。

Swift

let account = .... /* account retrieved above */

let signoutParameters = MSALSignoutParameters(webviewParameters: self.webViewParameters!)
signoutParameters.signoutFromBrowser = false
            
application.signout(with: account, signoutParameters: signoutParameters, completionBlock: {(success, error) in
                
	if let error = error {
		// Signout failed
		return
	}
                
	// Sign out completed successfully
})

Objective-C

MSALAccount *account = ... /* account retrieved above */;
        
MSALSignoutParameters *signoutParameters = [[MSALSignoutParameters alloc] initWithWebviewParameters:webViewParameters];
signoutParameters.signoutFromBrowser = NO;
        
[application signoutWithAccount:account signoutParameters:signoutParameters completionBlock:^(BOOL success, NSError * _Nullable error)
{
	if (!success)
	{
		// Signout failed
		return;
	}
            
	// Sign out completed successfully
}];

支持的版本

iOS - MSAL 支持iOS 14及更高版本。

macOS - MSAL 支持 macOS (OSX) 10.13及更高版本。

从ADAL Objective-C迁移

MSAL Objective-C旨在支持从ADAL Objective-C库的平稳迁移。有关详细设计和说明,请参阅此指南

额外指导

我们的wiki旨在记录常见模式、错误处理和调试、功能(例如日志记录、遥测)和活跃的bug。您可以在这里找到它。

社区帮助与支持

我们与社区使用 Stack Overflow 提供支持。我们强烈建议您首先在 Stack Overflow 上提出问题,并浏览现有问题以查看是否有人之前提出过相同问题。

如果您发现错误或有功能请求,请将问题提交到 GitHub Issues

要提出建议,请访问我们的 用户声音页面

提交反馈

我们期待您的对该库的观点。请完成 此简短调查

参与贡献

我们热忱欢迎贡献和反馈。您现在可以克隆存储库并开始贡献。

本项目已采用 Microsoft 开源行为准则。更多信息请参阅 行为准则常见问题解答 或联系 [email protected] 询问任何其他问题或提出意见。

安全库

此库控制用户如何登录和访问服务。我们建议您在可能的情况下始终将您应用程序中的库的最新版本作为首选。我们使用语义版本控制 (semantic versioning),因此您可以通过更新您的应用程序来控制相关风险。例如,始终下载最新的次要版本号(例如 x.y.x)可以确保您获得最新安全性增强和功能改进,而我们的API界面保持不变。您可以在GitHub“发布”选项卡下查看最新版本和发布说明。

安全报告

如果您发现我们库或服务中的安全漏洞,请尽可能详细地向[email protected]报告。您的提交可能符合Microsoft赏金计划的资格。请不要将安全漏洞发布到GitHub问题或其他任何公共网站上。收到信息后,我们将尽快与您联系。我们鼓励您通过访问此页面并订阅安全预警警报来获取安全事件发生时的通知。

许可

版权所有 ©微软公司。保留所有权利。在MIT许可证(“许可”)下许可。