iOS和macOS的AppAuth是为了与OAuth 2.0和OpenID Connect提供者通信的客户端SDK。它力争直接映射那些规范中的请求数据和响应,同时遵循实现语言的约定式风格。除了映射原始协议流程外,还提供方便的方法,帮助执行使用新令牌的操作等常见任务。
它遵循RFC 8252 - 原生应用程序的OAuth 2.0中提出的最优实践,包括在iOS上使用SFAuthenticationSession
和SFSafariViewController
进行身份验证请求。UIWebView
和WKWebView
由于安全性和可用性原因(原因请参阅RFC 8252的第8.12节)明确不支持。
它还支持OAuth的PKCE扩展,该扩展旨在在公共客户端中使用自定义URI方案重定向时保护授权代码。此库能够友好地处理所有协议请求和响应中的额外参数,能够处理其他扩展(标准或有其他用途)。
规范
iOS
支持的版本
AppAuth支持iOS 7及以上。
iOS 9+使用应用程序浏览器标签模式(通过SFSafariViewController
),在早期版本上回退至系统浏览器(移动Safari)。
认证服务器要求
库可以与自定义URI方案(所有受支持的iOS版本)和通用链接(iOS 9以上版本)一起使用。
一般情况下,AppAuth可以与任何支持原生应用的认证服务器(AS),如RFC 8252中所述,通过自定义URI方案重定向或通用链接进行工作。假设所有客户端都是基于Web或要求客户端维护客户端机密性保密的服务器可能工作不佳。
macOS
支持的版本
AppAuth支持macOS(OS X)10.9及以上版本。
认证服务器要求
AppAuth for macOS同时支持自定义方案和通过小型嵌入式服务器实现的回环HTTP重定向。
一般情况下,AppAuth可以与任何支持原生应用的认证服务器(AS),如RFC 8252中所述,通过自定义URI方案或回环HTTP重定向进行工作。假设所有客户端都是基于Web或要求客户端维护客户端机密性保密的服务器可能工作不佳。
尝试
想要试用AppAuth吗?只需运行
pod try AppAuth
按照Examples/README.md中的说明进行操作以配置您的OAuth客户端(您需要更改3个配置点以包含客户端信息以尝试演示)。
设置
AppAuth支持三种依赖管理选项。
CocoaPods
使用CocoaPods,将以下行添加到您的Podfile
中
pod 'AppAuth'
然后运行pod install
。
Carthage
使用Carthage,将以下行添加到您的Cartfile
中
github "openid/AppAuth-iOS" "master"
然后运行carthage bootstrap
。
静态库
您还可以将AppAuth用作静态库。这需要链接库和您的项目,并包括头文件。建议配置
- 创建一个Xcode Workspace。
- 将
AppAuth.xcodeproj
添加到您的Workspace中。 - 将libAppAuth视为您的目标链接库(在您的目标“通用 -> 链接框架和库”部分中)。
- 将
AppAuth-iOS/Source
添加到您的目标搜索路径中(在“构建设置 -> ”头文件搜索路径”中)。
认证流程
AppAuth同时支持与授权服务器手动交互以执行自己的令牌交换,以及执行某些逻辑的便利方法。此示例使用便利方法,它返回一个OIDAuthState
对象或一个错误。
OIDAuthState
是一个跟踪授权和令牌请求以及响应的类,并为调用带有新鲜令牌的API提供了便利方法。这是唯一需要序列化以保留会话授权状态的对象。
配置
您可以通过指定端点直接配置AppAuth。
NSURL *authorizationEndpoint =
[NSURL URLWithString:@"https://#/o/oauth2/v2/auth"];
NSURL *tokenEndpoint =
[NSURL URLWithString:@"https://www.googleapis.com/oauth2/v4/token"];
OIDServiceConfiguration *configuration =
[[OIDServiceConfiguration alloc]
initWithAuthorizationEndpoint:authorizationEndpoint
tokenEndpoint:tokenEndpoint];
// perform the auth request...
或者通过发现机制。
NSURL *issuer = [NSURL URLWithString:@"https://#"];
[OIDAuthorizationService discoverServiceConfigurationForIssuer:issuer
completion:^(OIDServiceConfiguration *_Nullable configuration,
NSError *_Nullable error) {
if (!configuration) {
NSLog(@"Error retrieving discovery document: %@",
[error localizedDescription]);
return;
}
// perform the auth request...
}];
授权 – iOS
首先,您需要在AppDelegate中添加一个属性来存储会话,以便从重定向继续授权流程。
// property of the app's AppDelegate
@property(nonatomic, strong, nullable)
id<OIDExternalUserAgentSession> currentAuthorizationFlow;
然后在您的主类中,一个属性用于存储授权状态
// property of the containing class
@property(nonatomic, strong, nullable) OIDAuthState *authState;
然后,发起授权请求。通过使用authStateByPresentingAuthorizationRequest
便捷方法,将自动执行令牌交换,一切都会通过PKCE(如果服务器支持)得到保护。AppAuth还允许您手动执行这些请求。请参考包含示例应用程序中的authNoCodeExchange
方法进行演示。
// builds authentication request
OIDAuthorizationRequest *request =
[[OIDAuthorizationRequest alloc] initWithConfiguration:configuration
clientId:kClientID
scopes:@[OIDScopeOpenID,
OIDScopeProfile]
redirectURL:KRedirectURI
responseType:OIDResponseTypeCode
additionalParameters:nil];
// performs authentication request
AppDelegate *appDelegate =
(AppDelegate *)[UIApplication sharedApplication].delegate;
appDelegate.currentAuthorizationFlow =
[OIDAuthState authStateByPresentingAuthorizationRequest:request
presentingViewController:self
callback:^(OIDAuthState *_Nullable authState,
NSError *_Nullable error) {
if (authState) {
NSLog(@"Got authorization tokens. Access token: %@",
authState.lastTokenResponse.accessToken);
[self setAuthState:authState];
} else {
NSLog(@"Authorization error: %@", [error localizedDescription]);
[self setAuthState:nil];
}
}];
处理重定向
授权响应URL将通过iOS的openURL应用程序代理方法返回给应用程序,因此您需要将其传递到当前授权会话(在之前会话中创建)。
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary<NSString *, id> *)options {
// Sends the URL to the current authorization flow (if any) which will
// process it if it relates to an authorization response.
if ([_currentAuthorizationFlow resumeExternalUserAgentFlowWithURL:url]) {
_currentAuthorizationFlow = nil;
return YES;
}
// Your additional URL handling (if any) goes here.
return NO;
}
授权 – MacOS
在macOS上,获取授权响应重定向最流行的方式是在环回接口上启动本地HTTP服务器(仅限于用户机器的入站请求)。授权完成后,用户将被重定向到该本地服务器,应用程序可以处理授权响应。AppAuth会为您管理本地HTTP服务器的生命周期。
💡 备选方案:自定义URI方案macOS也支持自定义URI方案,但某些浏览器会显示一个中继界面,从而降低了可用性。有关使用自定义URI方案与macOS的示例,请参见
Example-Mac
。
要使用本地HTTP服务器接收授权响应,首先您需要在您的主类中添加一个实例变量以保留HTTP重定向处理程序。
OIDRedirectHTTPHandler *_redirectHTTPHandler;
然后,由于本地HTTP服务器使用的端口可能不同,您需要在构建授权请求之前启动它,以便获取要使用的确切重定向URI。
static NSString *const kSuccessURLString =
@"http://openid.github.io/AppAuth-iOS/redirect/";
NSURL *successURL = [NSURL URLWithString:kSuccessURLString];
// Starts a loopback HTTP redirect listener to receive the code. This needs to be started first,
// as the exact redirect URI (including port) must be passed in the authorization request.
_redirectHTTPHandler = [[OIDRedirectHTTPHandler alloc] initWithSuccessURL:successURL];
NSURL *redirectURI = [_redirectHTTPHandler startHTTPListener:nil];
然后,发起授权请求。通过使用authStateByPresentingAuthorizationRequest
便捷方法,将自动执行令牌交换,一切都会通过PKCE(如果服务器支持)得到保护。通过将返回值分配给OIDRedirectHTTPHandler
的currentAuthorizationFlow
,一旦用户做出选择,授权将自动继续。
// builds authentication request
OIDAuthorizationRequest *request =
[[OIDAuthorizationRequest alloc] initWithConfiguration:configuration
clientId:kClientID
clientSecret:kClientSecret
scopes:@[ OIDScopeOpenID ]
redirectURL:redirectURI
responseType:OIDResponseTypeCode
additionalParameters:nil];
// performs authentication request
__weak __typeof(self) weakSelf = self;
_redirectHTTPHandler.currentAuthorizationFlow =
[OIDAuthState authStateByPresentingAuthorizationRequest:request
callback:^(OIDAuthState *_Nullable authState,
NSError *_Nullable error) {
// Brings this app to the foreground.
[[NSRunningApplication currentApplication]
activateWithOptions:(NSApplicationActivateAllWindows |
NSApplicationActivateIgnoringOtherApps)];
// Processes the authorization response.
if (authState) {
NSLog(@"Got authorization tokens. Access token: %@",
authState.lastTokenResponse.accessToken);
} else {
NSLog(@"Authorization error: %@", error.localizedDescription);
}
[weakSelf setAuthState:authState];
}];
编写API调用
AppAuth为您提供了原始令牌信息。然而,我们建议使用OIDAuthState
便利封装器的用户使用提供的performActionWithFreshTokens:
方法来执行API调用,以避免担心令牌的时效性。
[_authState performActionWithFreshTokens:^(NSString *_Nonnull accessToken,
NSString *_Nonnull idToken,
NSError *_Nullable error) {
if (error) {
NSLog(@"Error fetching fresh tokens: %@", [error localizedDescription]);
return;
}
// perform your API request using the tokens
}];
API文档
浏览API文档。
包含的示例
您可以通过打开源分布中的iOS示例来尝试iOS示例,进入Example/Example.xcworkspace
。您可以通过删除AppAuth
项目并配置pod来轻松地将示例工作区转换为Pod工作区。您还可以通过CocoaPods尝试示例。请务必遵循Example/README.md中的说明来配置自己的OAuth客户端ID以在示例中使用。
您可以通过在Example-Mac
文件夹中执行pod install
来尝试源分布中包含的macOS示例,然后打开Example-Mac.xcworkspace
。请务必遵循Example-Mac/README.md中的说明来配置自己的OAuth客户端ID以在示例中使用。