この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
Mercury Cloudの顔検索APIを2要素認証として使ってみる記事です。 顔検索APIは特徴データベースに登録されているすべての顔特徴の中からアップロードした画像から検出された顔を検索し、最も近い結果を返す というAPIです。
以前の記事でカメラで取得した画像データを特徴データベースに登録しました。
このデータベースを使って顔検索をし、本人特定のフローをシミュレーションしてみます。 Auth0を使った認証の2要素目として動作するようにしていきます。
やってみる
顔比較APIを2要素目として試した時に使ったActionsとアプリを流用します。
顔比較のアプリにダイレクトするAuth0 Actions
Auth0での認証途中でリダイレクトするようなActionsを作ります。
例)
payloadにユーザーを特定できる情報としてemailとexternalUserIdというデータを送ります。
externalUserIdはapp_metadataに保存しているfeature_id(顔特徴データベースに登録されているユーザー固有の特徴ID)を使用します。
のちのセクションでも出てきますが、app_metadata.feature_id は初回の顔特徴を登録したときのものを保存します。
externalUserIdが取得できた場合は顔特徴を登録せずに検索の処理を行う といった処理ができるのではないでしょうか。
exports.onExecutePostLogin = async (event, api) => {
const token = api.redirect.encodeToken({
secret: event.secrets.REDIRECT_SECRET,
expiresInSeconds: 600,
payload: {
// Custom claims to be added to the token
email: event.user.email,
externalUserId: event.user.app_metadata.feature_id,
},
});
// Send the user to https://my-app.exampleco.com along
// with a `session_token` query string param including
// the email.
api.redirect.sendUserTo("https://<<顔認証のアプリURL>>", {
query: { session_token: token }
});
// provider
// any: Use any of the configured challenges.
// duo: Use the Duo mutlifactor provider.
// google-authenticator: Use the Google Authenticator provider.
// guardian: Use the Guardian provider.
//api.multifactor.enable("any", {"allowRememberBrowser": false});
};
顔特徴データベースから検索
※ Auth0からexternalUserIdというデータが送られてきたケースで行なっていきます。
カメラの映像から取得した画像をデータベース内で検索します。
カメラで静止画を取得する, base64でデータを取得 だったりは前回の記事で行ったので割愛します。
顔認証のクラウドサービスMercury Cloudでさらに遊んでみる – 2要素認証に1対1比較を用いる –
例)
データベースから上位1件のデータを取得する
Auth0での認証途中の処理なので、最終的にAuth0の/continueエンドポイントにデータと一緒にリダイレクトします
var data = JSON.stringify({
"image": {
"data": img_data, // カメラで取得した画像(base64のデータ)
},
"db_ids":["<<特徴データベースのID>>"],
"top_k":1, // db_idsで指定された各特徴データベースの上位K個の類似検索結果を、[1、1024]の範囲で指定
"min_score": 0.9 // 各特徴データベースで顔検索するときの最小スコアを、[0、1]の範囲で指定
});
var config = {
method: 'post',
url: 'https://mercury-ap-northeast-1.japancv.co.jp/openapi/face/v1/<<app_id>>/databases/search',
headers: {
'x-date': x_date_time_string(), // 処理の中身は省略
'Authorization': authorization(), // 処理の中身は省略
'Content-Type': 'application/json'
},
data : data
};
// Auth0に返す情報を作成する
const is_compare = false
const returnToken = jwt.sign(
{
sub: "<<Auth0ユーザーのID>>",
exp: 1646444617, //expiresInSecondsパラメータで指定された有効期限(秒単位
iss: "<<Auth0ユーザーのID>>",
state: "<<Auth0から発行されたstateパラメーター>>",
is_compare: is_compare, // 比較結果
score: 0, // 比較スコア
feature_id: qrwefrgw // 顔特徴ID
},
"<<シークレット文字列>>",
{ algorithm: "HS256" }
);
axios(config)
.then(response => {
// ここにAPIの実行結果を使った処理を書く
〜〜〜〜〜〜〜
〜〜〜〜〜〜〜
〜〜〜〜〜〜〜
}).catch(error => {
console.log("error")
// ここにAPIの実行結果を使った処理を書く
〜〜〜〜〜〜〜
〜〜〜〜〜〜〜
〜〜〜〜〜〜〜
}).finally(function() {
// Auth0のcontinueエンドポイントにリダイレクト
// face_compareというパラメータを使って情報を渡している
reply.redirect(auth0_continue + "?state=" + request.body.state + "&face_compare=" + returnToken)
return
});
Auth0に戻ってきた時のActions
Auth0の/continueエンドポイントに来ると、ActionsのonContinuePostLogin
が動くので、その中に処理を書きます。
例)
顔検索の結果と、スコア、顔特徴IDを受け取り、最終的にスコア値をid-tokenに格納
顔特徴IDをapp_metadataに保存
した例です。
exports.onContinuePostLogin = async (event, api) => {
const payload = api.redirect.validateToken({
secret: event.secrets.REDIRECT_SECRET,
tokenParameterName: 'face_compare',
});
if(payload.is_compare == false) {
api.access.deny("顔認証に失敗しました");
}
// use the data encoded in the token, such as:
const namespace = 'https://study-archives';
api.idToken.setCustomClaim(`${namespace}/score`, payload.score);
api.idToken.setCustomClaim(`${namespace}/feature_id`, payload.feature_id);
api.user.setAppMetadata("feature_id", payload.feature_id);
};
一連の流れを確認
ログインから顔認証をし、id-tokenにスコア値を格納したところまでを録画しました
最後に
1対Nの顔検索をAuth0の認証に組み込んでみました。 顔データを送信するだけで本人確認ができるので複雑なアプリケーションを作る必要はなさそうですね。
注意しなければいけない点として、 Auth0の機能としての多要素認証ではないので、顔検証に失敗したりカメラがなくて顔のデータを取得できない場合は Auth0の多要素認証を実行するようにしたほうが良いかと思います。