2

我试图遵循这个这个教程,但我不确定这是否应该这样做。我正在使用CognitoSync ,当我尝试启动Sync Service时,我遇到了“Identity_id and dataset_name not unique”的异常。

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

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

在安卓应用中

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", "nameid.number@provider.com");

        //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();
    }}

我已经为这个类创建了一个 web 服务,在另一个类Bridge 类中我正在调用这个函数,它将令牌和 id 发送到 Android 应用程序。这工作正常,我在 Android 应用程序中获取 Token 和 IdentityId。

安卓类

MainActivity 类

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 App调用getCredentials()从 Java Server Class 获取令牌和 id。
  2. 然后将 Token 和 Id 传递给BYOIProvider 类以更新它们。
  3. 调用 syncData()来初始化 CognitoCredentialProvider 和 BYOIProvider 变量。
  4. CognitoSyncManager 使用 CognitoCredentialProvider 的对象进行初始化。
  5. 在此之后我收到一个异常错误

列 identity_id 和 dataset_name 不是唯一的

在这行代码上

数据集 = client.openOrCreateDataset("MyData");

更新 1(2014 年 11 月 11 日)

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

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 (RefQueueWorker@org.apache.http.impl.conn.tsccm.ConnPoolByRoute@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() 之后

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

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 (14/11/2014)

我更新的代码和 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)
4

1 回答 1

2

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

更新电话很重要。这是经过并触发对身份更改的适当处理(这可能是导致您的问题的原因)和更新令牌。这样做时确实需要调用它并具有适当的令牌和身份标识。如果您的 getCredentials() 调用在所有适当的时间都被使用,那么确保它返回令牌就足够了,但是如果您要将与服务器通信的一些代码移动到刷新调用内部(更新之上)并更新返回,它会自行处理。

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

编辑:

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

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

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

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

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

于 2014-11-10T21:33:42.050 回答