2

私はこれこのチュートリアルに従おうとしましたが、これがどのように行われるべきかはわかりません. CognitoSyncを使用していますが、同期サービスを開始しようとすると、 「Identity_id と dataset_name が一意ではありません」という例外に直面しています。

Amazon コンソールで 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", "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 を取得しています。

Android クラス

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 アプリからgetCredentials()が呼び出され、Java サーバー クラスからトークンと ID が取得されます。
  2. その後、トークンと ID がBYOIProvider クラスに渡されて更新されます。
  3. syncData()が呼び出され、CognitoCredentialProvider および BYOIProvider 変数が初期化されます。
  4. CognitoSyncManager は、CognitoCredentialProvider のオブジェクトで初期化されます。
  5. この後、例外エラーが発生します

列 identity_id と dataset_name が一意ではありません

このコード行で

データセット = client.openOrCreateDataset("MyData");

更新-1 (2014 年 11 月 11 日)

OK、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 (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)
4

1 に答える 1

2

Yangfan が述べたように、BYOIProvider.refresh() が null ではなくトークンを返すことを確認することが重要です。CognitoCachingCredentialsProvider によって内部的に呼び出され、そのトークンが使用されます。理想的には、サーバーとの通信は BYOIProvider クラスで行われます。そのクラスからのメソッド呼び出しは CognitoCachingCredentialsProvider で使用されるためです。

その更新呼び出しは重要です。それが通過するものであり、ID の変更 (問題の原因である可能性があります) の適切な処理とトークンの更新をトリガーします。そうするときは、実際に呼び出され、適切な token と identityId が必要です。getCredentials() 呼び出しがすべての適切なタイミングで使用される場合、トークンを返すことを保証するのに十分な場合がありますが、サーバーと通信するそのコードの一部を更新呼び出し内に移動する場合 (上記の更新)リターンを更新すると、それ自体が処理されます。

それでも問題が解決しない場合は、スタックトレースを投稿していただけますか?

編集:

よし、別の可能性が見えてきた。AWSAbstractCognitoIdentityProvider は、実際には identityId と token を追跡します。これらは、認証情報プロバイダーで内部的に使用されるものです。これは、資格情報プロバイダーが、設定している identityId とトークンを取得していないことを意味している可能性があります。これらは、ゲッターとセッターを介してアクセスできます。

さらに、setLogins()/withLogins() のドキュメントでは、ID ID が変更されている可能性があるため、プロバイダーにログインを追加した後、資格情報プロバイダーで手動で更新を呼び出す必要があると記載されています。ユーザーの ID ID は、認証されていない状態から認証された状態になると大きく変化します。

Edit2: ID が変更されると、いくつかのことが起こります。そのうちの 1 つは、データベースにローカルに保存されているデータセットで、古い ID ID へのリンクを削除し、新しい ID に追加する必要があります。そのアクションは、ID が変更されたリスナーがアクティブ化されるとトリガーされます。ID 変更リスナーは、初期化時に資格情報プロバイダーに登録されますが、ID プロバイダーからの更新呼び出し時にアクティブ化されます。そのため、順序はそれが行うものである必要があるため、データセットは適切な ID ID で保存され、このエラーは回避されます。

エラー自体は、次のワークフローによって引き起こされる可能性があります。1) 認証された ID ID b を使用してデータセット a を保存する 2) ID ID c を使用してデータセット a を保存する (認証されていない可能性が高いため) 3) ID ID b に戻す認証を行う。これにより、保存されたデータセットの親が c から b に変更され、一意でないエラーが表示されます。

したがって、基本的には、適切に処理されるように、適切な ID ID を使用して保存する必要があります。

于 2014-11-10T21:33:42.050 に答える