java - Amazon Cognito 中的开发人员身份验证

标签 java android amazon-web-services authentication amazon-cognito

我试图关注thisthis教程,但我不确定这是否应该这样做。我正在使用 CognitoSync,但当我尝试启动同步服务时,遇到“Identity_id 和 dataset_name 不唯一” 异常。

在亚马逊控制台上,我创建了一个 IdentityPool 并给出了服务器端类的包名称,即“com.leversystems.devauth”作为 DeveloperProvider,并在服务器类和 Android 应用程序中使用了它。 在服务器类中

map.put("com.leversystems.devauth", "someUniqueId");

在 Android 应用程序中

logins.put("com.leversystems.devauth", cognitoProvider.getToken());

这是我的代码

Java 服务器端

package com.leversystems.devauth;
import java.util.HashMap;

import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.cognitoidentity.AmazonCognitoIdentityClient;
import com.amazonaws.services.cognitoidentity.model.GetOpenIdTokenForDeveloperIdentityRequest;
import com.amazonaws.services.cognitoidentity.model.GetOpenIdTokenForDeveloperIdentityResult;

public class DevAuth {

    private BasicAWSCredentials credentials = null;

    private String myAwsAccessKey = "myaccesskey";
    private String myAwsSecretKey = "mysecretkey";
    private String identityPoolID = "identityPoolid";
    private String authARN = "arn:aws:iam::782936514542:role/DefaultRole";

    private String identityId;
    private String token;

    public DevAuth()
    {
        identityId = "No id has been set yet!";
        token = "No token has been set yet!";
        initializeSecurity();
    }

    public String getToken()
    {
        return this.token;
    }

    public String getIdentityId()
    {
        return this.identityId;     
    }

    public void initializeSecurity(){

        credentials = new BasicAWSCredentials(myAwsAccessKey , myAwsSecretKey);
        AmazonCognitoIdentityClient client = 
          new AmazonCognitoIdentityClient(credentials);
        GetOpenIdTokenForDeveloperIdentityRequest tokenRequest = 
          new GetOpenIdTokenForDeveloperIdentityRequest();
        tokenRequest.setIdentityPoolId(identityPoolID);
        HashMap<String, String> map = new HashMap<String, String>();

        map.put("com.leversystems.devauth", "<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="8de3ece0e8e4e9a3e3f8e0efe8ffcdfdffe2fbe4e9e8ffa3eee2e0" rel="noreferrer noopener nofollow">[email protected]</a>");

        //Duration of the generated OpenID Connect Token
        tokenRequest.setLogins(map);

        tokenRequest.setTokenDuration(1000l);

        GetOpenIdTokenForDeveloperIdentityResult result 
           = client.getOpenIdTokenForDeveloperIdentity(tokenRequest);
        this.identityId = result.getIdentityId();
        this.token = result.getToken();
    }}

我已经制作了此类的网络服务,并且在另一个类Bridge Class中我正在调用此函数,它将 token 和ID发送到Android应用程序。这工作正常,我在 Android 应用程序中获取 Token 和 IdentityId。

Android 类

主 Activity 类

package com.leversystems.authserver;

import java.util.HashMap;
import java.util.List;

import android.app.Activity;
import android.os.Bundle;
import android.os.StrictMode;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.amazonaws.auth.AWSCognitoIdentityProvider;
import com.amazonaws.auth.CognitoCachingCredentialsProvider;
import com.amazonaws.mobileconnectors.cognito.CognitoSyncManager;
import com.amazonaws.mobileconnectors.cognito.Dataset;
import com.amazonaws.mobileconnectors.cognito.Dataset.SyncCallback;
import com.amazonaws.mobileconnectors.cognito.Record;
import com.amazonaws.mobileconnectors.cognito.SyncConflict;
import com.amazonaws.mobileconnectors.cognito.exceptions.DataStorageException;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.cognitoidentity.AmazonCognitoIdentity;
import com.amazonaws.services.cognitoidentity.model.GetOpenIdTokenForDeveloperIdentityRequest;
import com.amazonaws.services.cognitoidentity.model.GetOpenIdTokenForDeveloperIdentityResult;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;

