顔認証のクラウドサービスMercury Cloudでさらに遊んでみる – 2要素認証に1対N検索を用いる –
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の多要素認証を実行するようにしたほうが良いかと思います。