あくまでもサンプルです。このままは使えないかと
組み合わせれば、なんとかなりそうなパターンを整理
サーバー上でcoginitoを使ってますが、
セッションエラーになるので基本はクライアントサイドで実行します。
#やりたいこと
- 未認証のRequestは、coginto.identityIdを返却
- 外部サービス認証のIDでcoginto.identityIdを参照
- Authロールにcredentialを更新
- 外部サービス認証時に認証情報をDatasetに保存
- coginto.identityIdからDatasetを参照
今回は後に共通処理としてまとめれる用に、ひとつのexports.handler
でまとめてある(手抜き)
appIdは本来、認証をするためのパラメータ(id,pass)とか
####実行環境
- Amazon API Gateway
- Lambda (Node.js runtime)
- Cognito
####npm
var _ = require('lodash');
var Q = require("q");
var AWS = require('aws-sdk');
AWSはlambdaで実行するのに必要ではないけども、ローカル開発用
Qはlambdaのnodejsが0.10.36
なので
lambda current-supported-versions
未認証のRequestは、coginto.identityIdを返却
とりあえずGETでidentityIdを送る前提
var identityId = null;
var createUser = function(data){
var d = Q.defer();
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityId: identityId,
IdentityPoolId: IDENTITY_POOLID
});
AWS.config.credentials.get(function(err) {
if (err) {
d.resolve({success: false});
return;
}
identityId = AWS.config.credentials.identityId;
d.resolve({
identityId: identityId
});
});
return d.promise;
}
外部サービス認証のIDでcoginto.identityIdを参照
my.app
はcognitoで設定したもの
本来はここで独自認証の処理を行い、userIDやtokenをLoginに登録
setTimeoutは認証の代わり
TokenはAuthenticated RoleでのAWSの接続に利用(今回はつかっていない)
var authUser = function(data){
var d = Q.defer();
//ここで外部認証処理...
setTimeout(function(){
//結果を保持する
var params = {
IdentityPoolId: IDENTITY_POOLID,
IdentityId: identityId,
Logins: {
'my.app': data.user
}
};
cognitoidentity.getOpenIdTokenForDeveloperIdentity(params, function(err, res){
if(err){
d.resolve({success: false});
return;
}
identityId = res.IdentityId;
d.resolve(res);
});
}, 500);
return d.promise;
};
Authロールにcredentialを更新
getOpenIdTokenForDeveloperIdentityで取得したTokenでcredentialを更新することで、ロールを切り変える
cognitoidentity.getOpenIdTokenForDeveloperIdentity(params, function(err, res){
if(err){
return;
}
//credentialを更新
AWS.config.credentials = new AWS.WebIdentityCredentials({
RoleArn: "arn:aws:iam:xxxxxxx:role/Cognito_myAppAuth_Role",
WebIdentityToken: res.Token
});
var dynamodb = new AWS.DynamoDB();
dynamodb.scan({
TableName: 'xxxxxx'
},function(err,data){
//tableを取得
});
});
coginto.identityIdからDatasetを参照
ここはそのまま
var cognitosync = new AWS.CognitoSync();
var listData = function(data){
var d = Q.defer();
if(!identityId){
d.resolve({
success: false
});
return d.promise;
}
cognitosync.listRecords({
DatasetName: COGNITO_DATASET_NAME,
IdentityId: identityId,
IdentityPoolId: IDENTITY_POOLID
}, function(err, res){
if (err) {
d.resolve({success: false});
return;
}
console.log(parseData(res.Records));
d.resolve(res);
});
return d.promise;
};
外部サービス認証時に認証情報をDatasetに保存
Recordに外部接続情報等を保持
var addData = function(data) {
var d = Q.defer();
if(!identityId){
d.resolve({
success: false
});
return d.promise;
}
var params = {
DatasetName: COGNITO_DATASET_NAME,
IdentityId: identityId,
IdentityPoolId: IDENTITY_POOLID,
SyncSessionToken: data.SyncSessionToken,
RecordPatches: [{
Key: 'USER_ID',
Op: 'replace',
SyncCount: data.DatasetSyncCount,
Value: 'aaaaaaaaaaaaa'
}]
};
cognitosync.updateRecords(params, function(err, data) {
if(err){
d.resolve({success: false});
return;
}
d.resolve(parseData(data.Records));
});
return d.promise;
}
#実行結果
###identityIdなし
https://xxxxxxx.execute-api.ap-northeast-1.amazonaws.com/production/cognito
{
identityId: "ap-northeast-1:2b967234-8a98-4dbf-945f-ba9581981a06"
}
###identityIdあり
https://xxxxxxx.execute-api.ap-northeast-1.amazonaws.com/production/cognito?identityId=ap-northeast-1:2b967234-8a98-4dbf-945f-ba9581981a06
{
identityId: "ap-northeast-1:2b967234-8a98-4dbf-945f-ba9581981a06",
userdata: {
USER_ID: "aaaaaaaaaaaaa"
}
}
###外部の認証情報(appId)を渡す
https://xxxxxxx.execute-api.ap-northeast-1.amazonaws.com/production/cognito?appId=user1
{
identityId: "ap-northeast-1:dc94f109-993a-457e-b40e-86042a1fbe67",
userdata: {
USER_ID: "aaaaaaaaaaaaa"
}
}
identityId, appId の優先度
appIdが優先される。
Identity poolに既にある場合はLinked logins:DISABLED
となる
全文
アカウントはダミー
/**
* cognito test
*
*/
"use strict";
var _ = require('lodash');
var Q = require("q");
var AWS = require('aws-sdk');
AWS.config.region = 'ap-northeast-1';
var IDENTITY_POOLID = 'ap-northeast-1:XXXXXXXXX';
var COGNITO_DATASET_NAME = 'userData';
var cognitoidentity = new AWS.CognitoIdentity();
var cognitosync = new AWS.CognitoSync();
var identityId = null;
/**
* 認証情報がない場合はUnauthenticated Userを作成
*/
var createUser = function(data){
var d = Q.defer();
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityId: identityId,
IdentityPoolId: IDENTITY_POOLID
});
AWS.config.credentials.get(function(err) {
if (err) {
d.resolve({success: false});
return;
}
identityId = AWS.config.credentials.identityId;
d.resolve({
identityId: identityId
});
});
return d.promise;
}
/**
* Developer Authenticated 認証
*/
var authUser = function(data){
var d = Q.defer();
//ここで外部認証処理...
setTimeout(function(){
//結果を保持する
var params = {
IdentityPoolId: IDENTITY_POOLID,
IdentityId: identityId,
Logins: {
'my.app': data.user
}
};
cognitoidentity.getOpenIdTokenForDeveloperIdentity(params, function(err, res){
if(err){
d.resolve({success: false});
return;
}
identityId = res.IdentityId;
d.resolve(res);
});
}, 500);
return d.promise;
};
/**
* List store Data
*/
var listData = function(data){
var d = Q.defer();
if(!identityId){
d.resolve({
success: false
});
return d.promise;
}
cognitosync.listRecords({
DatasetName: COGNITO_DATASET_NAME,
IdentityId: identityId,
IdentityPoolId: IDENTITY_POOLID
}, function(err, res){
if (err) {
d.resolve({success: false});
return;
}
console.log(parseData(res.Records));
d.resolve(res);
});
return d.promise;
};
/**
* add store Data
*/
var addData = function(data) {
var d = Q.defer();
if(!identityId){
d.resolve({
success: false
});
return d.promise;
}
var params = {
DatasetName: COGNITO_DATASET_NAME,
IdentityId: identityId,
IdentityPoolId: IDENTITY_POOLID,
SyncSessionToken: data.SyncSessionToken,
RecordPatches: [{
Key: 'USER_ID',
Op: 'replace',
SyncCount: data.DatasetSyncCount,
Value: 'aaaaaaaaaaaaa'
}]
};
cognitosync.updateRecords(params, function(err, data) {
if(err){
d.resolve({success: false});
return;
}
d.resolve(parseData(data.Records));
});
return d.promise;
}
/**
* Records を Object に変換
*/
var parseData= function(rec){
var obj = {};
_.each(rec, function(r){
obj[r.Key] = r.Value;
});
return obj;
};
exports.handler = function (e, context) {
var query = e.queryParameters || {};
//認証情報ない
if(!query.identityId && !query.appId){
createUser().done(function(res){
context.succeed(res);
});
return;
}
//appIdがない
if(!query.appId){
identityId = query.identityId;
Q.when()
.then(createUser)
.then(listData)
.then(addData)
.done(function(res){
context.succeed({
identityId:identityId,
userdata:res
});
});
return;
}
if(query.identityId) {
identityId = query.identityId;
}
Q.when({
user: query.appId
})
.then(authUser)
.then(listData)
.then(addData)
.done(function(res){
context.succeed({
identityId:identityId,
userdata:res
});
});
};
#参考リンク