经开发人员验证的身份(身份池) - Amazon Cognito
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

经开发人员验证的身份(身份池)

除了通过 将 Facebook 设置为身份池 IdP将 Google 设置为身份池 IdP将 Login with Amazon 设置为身份池 IdP将 “通过 Apple 登录” 设置为身份池 IdP 的 Web 身份联合验证之外,Amazon Cognito 还支持经开发人员验证的身份。使用经过开发人员身份验证的身份,您可以通过自己的现有身份验证流程注册和验证用户,同时仍可以使用 Amazon Cognito 同步用户数据和访问资源。 Amazon 使用经开发人员验证的身份涉及最终用户设备、身份验证后端和 Amazon Cognito 之间的交互。有关更多详细信息,请参阅博客中的了解 Amazon Cognito 身份验证第 2 部分:经过开发人员身份验证的 Amazon 身份

了解身份验证流程

GetOpenIdTokenForDeveloperIdentityAPI 操作可以为增强身份验证和基本身份验证启动开发者身份验证。此 API 使用管理凭证对请求进行身份验证。该Logins地图是身份池开发者提供商的名称,例如与自定义标识符login.mydevprovider配对。

例如:

"Logins": { "login.mydevprovider": "my developer identifier" }

增强的身份验证

使用包含令牌名称cognito-identity.amazonaws.com和值Logins的地图调用 GetCredentialsForIdentityAPI 操作GetOpenIdTokenForDeveloperIdentity

例如:

"Logins": { "cognito-identity.amazonaws.com": "eyJra12345EXAMPLE" }

GetCredentialsForIdentity使用经过开发者身份验证的身份,会返回身份池中默认经过身份验证的角色的临时证书。

基本身份验证

调用 AssumeRoleWithWebIdentityAPI 操作并请求已定义适当信任关系RoleArn的任何 IAM 角色的。将的值设置WebIdentityToken为从中获得的令牌GetOpenIdTokenForDeveloperIdentity

有关经过开发人员身份验证的身份 authflow 以及它们与外部提供商身份有何区别的信息,请参阅。身份池(联合身份)身份验证流程

定义开发人员提供商名称并将其与身份池关联

要使用经开发人员验证的身份,您需要与开发人员提供者关联的身份池。为此,请按照以下步骤操作:

添加自定义开发人员提供者
  1. Amazon Cognito 控制台中选择身份池。选择身份池。

  2. 选择用户访问选项卡。

  3. 选择添加身份提供者

  4. 选择自定义开发人员提供者

  5. 输入开发人员提供者名称。添加开发人员提供者后,无法更改或删除它。

  6. 选择保存更改

注意:一旦设置提供商名称,便无法进行更改。

有关使用 Amazon Cognito 控制台的更多说明,请参阅使用 Amazon Cognito 控制台

实施身份提供商

Android

要使用经开发人员验证的身份,请实施自己的身份提供者类,该类可扩展 AWSAbstractCognitoIdentityProvider。您的身份提供商类应返回包含令牌作为属性的响应对象。

以下是身份提供者的基本示例。

