@tatsuya1970

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

Unity + PLATEAU + Geospatial APIでAR作成時のiOSトークン認証について

質問内容

Unity + PLATEAU + Geospatial APIを使ったAR作成におけるiOSトークン認証について以下の状況に陥っており、解決策をご教授いただきたい。

iOSトークン認証とは、具体的には、Unityでこの図のように設定した場合のことです。
Image from Gyazo

経緯

こちらのサイトのおかげで、

こんな感じの建物のオクルージョンに対応したARアプリを作れるようになりました。

これの認証は、設定が簡単なARCoreのAPIキーを使いましたが、
先ほどのPLATEAUの公式サイトによれば

認証方式がいくつかあり、Androidはキーレス認証、iOSはトークン認証を使うのが望ましいですが、手順が複雑であることと、トークン認証ではサーバーが必要であることから、以下では、設定が簡単なAPIキー認証方式を用います。ただし、アプリ内にAPIキーを置くのはセキュリティ的に大きなリスクとなるので、一般に公開するアプリでは、この方式は使わないでください。

ということなので、
このたび一般公開するアプリを作成するために、トークン認証に挑戦しています。

状況

後述するとおり、ARCoreの公式チュートリアルを見ながら

・Googleサービスアカウントと署名鍵を作成
・署名鍵に基づいて、AWS LambdaでJWTのトークンを発行
・UnityからLambdaをたたいて入手したトークンをARcoreに渡す

という手順で進めましたが、最後UnityとXcodeのビルド&ランで、エラーなくiPhone実機も動くのですが、VPSに接続できません。

iPhoneのスクリーンショット

Xcodeのコンソールの表示には、このようなDebugLogのメッセージがあり、トークン認証が反映されてないです。
(GeospatialController.cs の DebugLog)

Geospatial sample encountered an EarthState error: ErrorNotAuthorized
Google.XR.ARCoreExtensions.Samples.Geospatial.GeospatialController:Update()

このDebugLogのメッセージは、
GeospatialController.cs の614行目
「Debug.LogWarning(errorMessage);」
にあたります。

GeospatialController.cs
// Check earth state.
            var earthState = EarthManager.EarthState;
            if (earthState == EarthState.ErrorEarthNotReady)
            {
                SnackBarText.text = _localizationInitializingMessage;
                return;
            }
            else if (earthState != EarthState.Enabled)
            {
                string errorMessage =
                    "Geospatial sample encountered an EarthState error: " + earthState;
                Debug.LogWarning(errorMessage);
                SnackBarText.text = errorMessage;
                return;
            }

環境

  • macOS Ventura 13.3.1
  • Unity 2021.3.4f1
  • ARcore Extensions 1.38.0
  • Python 3.8(AWS Lambda)

私がやった手順

Googleサービスアカウントの秘密鍵作成

  • Google Cloud Platform Console のナビゲーション メニュー で、目的のプロジェクトを選択し、 APIとサービス > 認証情報 に移動

  • 「サービスアカウントの管理」をクリック
    Image from Gyazo

  • 「サービスアカウントの作成」 をクリック。
    Image from Gyazo

  • サービスアカウントの詳細で、「サービスアカウント名」を入力。サービスアカウントIDは自動に生成される。 「作成して続行」をクリック
    Image from Gyazo

  • 「このサービス アカウントにプロジェクトへのアクセスを許可する」の中の「ロールを選択」プルダウンに移動。
    Image from Gyazo

  • 「現在使用中」 > 「サービス アカウント トークン作成者」を選択して、「続行」 をクリック。

  • 「ユーザーにこのサービス アカウントへのアクセスを許可」で、何も入力せずに「完了」 をクリック。
    Image from Gyazo

  • サービスアカウントが作られる
    Image from Gyazo

  • APIとサービス  > 認証情報 に戻り、
    作成したアカウントの名前をクリック。
    Image from Gyazo

  • キー > 「鍵を追加」を選択。
    Image from Gyazo

  • 鍵のタイプとして JSON を選択し、「作成」をクリック。
    Image from Gyazo

これで、秘密鍵を含む JSON ファイルがPCにダウンロードされる。

AWS Secret Manager

AWS Secrets Manager
>シークレット

新しいシークレットを保存する
Image from Gyazo

シークレットのタイプを「その他のシークレットのタイプ」を選択
キー/ 値のペア を「プレーンテキスト」を選び、
先ほど生成したJSONファイルの内容をペーストする。

Image from Gyazo

AWS Lambda

サーバーでトークンを作成する必要があります。
私はAWSのLambdaを使いました。

コード

lambda_function.py

import jwt
import cryptography
import json
import boto3
from datetime import datetime, timedelta

def get_secret(secret_name):
    client = boto3.client(YOUR_SECRET_NAME)
    response = client.get_secret_value(SecretId=secret_name)
    
    if 'SecretString' in response:
        secret = response['SecretString']
        return json.loads(secret)
    else:
        raise ValueError("Failed to retrieve the secret.")

