概要
ユーザDBとその認証認可をセットで提供しているサービスはたくさんありますが、一つの問題としてそのサービスにユーザデータがロックインされちゃう問題があります。
それを回避するためには自分たちでユーザDBについてはデータモデリングを行い、認証と認可の部分は別のサービスに任せるというソリューションが最高なんじゃないかと考えて、Auth0とDynamoDBで実現できるか検証しました。結論としてはAuth0のCustom Databaseの仕組みを使うことで出来ました。
Clientアプリケーションの設定
- Auth0のサイトへアクセスしてまずはアカウントを作成してください
- Create Applicationからアプリケーションを作ります
- QuickStartで使いたいテクノロジーを選択します
- 認証画面のサンプルコードが用意されてるのでそれをダウンロードしましょう
- ダウンロードしたサンプルのapp.jsを開いてdomainやclientIDの設定を行います。
var webAuth = new auth0.WebAuth({
domain: 'horike37.auth0.com',
clientID: 'KJ28cvUXP5OFbmwzc0BK09ce3BKKxRgs',
redirectUri: window.location.href,
responseType: 'token id_token',
scope: 'openid',
leeway: 60
});
設定できたら、npm install & npm start
を実行して、http://localhost:3000にアクセスします。
Custom Databaseの設定
- Auth0ダッシュボードの左メニューより、Connections > DatabaseからUsername-Password-Authenticationを選択します
- Custom Databaseのタブを選択するとログインやサインアップ、パスワード変更などを実行するScriptを実装する画面にたどり着きます。まずは最低限のログインとサインアップでDynamoDBのユーザテーブルを使うようにしてみましょう
- DyanoDBには以下のようなuser_idをパーティションキーとするテーブルを定義します
サインアップの実装
メールアドレスとパスワードをDBに登録します。注:このサンプルコードは動くことしか考えてない、非常に質の低いコードなので本番等ではコピペで使わないでね
function create(user, callback) {
var aws = require('aws-sdk');
aws.config.update({
accessKeyId: '<accessKeyId>',
secretAccessKey: '<secretAccessKey>',
region: 'us-east-1'
});
var dynamodb = new aws.DynamoDB();
bcrypt.hash(user.password, 10, function (err, hash) {
if (err) { return callback(err); }
var params = {
Item: {
"id": {
S: user.email
},
"password": {
S: hash
},
},
TableName: "users"
};
dynamodb.putItem(params, function(err, data) {
if (err) return callback(err); // an error occurred
else return callback(null); // successful response
});
});
}
ログインの実装
入力されたメールアドレスとパスワードをDB渡して検証します。注:このサンプルコードは動くことしか考えてない、非常に質の低いコードなので本番等ではコピペで使わないでね
function login(email, password, callback) {
var aws = require('aws-sdk');
aws.config.update({
accessKeyId: '<accessKeyId>',
secretAccessKey: '<secretAccessKey>',
region: 'us-east-1'
});
var dynamodb = new aws.DynamoDB();
var params = {
Key: {
"id": {
S: email
},
},
TableName: "users"
};
dynamodb.getItem(params, function(err, data) {
if (err) return callback(err);
else {
bcrypt.compare(password, data.Item.password.S, function (err, isValid) {
if (err) {
callback(err);
} else if (!isValid) {
callback(new WrongUsernameOrPasswordError(email));
} else {
callback(null, {
email: data.Item.id
});
}
});
}
});
}
動作確認
では先程の認証画面に戻ってサインアップを試してみます。
SIGN UPをクリックするとうまく行ったようです。
DynamoDBのデータ確認すると。。うおーーー!!!ちゃんとデータ出来てる!!
というわけで、Auth0 + DynamoDBがユーザディレクトリとしてベンダーロックイン、スケーラビリティの観点からかなり良いんじゃないかと思います。