public class MainActivity extends Activity {

AWSCognitoIdentityProvider cognitoProvider;
CognitoCachingCredentialsProvider credentialsProvider;
AmazonCognitoIdentity identityClient;
GetOpenIdTokenForDeveloperIdentityRequest idRequest;
GetOpenIdTokenForDeveloperIdentityResult idResp;
CognitoSyncManager client;

Dataset dataset;
TextView tv1;
TextView tv2;
TextView tv3;

Button btn1;
Button btn2;

final String ACC_ID = "myAccountID";
final String IDENTITY_POOL_ID = "identityPoolId";
final String AUTHORIZATION_ARN = "DefaultRole";
final String ACCESS_KEY = "myAccessKey";
final String SECRET_KEY = "mySecretKey";

Credentials cred;

public class Credentials {
    String identityId;
    String token;
}

            @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    playerName = (TextView) findViewById(R.id.textView1);
    currentLevel = (TextView) findViewById(R.id.textView2);
    highScore = (TextView) findViewById(R.id.textView3);

    btn1 = (Button) findViewById(R.id.button1);
    btn2 = (Button) findViewById(R.id.button2);
    btn3 = (Button) findViewById(R.id.button3);

    initCognito();

    btn1.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View arg0) {
            displayCogntioSyncData();
        }
    });

    btn2.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View arg0) {
            addCognitoSyncData();
        }
    });

    btn3.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            wipeCognitoSyncData();
        }
    });

}

private void initCognito() {

    StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
            .permitAll().build();
    StrictMode.setThreadPolicy(policy);

    AsyncHttpClient client = new AsyncHttpClient();
    client.get(
            "http://192.168.1.112:8080/AuthenticationService/services/auth/gctbda",
            new AsyncHttpResponseHandler() {
                // When the response returned by REST has Http response code
                // '200'
                @Override
                public void onSuccess(String response) {
                    try {
                        Gson gson = new Gson();
                        JsonParser jsonParser = new JsonParser();
                        JsonArray resultArray = jsonParser.parse(response)
                                .getAsJsonArray();

                        for (JsonElement credProvider : resultArray) {
                            cred = gson.fromJson(credProvider,
                                    Credentials.class);
                            BYOIProvider.identityId = cred.identityId;
                            BYOIProvider.token = cred.token;
                            System.out.println("Id: " + cred.identityId);
                            System.out.println("Token: " + cred.token);
                        }
                        syncCognito();
                    } catch (Exception e) {
                        System.err.println("Exception in OnSuccess: "
                                + e.getMessage());
                    }
                }
            });
}

private void syncCognito() {

    cognitoProvider = new BYOIProvider(ACC_ID, IDENTITY_POOL_ID);


    credentialsProvider = new CognitoCachingCredentialsProvider(
            getApplicationContext(), cognitoProvider, null,
            AUTHORIZATION_ARN);

    cognitoProvider.refresh();

    HashMap<String, String> logins = new HashMap<String, String>();

    logins.put("com.leversystems.devauth", cognitoProvider.getToken());

    credentialsProvider.setLogins(logins);

    credentialsProvider.refresh();

    client = new CognitoSyncManager(getApplicationContext(),
            IDENTITY_POOL_ID, Regions.US_EAST_1, credentialsProvider);

    dataset = client.openOrCreateDataset("GameInfo");

    synchronize();
}

private void wipeCognitoSyncData() {
    client.wipeData();
    dataset.delete();
    synchronize();
}

private void addCognitoSyncData() {

    dataset.put("playerName", "Muneeb");
    dataset.put("currentLevel", "29");
    dataset.put("highScore", "120345");

    synchronize();

}

private void displayCogntioSyncData() {
    synchronize();

    playerName.setText(dataset.get("playerName"));
    currentLevel.setText(dataset.get("currentLevel"));
    highScore.setText(dataset.get("highScore"));

}

