如何:macOS 和 iOS 上的 ADAL 与 MSAL 应用之间的 SSOHow to: SSO between ADAL and MSAL apps on macOS and iOS
适用于 iOS 的 Microsoft 身份验证库 (MSAL) 可与 ADAL Objective-C 共享应用程序之间的 SSO 状态。The Microsoft Authentication Library (MSAL) for iOS can share SSO state with ADAL Objective-C between applications. 你可以按照自己的步调将应用迁移到 MSAL,确保用户仍可受益于跨应用 SSO - 即使混用基于 ADAL 和基于 MSAL 的应用。You can migrate your apps to MSAL at your own pace, ensuring that your users will still benefit from cross-app SSO--even with a mix of ADAL and MSAL-based apps.
如果你正在寻找有关使用 MSAL SDK 在应用之间设置 SSO 的指导,请参阅多个应用之间的静默 SSO。If you're looking for guidance of setting up SSO between apps using the MSAL SDK, see Silent SSO between multiple apps. 本文重点介绍 ADAL 与 MSAL 之间的 SSO。This article focuses on SSO between ADAL and MSAL.
实现 SSO 的具体步骤取决于所用的 ADAL 版本。The specifics implementing SSO depend on ADAL version that you're using.
ADAL 2.7.xADAL 2.7.x
本部分介绍 MSAL 与 ADAL 2.7.x 之间的 SSO 差异This section covers SSO differences between MSAL and ADAL 2.7.x
缓存格式Cache format
ADAL 2.7.x 可以读取 MSAL 缓存格式。ADAL 2.7.x can read the MSAL cache format. 对于版本 ADAL 2.7.x 的跨应用 SSO,无需执行任何特殊操作。You don't need to do anything special for cross-app SSO with version ADAL 2.7.x. 但是,需要注意这两个库支持的帐户标识符的差异。However, you need to be aware of differences in account identifiers that those two libraries support.
帐户标识符差异Account identifier differences
MSAL 和 ADAL 使用不同的帐户标识符。MSAL and ADAL use different account identifiers. ADAL 使用 UPN 作为主要帐户标识符。ADAL uses UPN as its primary account identifier. MSAL 使用一个不可显示的帐户标识符,该标识符基于 AAD 帐户的对象 ID 和租户 ID,以及其他帐户类型的 sub
声明。MSAL uses a non-displayable account identifier that is based of an object ID and a tenant ID for AAD accounts, and a sub
claim for other types of accounts.
在 MSAL 结果中收到 MSALAccount
对象时,其 identifier
属性会包含一个帐户标识符。When you receive an MSALAccount
object in the MSAL result, it contains an account identifier in the identifier
property. 应用程序应使用此标识符发出后续的静默请求。The application should use this identifier for subsequent silent requests.
除 identifier
以外,MSALAccount
对象还包含名为 username
的可显示标识符。In addition to identifier
, MSALAccount
object contains a displayable identifier called username
. 该标识符将转换为 ADAL 中的 userId
。That translates to userId
in ADAL. username
不被视为唯一标识符且随时可能会更改,因此,只应将其用于 ADAL 的后向兼容方案。username
is not considered a unique identifier and can change anytime, so it should only be used for backward compatibility scenarios with ADAL. MSAL 支持使用 username
或 identifier
的缓存查询,建议按 identifier
进行查询。MSAL supports cache queries using either username
or identifier
, where querying by identifier
is recommended.
下表汇总了 ADAL 与 MSAL 之间的帐户标识符差异:Following table summarizes account identifier differences between ADAL and MSAL:
帐户标识符Account identifier | MSALMSAL | ADAL 2.7.xADAL 2.7.x | 旧版 ADAL(ADAL 2.7.x 以前的版本)Older ADAL (before ADAL 2.7.x) |
---|---|---|---|
可显示的标识符displayable identifier | username |
userId |
userId |
不可显示的唯一标识符unique non-displayable identifier | identifier |
homeAccountId |
不适用N/A |
没有任何已知的帐户 IDNo account id known | 通过 allAccounts: 中的 MSALPublicClientApplication API 查询所有帐户Query all accounts through allAccounts: API in MSALPublicClientApplication |
不适用N/A | 不适用N/A |
这是提供这些标识符的 MSALAccount
接口:This is the MSALAccount
interface providing those identifiers:
@protocol MSALAccount <NSObject>
/*!
Displayable user identifier. Can be used for UI and backward compatibility with ADAL.
*/
@property (readonly, nullable) NSString *username;
/*!
Unique identifier for the account.
Save this for account lookups from cache at a later point.
*/
@property (readonly, nullable) NSString *identifier;
/*!
Host part of the authority string used for authentication based on the issuer identifier.
*/
@property (readonly, nonnull) NSString *environment;
/*!
ID token claims for the account.
Can be used to read additional information about the account, e.g. name
Will only be returned if there has been an id token issued for the client Id for the account's source tenant.
*/
@property (readonly, nullable) NSDictionary<NSString *, NSString *> *accountClaims;
@end
从 MSAL 到 ADAL 的 SSOSSO from MSAL to ADAL
如果你有一个 MSAL 应用和一个 ADAL 应用,并且用户是首次登录到基于 MSAL 的应用,则你可以通过保存 MSALAccount
对象中的 username
并将其作为 userId
传递给基于 ADAL 的应用,在 ADAL 应用中实现 SSO。If you have an MSAL app and an ADAL app, and the user first signs into the MSAL-based app, you can get SSO in the ADAL app by saving the username
from the MSALAccount
object and passing it to your ADAL-based app as userId
. 然后,ADAL 可以使用 acquireTokenSilentWithResource:clientId:redirectUri:userId:completionBlock:
API 以静默方式查找帐户信息。ADAL can then find the account information silently with the acquireTokenSilentWithResource:clientId:redirectUri:userId:completionBlock:
API.
从 ADAL 到 MSAL 的 SSOSSO from ADAL to MSAL
如果你有一个 MSAL 应用和一个 ADAL 应用,并且用户是首次登录到基于 ADAL 的应用,则你可以使用 ADAL 用户标识符在 MSAL 中执行帐户查找。If you have an MSAL app and an ADAL app, and the user first signs into the ADAL-based app, you can use ADAL user identifiers for account lookups in MSAL. 此方法在从 ADAL 迁移到 MSAL 时也适用。This also applies when migrating from ADAL to MSAL.
ADAL 的 homeAccountIdADAL's homeAccountId
ADAL 2.7.x 通过此属性在结果中返回 ADUserInformation
对象中的 homeAccountId
:ADAL 2.7.x returns the homeAccountId
in the ADUserInformation
object in the result via this property:
/*! Unique AAD account identifier across tenants based on user's home OID/home tenantId. */
@property (readonly) NSString *homeAccountId;
ADAL 中的 homeAccountId
等效于 MSAL 中的 identifier
。homeAccountId
in ADAL's is equivalent of identifier
in MSAL. 可以保存此标识符,以便在 MSAL 中使用它来通过 accountForIdentifier:error:
API 执行帐户查找。You can save this identifier to use in MSAL for account lookups with the accountForIdentifier:error:
API.
ADAL 的 userId
ADAL's userId
如果 homeAccountId
不可用,或者只有可显示的标识符,则可以使用 ADAL 的 userId
在 MSAL 中执行帐户查找。If homeAccountId
is not available, or you only have the displayable identifier, you can use ADAL's userId
to lookup the account in MSAL.
在 MSAL 中,首先按 username
或 identifier
查找帐户。In MSAL, first look up an account by username
or identifier
. 如果有 identifier
,请始终使用它执行查询,仅将 username
用作应变手段。Always use identifier
for querying if you have it, and only use username
as a fallback. 如果找到帐户,请在 acquireTokenSilent
调用中使用该帐户。If the account is found, use the account in the acquireTokenSilent
calls.
Objective-C:Objective-C:
NSString *msalIdentifier = @"previously.saved.msal.account.id";
MSALAccount *account = nil;
if (msalIdentifier)
{
// If you have MSAL account id returned either from MSAL as identifier or ADAL as homeAccountId, use it
account = [application accountForIdentifier:@"my.account.id.here" error:nil];
}
else
{
// Fallback to ADAL userId for migration
account = [application accountForUsername:@"adal.user.id" error:nil];
}
if (!account)
{
// Account not found.
return;
}
MSALSilentTokenParameters *silentParameters = [[MSALSilentTokenParameters alloc] initWithScopes:@[@"https://microsoftgraph.chinacloudapi.cn/user.read"] account:account];
[application acquireTokenSilentWithParameters:silentParameters completionBlock:completionBlock];
Swift:Swift:
let msalIdentifier: String?
var account: MSALAccount
do {
if let msalIdentifier = msalIdentifier {
account = try application.account(forIdentifier: msalIdentifier)
}
else {
account = try application.account(forUsername: "adal.user.id")
}
let silentParameters = MSALSilentTokenParameters(scopes: ["https://microsoftgraph.chinacloudapi.cn/user.read"], account: account)
application.acquireTokenSilent(with: silentParameters) {
(result: MSALResult?, error: Error?) in
// handle result
}
} catch let error as NSError {
// handle error or account not found
}
MSAL 支持的帐户查找 API:MSAL supported account lookup APIs:
/*!
Returns account for the given account identifier (received from an account object returned in a previous acquireToken call)
@param error The error that occurred trying to get the accounts, if any, if you're
not interested in the specific error pass in nil.
*/
- (nullable MSALAccount *)accountForIdentifier:(nonnull NSString *)identifier
error:(NSError * _Nullable __autoreleasing * _Nullable)error;
/*!
Returns account for for the given username (received from an account object returned in a previous acquireToken call or ADAL)
@param username The displayable value in UserPrincipleName(UPN) format
@param error The error that occurred trying to get the accounts, if any, if you're
not interested in the specific error pass in nil.
*/
- (MSALAccount *)accountForUsername:(NSString *)username
error:(NSError * __autoreleasing *)error;
ADAL 2.x-2.6.6ADAL 2.x-2.6.6
本部分介绍 MSAL 与 ADAL 2.x-2.6.6 之间的 SSO 差异This section covers SSO differences between MSAL and ADAL 2.x-2.6.6.
旧版 ADAL 原生并不支持 MSAL 缓存格式。Older ADAL versions don't natively support the MSAL cache format. 但是,为了确保从 ADAL 平稳迁移到 MSAL,MSAL 可以读取旧版 ADAL 缓存格式,而不会再次提示输入用户凭据。However, to ensure smooth migration from ADAL to MSAL, MSAL can read the older ADAL cache format without prompting for user credentials again.
由于 homeAccountId
在旧版 ADAL 中不可用,因此需要使用 username
查找帐户:Because homeAccountId
isn't available in older ADAL versions, you'd need to look up accounts using the username
:
/*!
Returns account for for the given username (received from an account object returned in a previous acquireToken call or ADAL)
@param username The displayable value in UserPrincipleName(UPN) format
@param error The error that occurred trying to get the accounts, if any. If you're not interested in the specific error pass in nil.
*/
- (MSALAccount *)accountForUsername:(NSString *)username
error:(NSError * __autoreleasing *)error;
例如:For example:
Objective-C:Objective-C:
MSALAccount *account = [application accountForUsername:@"adal.user.id" error:nil];;
MSALSilentTokenParameters *silentParameters = [[MSALSilentTokenParameters alloc] initWithScopes:@[@"https://microsoftgraph.chinacloudapi.cn/user.read"] account:account];
[application acquireTokenSilentWithParameters:silentParameters completionBlock:completionBlock];
Swift:Swift:
do {
let account = try application.account(forUsername: "adal.user.id")
let silentParameters = MSALSilentTokenParameters(scopes: ["https://microsoftgraph.chinacloudapi.cn/user.read"], account: account)
application.acquireTokenSilent(with: silentParameters) {
(result: MSALResult?, error: Error?) in
// handle result
}
} catch let error as NSError {
// handle error or account not found
}
或者,可以读取所有帐户,这样也会读取 ADAL 中的帐户信息:Alternatively, you can read all of the accounts, which will also read account information from ADAL:
Objective-C:Objective-C:
NSArray *accounts = [application allAccounts:nil];
if ([accounts count] == 0)
{
// No account found.
return;
}
if ([accounts count] > 1)
{
// You might want to display an account picker to user in actual application
// For this sample we assume there's only ever one account in cache
return;
}
``
MSALSilentTokenParameters *silentParameters = [[MSALSilentTokenParameters alloc] initWithScopes:@[@"https://microsoftgraph.chinacloudapi.cn/user.read"] account:accounts[0]];
[application acquireTokenSilentWithParameters:silentParameters completionBlock:completionBlock];
Swift:Swift:
do {
let accounts = try application.allAccounts()
if accounts.count == 0 {
// No account found.
return
}
if accounts.count > 1 {
// You might want to display an account picker to user in actual application
// For this sample we assume there's only ever one account in cache
return
}
let silentParameters = MSALSilentTokenParameters(scopes: ["https://microsoftgraph.chinacloudapi.cn/user.read"], account: accounts[0])
application.acquireTokenSilent(with: silentParameters) {
(result: MSALResult?, error: Error?) in
// handle result or error
}
} catch let error as NSError {
// handle error
}
后续步骤Next steps
详细了解身份验证流和应用程序方案Learn more about Authentication flows and application scenarios