

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

# 经开发人员验证的身份
<a name="developer-authenticated-identities"></a>

除了通过 [将 Facebook 设置为身份池 IdP](facebook.md)、[将 Google 设置为身份池 IdP](google.md)、[设置 Login with Amazon 作为身份池 IdP](amazon.md) 和 [使用 Apple 作为身份池 IdP 来设置登录](apple.md) 的 Web 身份联合验证之外，Amazon Cognito 还支持经开发人员验证的身份。使用经过开发人员身份验证的身份，您可以通过自己的现有身份验证流程注册和验证用户，同时仍可以使用 Amazon Cognito 同步用户数据和访问资源。 AWS 使用经开发人员验证的身份涉及最终用户设备、身份验证后端和 Amazon Cognito 之间的交互。有关更多详细信息，请参阅博客中的[了解 Amazon Cognito 身份验证第 2 部分：经过开发人员身份验证的 AWS 身份](https://aws.amazon.com/blogs/mobile/understanding-amazon-cognito-authentication-part-2-developer-authenticated-identities/)。

## 了解身份验证流程
<a name="understanding-the-authentication-flow"></a>

[GetOpenIdTokenForDeveloperIdentity](https://docs.aws.amazon.com/cognitoidentity/latest/APIReference/API_GetOpenIdTokenForDeveloperIdentity.html)API 操作可以为增强身份验证和基本身份验证启动开发者身份验证。此 API 使用管理凭证对请求进行身份验证。`Logins` 映射是身份池开发人员提供者的名称，例如与自定义标识符配对的 `login.mydevprovider`。

示例：

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

**增强型身份验证**

使用包含令牌名称`cognito-identity.amazonaws.com`和值`Logins`的地图调用 [GetCredentialsForIdentity](https://docs.aws.amazon.com/cognitoidentity/latest/APIReference/API_GetCredentialsForIdentity.html)API 操作`GetOpenIdTokenForDeveloperIdentity`。

示例：

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

`GetCredentialsForIdentity` 使用经开发人员验证的身份，它会返回身份池中默认经过身份验证的角色的临时凭证。

**基本身份验证**

调用 [AssumeRoleWithWebIdentity](https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html)API 操作并请求已[定义适当信任关系`RoleArn`的任何 IAM 角色的](iam-roles.md#role-trust-and-permissions)。将 `WebIdentityToken` 的值设置为从 `GetOpenIdTokenForDeveloperIdentity` 获取令牌。

要了解经开发人员验证的身份的身份验证流程以及该流程与外部提供者身份验证流程有何不同，请参阅[身份池身份验证流程](authentication-flow.md)。

## 定义开发人员提供商名称并将其与身份池关联
<a name="associate-developer-provider"></a>

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

**添加自定义开发人员提供者**

1. 从 [Amazon Cognito 控制台](https://console.aws.amazon.com/cognito/home)中选择**身份池**。选择身份池。

1. 选择**用户访问**选项卡。

1. 选择**添加身份提供者**。

1. 选择**自定义开发人员提供者**。

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

1. 选择**保存更改**。

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

## 实施身份提供商
<a name="implement-an-identity-provider"></a>

### Android
<a name="implement-id-provider-1.android"></a>

要使用经开发人员验证的身份，请实施自己的身份提供者类，该类可扩展 `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
<a name="implement-id-provider-1.ios-objc"></a>

要使用经开发人员验证的身份，请实施自己的身份提供者类，该类可扩展 [AWSCognitoCredentialsProviderHelper](https://github.com/aws-amplify/aws-sdk-ios)。您的身份提供者类应返回包含令牌作为属性的响应对象。

```
@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];
    }
}
```

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

```
- (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
<a name="implement-id-provider-1.ios-swift"></a>

要使用经开发人员验证的身份，请实施自己的身份提供者类，该类可扩展 [AWSCognitoCredentialsProviderHelper](https://github.com/aws-amplify/aws-sdk-ios)。您的身份提供者类应返回包含令牌作为属性的响应对象。

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

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

```
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
<a name="implement-id-provider-1.javascript"></a>

从后端获取身份 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
<a name="implement-id-provider-1.unity"></a>

要使用经开发人员验证的身份，您必须扩展 `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
<a name="implement-id-provider-1.xamarin"></a>

要使用经开发人员验证的身份，您必须扩展 `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）
<a name="updating-the-logins-map"></a>

### Android
<a name="updating-logins-map-1.android"></a>

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

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

credentialsProvider.setLogins(loginsMap);
credentialsProvider.refresh();
```

### iOS – objective-C
<a name="updating-logins-map-1.ios-objc"></a>

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

```
[credentialsProvider clearCredentials];
```

### iOS – swift
<a name="updating-logins-map-1.ios-swift"></a>

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

```
credentialsProvider.clearCredentials()
```

## 获取令牌（服务器端）
<a name="getting-a-token-server-side"></a>

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

对于由 `GetOpenIdTokenForDeveloperIdentity` 返回的令牌，您需要注意以下事项：
+ 您可以指定令牌的自定义过期时间，以便缓存。如果您不提供任何自定义过期时间，则令牌的有效期为 15 分钟。
+ 您可以设置的最大令牌持续时间为 24 小时。
+ 请留意延长令牌持续时间所带来的安全方面的问题。如果攻击者获得此令牌，他们可以在令牌有效期内将其交换为最终用户的 AWS 凭证。

以下 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
//...
```

按照上述步骤操作，您应该能够将经开发人员验证的身份集成到应用程序中。如有任何问题或疑问，请随时在我们的[论坛](https://forums.aws.amazon.com/forum.jspa?forumID=173)上发帖。

## 连接到现有社交身份
<a name="connect-to-an-existing-social-identity"></a>

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

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

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

## 支持在提供商之间转换
<a name="supporting-transition-between-providers"></a>

### Android
<a name="support-transition-between-providers-1.android"></a>

您的应用程序可能需要支持未经身份验证的身份或使用公有提供者（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
<a name="support-transition-between-providers-1.ios-objc"></a>

您的应用程序可能需要支持未经身份验证的身份或使用公有提供者（Login with Amazon、通过 Apple 登录、Facebook 或 Google）的经过身份验证的身份，以及经开发人员验证的身份。为此，请重写该[AWSCognitoCredentialsProviderHelper](https://github.com/aws-amplify/aws-sdk-ios)`logins`方法，以便能够根据当前身份提供者返回正确的登录映射。此示例说明如何能够在未经身份验证的身份、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
<a name="support-transition-between-providers-1.ios-swift"></a>

您的应用程序可能需要支持未经身份验证的身份或使用公有提供者（Login with Amazon、通过 Apple 登录、Facebook 或 Google）的经过身份验证的身份，以及经开发人员验证的身份。为此，请重写该[AWSCognitoCredentialsProviderHelper](https://github.com/aws-amplify/aws-sdk-ios)`logins`方法，以便能够根据当前身份提供者返回正确的登录映射。此示例说明如何能够在未经身份验证的身份、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
<a name="support-transition-between-providers-1.unity"></a>

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

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

### Xamarin
<a name="support-transition-between-providers-1.xamarin"></a>

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