private void synchronize() {

    dataset.synchronize(new SyncCallback() {

        @Override
        public boolean onConflict(Dataset arg0, List<SyncConflict> arg1) {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        public boolean onDatasetDeleted(Dataset arg0, String arg1) {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        public boolean onDatasetsMerged(Dataset arg0, List<String> arg1) {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        public void onFailure(DataStorageException arg0) {
            System.err.println("Error onSyncro: " + arg0.getMessage());
        }

        @Override
        public void onSuccess(Dataset arg0, List<Record> arg1) {
            System.out.println("Dataset Synchronized!");
        }
    });

}
}

BYOIProvider 类

package com.leversystems.authserver;

import com.amazonaws.auth.AWSAbstractCognitoIdentityProvider;

public class BYOIProvider extends AWSAbstractCognitoIdentityProvider {

    public static String id;
    public static String token;


    public BYOIProvider(String acctId, String identityPoolId) {
        super(acctId, identityPoolId);

    }

    @Override
    public String getProviderName() {

        return "com.leversystems.devauth";
    }

    @Override
    public String refresh() {
        update(id, token);
        return null;
    }
}

工作流程

  1. 从 Android 应用程序中,单击按钮时,将调用 getCredentials(),从 Java 服务器类获取 token 和 ID。
  2. 然后将 token 和 Id 传递给 BYOIProvider 类以更新它们。
  3. syncData() 被调用,用于初始化 CognitoCredentialProvider 和 BYOIProvider 变量。
  4. CognitoSyncManager 使用 CognitoCredentialProvider 的对象进行初始化。
  5. 此后我收到一个异常错误

columns identity_id and dataset_name are not unique

在这行代码

dataset = client.openOrCreateDataset("MyData");

更新 1(2014 年 11 月 11 日)

好的,我现在已经将refresh()的返回字符串更改为token变量,这是堆栈跟踪。

11-11 12:58:52.196: I/View(29237): Touch down dispatch to android.widget.Button{4186d880 VFED..C. ........ 206,342-417,438 #7f080003 app:id/button1}, event = MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=76.0, y[0]=34.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=228482273, downTime=228482273, deviceId=2, source=0x1002 }
11-11 12:58:52.213: D/GraphicBuffer(29237): create handle(0x5ed83e60) (w:720, h:1280, f:1)
11-11 12:58:52.222: I/SurfaceTextureClient(29237): [STC::queueBuffer] (this:0x5d12eb78) fps:0.10, dur:20282.80, max:20162.90, min:119.90
11-11 12:58:52.222: I/SurfaceTextureClient(29237): [STC::queueBuffer] this:0x5d12eb78, api:1, last queue time elapsed:20162.90
11-11 12:58:52.326: I/View(29237): Touch up dispatch to android.widget.Button{4186d880 VFED..C. ...P.... 206,342-417,438 #7f080003 app:id/button1}, event = MotionEvent { action=ACTION_UP, id[0]=0, x[0]=76.0, y[0]=34.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=228482404, downTime=228482273, deviceId=2, source=0x1002 }
11-11 12:58:52.327: V/Provider/Settings(29237):  from settings cache , name = sound_effects_enabled , value = 0
11-11 12:58:52.328: D/dalvikvm(29237): create interp thread : stack size=128KB
11-11 12:58:52.328: D/dalvikvm(29237): create new thread
11-11 12:58:52.328: D/dalvikvm(29237): new thread created
11-11 12:58:52.328: D/dalvikvm(29237): update thread list
11-11 12:58:52.329: D/dalvikvm(29237): threadid=15: interp stack at 0x60115000
11-11 12:58:52.329: D/dalvikvm(29237): threadid=15: created from interp
11-11 12:58:52.329: D/dalvikvm(29237): start new thread
11-11 12:58:52.329: D/dalvikvm(29237): threadid=15: notify debugger
11-11 12:58:52.329: D/dalvikvm(29237): threadid=15 (<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f2a09794a387978797a59d80999780b29d8095dc938293919a97dc9a868682dc9b9f829edc919d9c9cdc868191919fdcb19d9c9ca29d9d9eb08ba09d878697" rel="noreferrer noopener nofollow">[email protected]</a>@419852e8): calling run()
11-11 12:58:52.330: I/System.out(29237): httpget:http://192.168.1.112:8080/AuthenticationService/services/auth/gctbda
11-11 12:58:52.331: I/System.out(29237): http://192.168.1.112:8080/AuthenticationService/services/auth/gctbda
11-11 12:58:52.331: D/dalvikvm(29237): create interp thread : stack size=128KB
11-11 12:58:52.331: D/dalvikvm(29237): create new thread
11-11 12:58:52.332: D/dalvikvm(29237): new thread created
11-11 12:58:52.332: D/dalvikvm(29237): update thread list
11-11 12:58:52.332: D/dalvikvm(29237): threadid=16: interp stack at 0x60235000
11-11 12:58:52.332: D/dalvikvm(29237): threadid=16: created from interp
11-11 12:58:52.332: D/dalvikvm(29237): start new thread
11-11 12:58:52.333: D/dalvikvm(29237): threadid=16: notify debugger
11-11 12:58:52.333: D/dalvikvm(29237): threadid=16 (pool-3-thread-1): calling run()
11-11 12:58:52.336: I/System.out(29237): [socket][1] connection /192.168.1.112:8080;LocalPort=35830(10000)
11-11 12:58:52.336: I/System.out(29237): [CDS]connect[/192.168.1.112:8080] tm:10
11-11 12:58:52.336: D/Posix(29237): [Posix_connect Debug]Process com.leversystems.authserver :8080 
11-11 12:58:52.358: I/System.out(29237): [socket][/192.168.1.136:35830] connected
11-11 12:58:52.358: I/System.out(29237): [CDS]rx timeout:10000
11-11 12:58:52.358: I/System.out(29237): [CDS]SO_SND_TIMEOUT:0
11-11 12:58:52.360: I/System.out(29237): >doSendRequest
11-11 12:58:52.361: I/System.out(29237): <doSendRequest
11-11 12:58:53.259: I/AmazonWebServiceClient(29237): {cognito-sync, us-east-1} was not found in region metadata, trying to construct an endpoint using the standard pattern for this region: 'cognito-sync.us-east-1.amazonaws.com'.
11-11 12:58:53.259: D/CognitoCachingCredentialsProvider(29237): Identity id is changed
11-11 12:58:53.259: D/CognitoCachingCredentialsProvider(29237): Saving identity id to SharedPreferences
11-11 12:58:53.260: I/CognitoSyncManager(29237): identity change detected
11-11 12:58:53.271: W/System.err(29237): Exception in OnSuccess: columns identity_id, dataset_name are not unique (code 19)

更新 2(2014 年 11 月 13 日)

添加

credentialsProvider.refresh();

setLogins()/withLogins()之后

现在,如果我尝试错误的标记,它会给出相应的异常。当我提供的 token 正确时,它会给我这个异常

Exception in onSuccess: Not authorized to perform sts:AssumeRoleWithWebIdentity (Service: AWSSecurityTokenService; Status Code: 403; Error Code: AccessDenied; Request ID: *SomeID*)

更新 3(2014 年 11 月 13 日)

好的,我已经在 IAM 控制台上创建了一个新角色。 Update-2 中的异常现已明确。下一个问题与第一个问题相同。我在 AsyncHttpClient 中收到的确切异常是

11-13 15:40:41.738: I/AmazonWebServiceClient(23921): {cognito-sync, us-east-1} was not found in region metadata, trying to construct an endpoint using the standard pattern for this region: 'cognito-sync.us-east-1.amazonaws.com'.
11-13 15:40:41.739: D/CognitoCachingCredentialsProvider(23921): Identity id is changed
11-13 15:40:41.739: D/CognitoCachingCredentialsProvider(23921): Saving identity id to SharedPreferences
11-13 15:40:41.740: I/CognitoSyncManager(23921): identity change detected
11-13 15:40:41.749: W/System.err(23921): Exception in OnSuccess: columns identity_id, dataset_name are not unique (code 19)

更新 4(2014 年 11 月 14 日)

我更新的代码和 StackTrace

代码:

credentialsProvider = new CognitoCachingCredentialsProvider(
            getApplicationContext(), cognitoProvider, null,
            AUTHORIZATION_ARN);

cognitoProvider.refresh();

堆栈跟踪:

11-14 11:25:01.357: I/AmazonWebServiceClient(31084): {cognito-sync, us-east-1} was not found in region metadata, trying to construct an endpoint using the standard pattern for this region: 'cognito-sync.us-east-1.amazonaws.com'.
11-14 11:25:01.358: D/CognitoCachingCredentialsProvider(31084): Identity id is changed
11-14 11:25:01.358: D/CognitoCachingCredentialsProvider(31084): Saving identity id to SharedPreferences
11-14 11:25:01.358: I/CognitoSyncManager(31084): identity change detected
11-14 11:25:01.367: W/System.err(31084): Exception in OnSuccess: columns identity_id, dataset_name, key are not unique (code 19)

最佳答案

正如 Yangfan 提到的,确保 BYOIProvider.refresh() 返回 token 而不是 null 非常重要。它由 CognitoCachingCredentialsProvider 在内部调用,并使用该 token 。理想情况下,与服务器的通信将在 BYOIProvider 类中进行,因为来自该类的方法调用在 CognitoCachingCredentialsProvider 中使用。

这次更新电话很重要。它会经历并触发对身份更改(这可能是导致您的问题的原因)和更新 token 的适当处理。这样做时确实需要调用它并具有适当的 token 和identityId。如果在所有适当的时间使用 getCredentials() 调用,则足以确保它返回 token ,但是如果您要将与服务器通信的部分代码移至刷新调用内部(更新上方)并更新返回,它会自行处理。

如果这不能解决您的问题,您可以发布您的堆栈跟踪吗?

编辑:

好吧,我看到了另一种可能性。 AWSAbstractCognitoIdentityProvider 实际上会跟踪 IdentityId 和 token - 这些是凭证提供程序内部使用的内容。这可能意味着凭据提供程序未获取您正在设置的 IdentityId 和 token 。这些可以通过 getter 和 setter 访问。

此外,在 setLogins()/withLogins() 的文档中,它表示您应该在向提供程序添加登录名后手动调用凭据提供程序的刷新,因为您的身份 ID 可能已更改。用户从未经身份验证变为经过身份验证后,其身份 ID 会发生很大变化。

编辑2: 当身份发生变化时,会发生一些事情 - 其中之一是本地存储在数据库中的数据集需要从旧身份 ID 的链接中删除并添加到新身份 ID 中。该操作在身份更改监听器被激活时触发。身份更改监听器在初始化时注册到凭据提供程序,但在来自身份提供程序的更新调用时激活。这就是为什么顺序需要是它所做的,因此数据集使用适当的身份 ID 保存,并且可以避免此错误。

错误本身可能是由以下工作流程引起的: 1)使用经过身份验证的身份id b保存数据集a 2)使用身份ID c保存数据集a(很可能是未经身份验证) 3) 验证身份 id b。这会将保存的数据集从 c 重新设置为 b 的父级,并导致出现非唯一错误。

因此,基本上,您必须确保在保存时使用适当的身份 ID 进行保存,以便正确处理。

关于java - Amazon Cognito 中的开发人员身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26826546/

相关文章:

Java 的 equals 和 hashmap 问题

java - 什么时候应该将一个多模块项目拆分成单独的存储库树?

java - hibernate 标准是否有任何标准来涵盖列表的包含条件

android - 在多个设备上同步播放音乐

amazon-web-services - Redshift Spectrum 如何扫描数据?

java - Google Fit dataRead 返回状态 TIMEOUT

android - 我可以让市场更新从其他地方安装的应用程序吗?

java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用

amazon-web-services - 如何使用awslog驱动程序从docker容器获取日志?

amazon-web-services - 如何在 Amazon Linux 2 上配置 nginx?