def lambda_handler(event, context):
    # AWS Secrets Managerから秘密鍵の情報を取得
    # TODO: 'YOUR_SECRET_NAME' を適切なSecrets Managerの秘密鍵名に置き換える
    service_account_info = get_secret('plateauAR-key')
    private_key = service_account_info['private_key']
    client_email = service_account_info['client_email']
    current_time = datetime.now() + timedelta(hours=9)  #日本時間にする
    expiration_time = current_time + timedelta(hours=1)
    
    # print (current_time)
    # print (expiration_time)
    
    payload = {
        'iss': client_email,
        'sub': client_email,
        'iat': int(current_time.timestamp()),
        'exp': int(expiration_time.timestamp()),
        'aud': 'https://arcore.googleapis.com/',
    }

    token = jwt.encode(payload, private_key, algorithm='RS256')

    # print (token)
    
    return {'statusCode': 200, 'body': token}

Pythonライブラリの追加(Lambdaレイヤーの追加)

PyJWT 、 cryptography のライブラリの追加が必要。

ライブラリの追加はレイヤーの追加で対処します。
親切な人が一覧にしてたので、ここでライブラリのARMを探します。
https://github.com/keithrozario/Klayers/tree/master/deployments

参考サイト
https://qiita.com/rapirapi/items/faf18994fcc69a1136bf

AWS Lambda > レイヤー >レイヤーの作成
Image from Gyazo

レイヤーの追加
レイヤーを選択 > ARMを選択
Image from Gyazo

ARNがない場合は

python というフォルダを作る
※必ずフォルダ名はPythonで

pip install XXX -t ./python/

または

python3 -m pip install jwt -t ./python/

pythonフォルダを zip化し、

Lambda > レイヤーの追加
レイヤーを選択 > カスタムレイヤー
Image from Gyazo

AWS IAMポリシー設定

設定 > アクセス権限 
ロールをクリック
Image from Gyazo

ポリシー
ポリシーを作成
Image from Gyazo

JSONを選択し、ポリシーエディタに以下のJSONを入力する。
Image from Gyazo

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "secretsmanager:GetSecretValue",
            "Resource": "シークレットマネージャーのARNを入力"
        }
    ]
}

さきほど作成したポリシーをアタッチ!

Image from Gyazo

Unity

Edit > Project Settings
XR Plugin Management > ARcore Extensions

iOS Authentication Strategy で "Authentication Token" を選択

Image from Gyazo

空のゲームオブジェクト「SetToken」を作り、それに以下のコードをアタッチ。

setToken.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using Google.XR.ARCoreExtensions;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;

public class SetToken : MonoBehaviour
{
    public ARAnchorManager AnchorManager;

    // Start is called before the first frame update
    void Start()
    {
        //TOKEN取得
        StartCoroutine(FetchTokenAndSet());
    }
   
    IEnumerator FetchTokenAndSet()
    {
        string endpointURL = "先ほどのAWS LambdaのURL";
        UnityWebRequest request = UnityWebRequest.Get(endpointURL);
        yield return request.SendWebRequest();

        if (request.result != UnityWebRequest.Result.Success)
        {
            Debug.LogError("Failed to fetch the token: " + request.error);
            yield break;
        }
        string jwt = request.downloadHandler.text;
        //デバッグ用にプリント(通常はプリントしないほうがいい)
        print("Token :" + jwt);
        
        AnchorManager.SetAuthToken(jwt);
   }
}

Inspectorの Anchor Manager は 「AR Session Origin」を選択
Image from Gyazo

これで、ビルド&ランすると、

Unityのビルドは成功し、iOSのビルドも成功。

iPhoneの実機が立ち上がるが、
VPSには繋がらない。

Xcodeのログでは、このようなエラー。

Token :eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJwbGF0ZWF5YXItYXBwMkBwbGF0ZWF1LWFyLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic3ViIjoicGxhdGVheWFyLWFwcDJAcGxhdGVhdS1hci5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImlhdCI6MTY5Mzc1MzQ0MSwiZXhwIjoxNjkzNzU3MDQxLCJhdWQiOiJodHRwczovL2FyY29yZS5nb29nbGVhcGlzLmNvbS8ifQ.IpisakX8GsS9j6v_e0DL3UkTE425_T7QuBeufeT5-zppJdpe7a5DsigxTZIdXMR5l_8xm4PSCZpvB70WJYzHGJh_B6AdZGnVUaYc9_DkHJQkcb1mfHW-_mvzZ0RMLn3woNipbHpAVbgUEf54YJhAsnh73zD-88QM2TjUycYMCmtcoDk5P5rmbIAFdq3OJbESWw900VQNrnLfBMz4QQBpT2GvR8fUz-4vJgSbbc11zguY7-8c9YCX_eh94m2xo_MNvu1DW0UdFcCo4dNfV0K4Cq184wRgVby5cjnCAijA3X3I6uyFQtQsFtTFxsjYQXYVziti8EMl0BwE9yIwwjbjmQ
<FetchTokenAndSet>d__3:MoveNext()
UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)

Geospatial sample encountered an EarthState error: ErrorNotAuthorized
Google.XR.ARCoreExtensions.Samples.Geospatial.GeospatialController:Update()

エラーメッセージの該当箇所は、

GeospatialController.csの 614行目

GeospatialController.cs
// Check earth state.
            var earthState = EarthManager.EarthState;
            if (earthState == EarthState.ErrorEarthNotReady)
            {
                SnackBarText.text = _localizationInitializingMessage;
                return;
            }
            else if (earthState != EarthState.Enabled)
            {
                string errorMessage =
                    "Geospatial sample encountered an EarthState error: " + earthState;
                Debug.LogWarning(errorMessage);
                SnackBarText.text = errorMessage;
                return;
            }

以上です。

0 likes

No Answers yet.

Your answer might help someone💌