public class DeveloperAuthenticationProvider extends AWSAbstractCognitoDeveloperIdentityProvider { private static final String developerProvider = "<Developer_provider_name>"; public DeveloperAuthenticationProvider(String accountId, String identityPoolId, Regions region) { super(accountId, identityPoolId, region); // Initialize any other objects needed here. } // Return the developer provider name which you choose while setting up the // identity pool in the &COG; Console @Override public String getProviderName() { return developerProvider; } // Use the refresh method to communicate with your backend to get an // identityId and token. @Override public String refresh() { // Override the existing token setToken(null); // Get the identityId and token by making a call to your backend // (Call to your backend) // Call the update method with updated identityId and token to make sure // these are ready to be used from Credentials Provider. update(identityId, token); return token; } // If the app has a valid identityId return it, otherwise get a valid // identityId from your backend. @Override public String getIdentityId() { // Load the identityId from the cache identityId = cachedIdentityId; if (identityId == null) { // Call to your backend } else { return identityId; } } }

要使用此身份提供商,您必须将其传递到 CognitoCachingCredentialsProvider。示例如下:

DeveloperAuthenticationProvider developerProvider = new DeveloperAuthenticationProvider( null, "IDENTITYPOOLID", context, Regions.USEAST1); CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider( context, developerProvider, Regions.USEAST1);

iOS – objective-C

要使用经开发人员验证的身份,请实施自己的身份提供者类,该类可扩展 AWSCognitoCredentialsProviderHelper。您的身份提供商类应返回包含令牌作为属性的响应对象。

@implementation DeveloperAuthenticatedIdentityProvider /* * Use the token method to communicate with your backend to get an * identityId and token. */ - (AWSTask <NSString*> *) token { //Write code to call your backend: //Pass username/password to backend or some sort of token to authenticate user //If successful, from backend call getOpenIdTokenForDeveloperIdentity with logins map //containing "your.provider.name":"enduser.username" //Return the identity id and token to client //You can use AWSTaskCompletionSource to do this asynchronously // Set the identity id and return the token self.identityId = response.identityId; return [AWSTask taskWithResult:response.token]; } @end

要使用此身份提供商,请将其传递到 AWSCognitoCredentialsProvider,如下例所示:

DeveloperAuthenticatedIdentityProvider * devAuth = [[DeveloperAuthenticatedIdentityProvider alloc] initWithRegionType:AWSRegionYOUR_IDENTITY_POOL_REGION identityPoolId:@"YOUR_IDENTITY_POOL_ID" useEnhancedFlow:YES identityProviderManager:nil]; AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:AWSRegionYOUR_IDENTITY_POOL_REGION identityProvider:devAuth];

如果您想同时支持未经身份验证的身份和经开发人员验证的身份,请在 logins 实施中覆盖 AWSCognitoCredentialsProviderHelper 方法。

- (AWSTask<NSDictionary<NSString *, NSString *> *> *)logins { if(/*logic to determine if user is unauthenticated*/) { return [AWSTask taskWithResult:nil]; }else{ return [super logins]; } }

如果您想支持经开发人员验证的身份和社交提供者,您必须管理在 AWSCognitoCredentialsProviderHelperlogins 实施中谁是当前的提供者。

- (AWSTask<NSDictionary<NSString *, NSString *> *> *)logins { if(/*logic to determine if user is unauthenticated*/) { return [AWSTask taskWithResult:nil]; }else if (/*logic to determine if user is Facebook*/){ return [AWSTask taskWithResult: @{ AWSIdentityProviderFacebook : [FBSDKAccessToken currentAccessToken] }]; }else { return [super logins]; } }

iOS – swift

要使用经开发人员验证的身份,请实施自己的身份提供者类,该类可扩展 AWSCognitoCredentialsProviderHelper。您的身份提供商类应返回包含令牌作为属性的响应对象。

import AWSCore /* * Use the token method to communicate with your backend to get an * identityId and token. */ class DeveloperAuthenticatedIdentityProvider : AWSCognitoCredentialsProviderHelper { override func token() -> AWSTask<NSString> { //Write code to call your backend: //pass username/password to backend or some sort of token to authenticate user, if successful, //from backend call getOpenIdTokenForDeveloperIdentity with logins map containing "your.provider.name":"enduser.username" //return the identity id and token to client //You can use AWSTaskCompletionSource to do this asynchronously // Set the identity id and return the token self.identityId = resultFromAbove.identityId return AWSTask(result: resultFromAbove.token) }

要使用此身份提供商,请将其传递到 AWSCognitoCredentialsProvider,如下例所示:

let devAuth = DeveloperAuthenticatedIdentityProvider(regionType: .YOUR_IDENTITY_POOL_REGION, identityPoolId: "YOUR_IDENTITY_POOL_ID", useEnhancedFlow: true, identityProviderManager:nil) let credentialsProvider = AWSCognitoCredentialsProvider(regionType: .YOUR_IDENTITY_POOL_REGION, identityProvider:devAuth) let configuration = AWSServiceConfiguration(region: .YOUR_IDENTITY_POOL_REGION, credentialsProvider:credentialsProvider) AWSServiceManager.default().defaultServiceConfiguration = configuration

如果您想同时支持未经身份验证的身份和经开发人员验证的身份,请在 logins 实施中覆盖 AWSCognitoCredentialsProviderHelper 方法。

override func logins () -> AWSTask<NSDictionary> { if(/*logic to determine if user is unauthenticated*/) { return AWSTask(result:nil) }else { return super.logins() } }

如果您想支持经开发人员验证的身份和社交提供者,您必须管理在 AWSCognitoCredentialsProviderHelperlogins 实施中谁是当前的提供者。

override func logins () -> AWSTask<NSDictionary> { if(/*logic to determine if user is unauthenticated*/) { return AWSTask(result:nil) }else if (/*logic to determine if user is Facebook*/){ if let token = AccessToken.current?.authenticationToken { return AWSTask(result: [AWSIdentityProviderFacebook:token]) } return AWSTask(error:NSError(domain: "Facebook Login", code: -1 , userInfo: ["Facebook" : "No current Facebook access token"])) }else { return super.logins() } }

JavaScript

从后端获取身份 ID 和会话令牌后,您要将它们传递到 AWS.CognitoIdentityCredentials 提供者。以下为示例。

AWS.config.credentials = new AWS.CognitoIdentityCredentials({ IdentityPoolId: 'IDENTITY_POOL_ID', IdentityId: 'IDENTITY_ID_RETURNED_FROM_YOUR_PROVIDER', Logins: { 'cognito-identity.amazonaws.com': 'TOKEN_RETURNED_FROM_YOUR_PROVIDER' } });

Unity

要使用经开发人员验证的身份,您必须扩展 CognitoAWSCredentials 并覆盖 RefreshIdentity 方法,以从后端检索用户身份 ID 和令牌,并将它们返回。下面是可通过“example.com”联系假想后端的身份提供者的简单示例:

using UnityEngine; using System.Collections; using Amazon.CognitoIdentity; using System.Collections.Generic; using ThirdParty.Json.LitJson; using System; using System.Threading; public class DeveloperAuthenticatedCredentials : CognitoAWSCredentials { const string PROVIDER_NAME = "example.com"; const string IDENTITY_POOL = "IDENTITY_POOL_ID"; static readonly RegionEndpoint REGION = RegionEndpoint.USEast1; private string login = null; public DeveloperAuthenticatedCredentials(string loginAlias) : base(IDENTITY_POOL, REGION) { login = loginAlias; } protected override IdentityState RefreshIdentity() { IdentityState state = null; ManualResetEvent waitLock = new ManualResetEvent(false); MainThreadDispatcher.ExecuteCoroutineOnMainThread(ContactProvider((s) => { state = s; waitLock.Set(); })); waitLock.WaitOne(); return state; } IEnumerator ContactProvider(Action<IdentityState> callback) { WWW www = new WWW("http://example.com/?username="+login); yield return www; string response = www.text; JsonData json = JsonMapper.ToObject(response); //The backend has to send us back an Identity and a OpenID token string identityId = json["IdentityId"].ToString(); string token = json["Token"].ToString(); IdentityState state = new IdentityState(identityId, PROVIDER_NAME, token, false); callback(state); } }

上面的代码使用线程调度程序对象调用协同程序。如果您在项目中无法执行上述操作,您可以在场景中使用以下脚本:

using System; using UnityEngine; using System.Collections; using System.Collections.Generic; public class MainThreadDispatcher : MonoBehaviour { static Queue<IEnumerator> _coroutineQueue = new Queue<IEnumerator>(); static object _lock = new object(); public void Update() { while (_coroutineQueue.Count > 0) { StartCoroutine(_coroutineQueue.Dequeue()); } } public static void ExecuteCoroutineOnMainThread(IEnumerator coroutine) { lock (_lock) { _coroutineQueue.Enqueue(coroutine); } } }

Xamarin

要使用经开发人员验证的身份,您必须扩展 CognitoAWSCredentials 并覆盖 RefreshIdentity 方法,以从后端检索用户身份 ID 和令牌,并将它们返回。下面是可通过“example.com”联系假想后端的身份提供者的基本示例:

public class DeveloperAuthenticatedCredentials : CognitoAWSCredentials { const string PROVIDER_NAME = "example.com"; const string IDENTITY_POOL = "IDENTITY_POOL_ID"; static readonly RegionEndpoint REGION = RegionEndpoint.USEast1; private string login = null; public DeveloperAuthenticatedCredentials(string loginAlias) : base(IDENTITY_POOL, REGION) { login = loginAlias; } protected override async Task<IdentityState> RefreshIdentityAsync() { IdentityState state = null; //get your identity and set the state return state; } }

更新登录映射(仅限 Android 和 iOS)

Android

使用身份验证系统成功对用户进行身份验证后,请使用开发人员提供者名称和开发人员用户标识符更新登录映射。此标识符是一个字母数字字符串,可在身份验证系统中唯一标识用户。请确保在更新登录映射后调用 refresh 方法,因为 identityId 可能已更改:

HashMap<String, String> loginsMap = new HashMap<String, String>(); loginsMap.put(developerAuthenticationProvider.getProviderName(), developerUserIdentifier); credentialsProvider.setLogins(loginsMap); credentialsProvider.refresh();

iOS – objective-C

如果没有凭证或者凭证已过期,则 iOS 开发工具包仅调用 logins 方法,以获取最新登录映射。如果您要强制 SDK 获取新的凭证(例如,最终用户从未经身份验证变为经过身份验证并且您想要经过身份验证的用户的凭证),则对 credentialsProvider 调用 clearCredentials

[credentialsProvider clearCredentials];

iOS – swift

如果没有凭证或者凭证已过期,则 iOS 开发工具包仅调用 logins 方法,以获取最新登录映射。如果您要强制开发工具包获取新的凭证 (例如,最终用户从未经身份验证变为经过身份验证并且您想要经过身份验证的用户的凭证),则在 clearCredentials 上调用 credentialsProvider

credentialsProvider.clearCredentials()

获取令牌(服务器端)

您可以通过调用获取令牌GetOpenIdTokenForDeveloperIdentity。必须使用 Amazon 开发者凭据从您的后端调用此 API。不得从客户端开发工具包调用它。API 接收 Cognito 身份池 ID;包含身份提供者名称作为密钥及标识符作为值的登录映射;以及可选 Cognito 身份 ID(例如,您让一个未经过身份验证的用户变成了经身份验证的用户)。标识符可以是用户的用户名、电子邮件地址或数值。API 通过为用户提供唯一 Cognito ID 及为最终用户提供 OpenID Connect 令牌来响应您的调用。

对于由 GetOpenIdTokenForDeveloperIdentity 返回的令牌,您需要注意以下事项:

  • 您可以指定令牌的自定义过期时间,以便缓存。如果您不提供任何自定义过期时间,则令牌的有效期为 15 分钟。

  • 您可以设置的最大令牌持续时间为 24 小时。

  • 请留意延长令牌持续时间所带来的安全方面的问题。如果攻击者获得此令牌,他们可以在令牌有效期内将其交换为最终用户的 Amazon 凭证。

以下 Java 代码段显示了如何初始化 Amazon Cognito 客户端,以及如何检索经开发人员验证的身份的令牌。

// authenticate your end user as appropriate // .... // if authenticated, initialize a cognito client with your AWS developer credentials AmazonCognitoIdentity identityClient = new AmazonCognitoIdentityClient( new BasicAWSCredentials("access_key_id", "secret_access_key") ); // create a new request to retrieve the token for your end user GetOpenIdTokenForDeveloperIdentityRequest request = new GetOpenIdTokenForDeveloperIdentityRequest(); request.setIdentityPoolId("YOUR_COGNITO_IDENTITY_POOL_ID"); request.setIdentityId("YOUR_COGNITO_IDENTITY_ID"); //optional, set this if your client has an //identity ID that you want to link to this //developer account // set up your logins map with the username of your end user HashMap<String,String> logins = new HashMap<>(); logins.put("YOUR_IDENTITY_PROVIDER_NAME","YOUR_END_USER_IDENTIFIER"); request.setLogins(logins); // optionally set token duration (in seconds) request.setTokenDuration(60 * 15l); GetOpenIdTokenForDeveloperIdentityResult response = identityClient.getOpenIdTokenForDeveloperIdentity(request); // obtain identity id and token to return to your client String identityId = response.getIdentityId(); String token = response.getToken(); //code to return identity id and token to client //...

按照上述步骤操作,您应该能够将经开发人员验证的身份集成到应用程序中。如有任何问题或疑问,请随时在我们的论坛上发帖。

连接到现有社交身份

当您使用经开发人员验证的身份时,您必须从后端链接所有提供者。要将自定义身份与用户的社交身份(Login with Amazon、使用 Apple 登录、Facebook 或 Google 登录)关联起来,请在致电GetOpenIdTokenForDeveloperIdentity时将身份提供者令牌添加到登录地图中。要实现上述目标,当您从客户端开发工具包调用后端来对最终用户进行身份验证时,您还需要传递最终用户的社交提供商令牌。

例如,如果您想将自定义身份链接到 Facebook,在调用 GetOpenIdTokenForDeveloperIdentity 时,除了身份提供商标识符之外,您还需要将 Facebook 令牌添加到登录映射。

logins.put("YOUR_IDENTITY_PROVIDER_NAME","YOUR_END_USER_IDENTIFIER"); logins.put("graph.facebook.com","END_USERS_FACEBOOK_ACCESSTOKEN");

支持在提供商之间转换

Android

您的应用程序可能需要支持未经身份验证的身份或使用公有提供者(Login with Amazon、通过 Apple 登录、Facebook 或 Google)的经过身份验证的身份,以及经开发人员验证的身份。经开发人员验证的身份与其他身份(未经身份验证的身份和使用公共提供者的经过身份验证的身份)的主要区别在于 identityId 和令牌的获取方式。对于其他身份,移动应用程序将直接与 Amazon Cognito 进行交互,而不是与身份验证系统联系。因此,移动应用程序应该能够支持两个不同的流程,具体取决于应用程序用户的选择。对此,您必须对自定义身份提供者做出一些更改。

refresh 方法检查登录映射。如果映射不为空并且有带开发人员提供者名称的密钥,请调用您的后端。否则,调用该 getIdentityId方法并返回 null。

public String refresh() { setToken(null); // If the logins map is not empty make a call to your backend // to get the token and identityId if (getProviderName() != null && !this.loginsMap.isEmpty() && this.loginsMap.containsKey(getProviderName())) { /** * This is where you would call your backend **/ // now set the returned identity id and token in the provider update(identityId, token); return token; } else { // Call getIdentityId method and return null this.getIdentityId(); return null; } }

同样,getIdentityId 方法也有两个流程,具体取决于登录映射的内容:

public String getIdentityId() { // Load the identityId from the cache identityId = cachedIdentityId; if (identityId == null) { // If the logins map is not empty make a call to your backend // to get the token and identityId if (getProviderName() != null && !this.loginsMap.isEmpty() && this.loginsMap.containsKey(getProviderName())) { /** * This is where you would call your backend **/ // now set the returned identity id and token in the provider update(identityId, token); return token; } else { // Otherwise call &COG; using getIdentityId of super class return super.getIdentityId(); } } else { return identityId; } }

iOS – objective-C

您的应用程序可能需要支持未经身份验证的身份或使用公有提供者(Login with Amazon、通过 Apple 登录、Facebook 或 Google)的经过身份验证的身份,以及经开发人员验证的身份。为此,请重写该AWSCognitoCredentialsProviderHelperlogins方法,以便能够根据当前身份提供者返回正确的登录映射。此示例说明如何能够在未经身份验证的身份、Facebook 和经开发人员验证的身份之间切换。

- (AWSTask<NSDictionary<NSString *, NSString *> *> *)logins { if(/*logic to determine if user is unauthenticated*/) { return [AWSTask taskWithResult:nil]; }else if (/*logic to determine if user is Facebook*/){ return [AWSTask taskWithResult: @{ AWSIdentityProviderFacebook : [FBSDKAccessToken currentAccessToken] }]; }else { return [super logins]; } }

当您从未经身份验证转换为经过身份验证时,您应该调用 [credentialsProvider clearCredentials]; 以强制开发工具包获取经过身份验证的新凭证。当您在两个经过身份验证的提供者之间切换并且不想将这两个提供者链接起来时(例如,您没有在登录词典中为多个提供者提供令牌),请调用 [credentialsProvider clearKeychain];。上述操作将清除凭证和身份,并强制开发工具包获取新的。

iOS – swift

您的应用程序可能需要支持未经身份验证的身份或使用公有提供者(Login with Amazon、通过 Apple 登录、Facebook 或 Google)的经过身份验证的身份,以及经开发人员验证的身份。为此,请重写该AWSCognitoCredentialsProviderHelperlogins方法,以便能够根据当前身份提供者返回正确的登录映射。此示例说明如何能够在未经身份验证的身份、Facebook 和经开发人员验证的身份之间切换。

override func logins () -> AWSTask<NSDictionary> { if(/*logic to determine if user is unauthenticated*/) { return AWSTask(result:nil) }else if (/*logic to determine if user is Facebook*/){ if let token = AccessToken.current?.authenticationToken { return AWSTask(result: [AWSIdentityProviderFacebook:token]) } return AWSTask(error:NSError(domain: "Facebook Login", code: -1 , userInfo: ["Facebook" : "No current Facebook access token"])) }else { return super.logins() } }

当您从未经身份验证转换为经过身份验证时,您应该调用 credentialsProvider.clearCredentials() 以强制开发工具包获取经过身份验证的新凭证。当您在两个经过身份验证的提供商之间切换并且不想将这两个提供商链接起来时 (即,您没有在登录词典中为多个提供商提供令牌),您应该调用 credentialsProvider.clearKeychain()。上述操作将清除凭证和身份,并强制开发工具包获取新的。

Unity

您的应用程序可能需要支持未经身份验证的身份或使用公有提供者(Login with Amazon、通过 Apple 登录、Facebook 或 Google)的经过身份验证的身份,以及经开发人员验证的身份。经开发人员验证的身份与其他身份(未经身份验证的身份和使用公共提供者的经过身份验证的身份)的主要区别在于 identityId 和令牌的获取方式。对于其他身份,移动应用程序将直接与 Amazon Cognito 进行交互,而不是与身份验证系统联系。移动应用程序应该能够支持两个不同的流程,具体取决于应用程序用户的选择。对此,您必须对自定义身份提供商做出一些更改。

在 Unity 中执行此操作的推荐方法是从 AmazonCognitoEnhancedIdentityProvide 而不是扩展您的身份提供商 AbstractCognitoIdentityProvider,并调用父 RefreshAsync 方法而不是您自己的方法,以防用户未使用您自己的后端进行身份验证。如果用户已经过身份验证,则您可以使用之前介绍的相同的流程。

Xamarin

您的应用程序可能需要支持未经身份验证的身份或使用公有提供者(Login with Amazon、通过 Apple 登录、Facebook 或 Google)的经过身份验证的身份,以及经开发人员验证的身份。经开发人员验证的身份与其他身份(未经身份验证的身份和使用公共提供者的经过身份验证的身份)的主要区别在于 identityId 和令牌的获取方式。对于其他身份,移动应用程序将直接与 Amazon Cognito 进行交互,而不是与身份验证系统联系。移动应用程序应该能够支持两个不同的流程,具体取决于应用程序用户的选择。对此,您必须对自定义身份提供者做出一些更改。