getUser にすることを推奨します。
このスクリプトは、自動移行では必須であり、レガシー認証では接続に設定されている操作に応じて条件付きで必須になります。重複するユーザーが作成されるのを防ぐため、返されるユーザープロファイルには永続的な user_id を設定することを Auth0 では推奨しています。
接続で自動移行が設定されていて、ユーザープロファイルがまだ作成されていない場合、このスクリプトは次の操作が発生するたびに実行されます。
- メールアドレスの変更
- サインアップ
- パスワードリセット
- ユーザーの作成
- メールアドレスの変更
- パスワードの変更
- パスワードリセット
Get User 関数
getUser 関数では、次の処理を行う必要があります。
- ユーザーの識別子を外部データベースの API に送信する。
- ユーザーが見つかった場合は、そのプロファイルデータを返す。
- ユーザーが存在するかどうかの判定中に問題が発生した場合は、エラーを返す。
定義
getUser 関数は 2 つのパラメーターを受け取り、callback 関数を返します。
getUser(email, callback): function
| パラメーター | 型 | 説明 |
|---|---|---|
email | String | ユーザーのメールアドレス。 |
callback | Function | エラーまたはプロファイルデータをパイプラインに渡すために使用します |
例
これは、getUser 関数の実装方法を示す擬似 JavaScript の例です。言語ごとの例については、言語別のスクリプト例を参照してください。
function getUser(email, callback) {
// ユーザー識別子を外部データベースAPIに送信する
let options = {
url: "https://example.com/api/search-users",
body: {
email: email
}
};
send(options, (err, profileData) => {
// ユーザーの検索中に問題が発生した場合、コールバックでエラーを返す
if (err) {
return callback(new Error("Could not determine if user exists or not."));
} else {
// ユーザーが見つからなかった場合はコールバックでnullを返し、見つかった場合はプロファイルデータを返す
if (!profileData) {
return callback(null);
} else {
let profile = {
email: profileData.email,
user_id: profileData.userId
};
return callback(null, profile);
}
}
});
}
コールバック関数
callback 関数は、ユーザープロファイルのデータまたはエラーデータをパイプライン内で受け渡すために使用されます。
定義
callback 関数は最大2つのパラメーターを受け取り、関数を返します。
callback(error[,profile]): function
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
error | Object | 必須 | エラーデータを含みます。 |
profile | Object | 任意 | ユーザーのプロフィールデータを含みます。 |
ユーザープロファイルを返す (ユーザーが見つかった場合)
ユーザーに対して Get User スクリプトが返すプロファイルデータは、Login スクリプトが返すプロファイルデータと一致している必要があります。
error パラメータに null を渡し、profile パラメータにユーザーのプロファイルデータを正規化形式で渡します。標準フィールドに加えて、user_metadata、app_metadata、mfa_factors フィールドも含めることができます。
例
return callback(null, {
username: "username",
user_id: "my-custom-db|username@domain.com",
email: "username@domain.com",
email_verified: false,
user_metadata: {
language: "en"
},
app_metadata: {
plan: "full"
},
mfa_factors: [
{
phone: {
value: "+15551234567"
}
},
]
});
ユーザープロファイルを返さない (ユーザーが見つからない場合)
error パラメーターに null を渡し、profile パラメーターは省略します。
例
return callback(null);
エラーを返す
error パラメーターに渡します。詳細については、カスタムデータベースのトラブルシューティングを参照してください。
例
return callback(new Error("My custom error message."));
言語別のスクリプト例
- JavaScript
- ASP.NET Membership Provider (MVC3 - Universal Providers)
- ASP.NET Membership Provider (MVC4 - Simple Membership)
- MongoDB
- MySQL
- PostgreSQL
- SQL Server
- Windows Azure SQL Database
- Axios
- Stormpath
JavaScript
function getByEmail(email, callback) {
// このスクリプトは、ユーザーを認証せずに既存のデータベースからユーザープロファイルを取得します。
// 認証を必要としないフロー(サインアップおよびパスワードリセット)を実行する前に、
// ユーザーが存在するかどうかを確認するために使用されます。
//
// このスクリプトの終了パターンは3通りあります:
// 1. ユーザーが正常に見つかった場合。プロファイルは以下の形式である必要があります:
// https://auth0.com/docs/users/normalized/auth0/normalized-user-profile-schema
// callback(null, profile);
// 2. ユーザーが見つからなかった場合
// callback(null);
// 3. データベースへの接続中にエラーが発生した場合:
// callback(new Error("my error message"));
const msg = 'Please implement the Get User script for this database connection ' +
'at https://manage.auth0.com/#/connections/database';
return callback(new Error(msg));
}
ASP.NET メンバーシップ プロバイダー (MVC3 - Universal Providers)
function getByEmail(email, callback) {
const sqlserver = require('tedious@1.11.0');
const Connection = sqlserver.Connection;
const Request = sqlserver.Request;
const TYPES = sqlserver.TYPES;
const connection = new Connection({
userName: 'the username',
password: 'the password',
server: 'the server',
options: {
database: 'the db name',
encrypt: true // for Windows Azure
}
});
connection.on('debug', function(text) {
// 接続に問題がある場合は、詳細情報を取得するためにコメントを解除してください
//console.log(text);
}).on('errorMessage', function(text) {
// SQLデータベースへの接続時またはSQLステートメントのエラーがここに表示されます
console.log(JSON.stringify(text));
});
connection.on('connect', function(err) {
if (err) return callback(err);
var user = {};
const query =
'SELECT Memberships.UserId, Email, Users.UserName ' +
'FROM Memberships INNER JOIN Users ' +
'ON Users.UserId = Memberships.UserId ' +
'WHERE Memberships.Email = @Username OR Users.UserName = @Username';
const getMembershipQuery = new Request(query, function(err, rowCount) {
if (err) return callback(err);
if (rowCount < 1) return callback();
callback(null, user);
});
getMembershipQuery.addParameter('Username', TYPES.VarChar, email);
getMembershipQuery.on('row', function(fields) {
user = {
user_id: fields.UserId.value,
nickname: fields.UserName.value,
email: fields.Email.value
};
});
connection.execSql(getMembershipQuery);
});
}
ASP.NET メンバーシップ プロバイダー (MVC4 - Simple Membership)
function getByEmail(email, callback) {
const sqlserver = require('tedious@1.11.0');
const Connection = sqlserver.Connection;
const Request = sqlserver.Request;
const TYPES = sqlserver.TYPES;
const connection = new Connection({
userName: 'the username',
password: 'the password',
server: 'the server',
options: {
database: 'the db name',
encrypt: true // Windows Azure の場合
}
});
connection.on('debug', function(text) {
// 接続に問題がある場合は、このコメントを解除するとより詳細な情報を確認できます
//console.log(text);
}).on('errorMessage', function(text) {
// SQL データベースへの接続時または SQL ステートメント実行時のエラーが表示されます
console.log(JSON.stringify(text));
});
connection.on('connect', function(err) {
if (err) return callback(err);
var user = {};
const query =
'SELECT webpages_Membership.UserId, UserName, UserProfile.UserName from webpages_Membership ' +
'INNER JOIN UserProfile ON UserProfile.UserId = webpages_Membership.UserId ' +
'WHERE UserProfile.UserName = @Username';
const getMembershipQuery = new Request(query, function (err, rowCount) {
if (err) return callback(err);
if (rowCount < 1) return callback();
callback(null, user);
});
getMembershipQuery.addParameter('Username', TYPES.VarChar, email);
getMembershipQuery.on('row', function (fields) {
user = {
user_id: fields.UserId.value,
nickname: fields.UserName.value,
email: fields.UserName.value
};
});
connection.execSql(getMembershipQuery);
});
}
MongoDB
function getByEmail(email, callback) {
const MongoClient = require('mongodb@5.1.0').MongoClient;
const client = new MongoClient('mongodb://user:pass@mymongoserver.com');
client.connect(function (err) {
if (err) return callback(err);
const db = client.db('db-name');
const users = db.collection('users');
users.findOne({ email: email }, function (err, user) {
client.close();
if (err) return callback(err);
if (!user) return callback(null, null);
return callback(null, {
user_id: user._id.toString(),
nickname: user.nickname,
email: user.email
});
});
});
}
MySQL
function getByEmail(email, callback) {
const mysql = require('mysql');
const connection = mysql({
host: 'localhost',
user: 'me',
password: 'secret',
database: 'mydb'
});
connection.connect();
const query = 'SELECT id, nickname, email FROM users WHERE email = ?';
connection.query(query, [ email ], function(err, results) {
if (err || results.length === 0) return callback(err || null);
const user = results[0];
callback(null, {
user_id: user.id.toString(),
nickname: user.nickname,
email: user.email
});
});
}
PostgreSQL
function loginByEmail(email, callback) {
//この例では "pg" ライブラリを使用しています
//詳細はこちら: https://github.com/brianc/node-postgres
const postgres = require('pg');
const conString = 'postgres://user:pass@localhost/mydb';
postgres.connect(conString, function (err, client, done) {
if (err) return callback(err);
const query = 'SELECT id, nickname, email FROM users WHERE email = $1';
client.query(query, [email], function (err, result) {
// 注意: データベースへの接続を閉じるために
// 必ずここで `done()` を呼び出してください
done();
if (err || result.rows.length === 0) return callback(err);
const user = result.rows[0];
return callback(null, {
user_id: user.id,
nickname: user.nickname,
email: user.email
});
});
});
}
SQL Server
function getByEmail(email, callback) {
//この例では "tedious" ライブラリを使用しています
//詳細はこちら: http://pekim.github.io/tedious/index.html
const sqlserver = require('tedious@1.11.0');
const Connection = sqlserver.Connection;
const Request = sqlserver.Request;
const TYPES = sqlserver.TYPES;
const connection = new Connection({
userName: 'test',
password: 'test',
server: 'localhost',
options: {
database: 'mydb'
}
});
const query = 'SELECT Id, Nickname, Email FROM dbo.Users WHERE Email = @Email';
connection.on('debug', function (text) {
console.log(text);
}).on('errorMessage', function (text) {
console.log(JSON.stringify(text, null, 2));
}).on('infoMessage', function (text) {
console.log(JSON.stringify(text, null, 2));
});
connection.on('connect', function (err) {
if (err) return callback(err);
const request = new Request(query, function (err, rowCount, rows) {
if (err) return callback(err);
callback(null, {
user_id: rows[0][0].value,
nickname: rows[0][1].value,
email: rows[0][2].value
});
});
request.addParameter('Email', TYPES.VarChar, email);
connection.execSql(request);
});
}
Windows Azure SQL Database
function getByEmail (name, callback) {
var profile = {
user_id: "103547991597142817347",
nickname: "johnfoo",
email: "johnfoo@gmail.com",
name: "John Foo",
given_name: "John",
family_name: "Foo"
};
callback(null, profile);
}
Axios
async function getUserAsync(email, callback) {
//axiosの新バージョンが利用可能になり次第、更新すること (https://auth0-extensions.github.io/canirequire/#axios)
const axios = require("axios@0.22.0");
let response;
try {
response = await axios.post(
//SDLC環境を適切にサポートするため、APIのURLは接続設定に保存すること
configuration.baseAPIUrl + "/getUser",
//ユーザー資格情報をリクエストボディとして渡す
{
email: email,
},
{
timeout: 10000, //リクエストがタイムアウトした場合にスクリプトが必要なコールバックを実行できるよう、呼び出しを正常終了する
headers: {
//接続設定に保存されたapiKeyでAPIコールを保護する。
//手軽な方法だが、クライアントとAPI間でシークレットを共有すべきでないため、
// M2Mトークンを使用する方がより安全。
"x-api-key": configuration.apiKey,
},
}
);
} catch (e) {
if (e.response.status === 404) {
//指定されたメールアドレス/usernameのユーザーが見つからない場合、APIが404を返すことを想定
return callback(null, null);
}
//その他のエラーに対するコールバック
return callback(new Error(e.message));
}
try {
let user = response.data;
//テナントで複数のカスタムDB接続を使用する場合は、
//user_idに接続固有のキーをプレフィックスとして付加すること(例: "connName|" + user.user_id)
//これにより、すべてのDB接続でユーザーIDの一意性が保証される
return callback(null, {
user_id: user.user_id,
email: user.email,
});
} catch (e) {
return callback(new Error(e.message));
}
}
Stormpath
function getByEmail(email, callback) {
// {yourStormpathClientId} をあなたの Stormpath ID に置き換えてください
var url = 'https://api.stormpath.com/v1/applications/{yourStormpathClientId}/accounts';
// Stormpath API のクライアントID とシークレットを追加してください
var apiCredentials = {
user : '{yourStormpathApiId}',
password: '{yourStormpathApiSecret}'
};
// メールアドレスでユーザーを検索する GET リクエストを送信します
request({
url: url,
method: 'GET',
auth: apiCredentials,
qs: { q: email },
json: true
}, function (error, response, body) {
if (response.statusCode !== 200) return callback();
var user = body.items[0];
if (!user) return callback();
var id = user.href.replace('https://api.stormpath.com/v1/accounts/', '');
return callback(null, {
user_id: id,
username: user.username,
email: user.email,
email_verified: true
// Stormpath から引き継ぎたい追加フィールドをここに追加してください
});
});
}