作業中のサービスの REST API を作成しようとしています。このサービスには、Web サイトとモバイル クライアントの 2 つの部分があります。基本的に、モバイル デバイスは API を介して最新の位置情報を保持し、Web サイトは API を介してデータを表示します。
私のアプリケーションは Android のみを対象としているため、モバイル クライアントと Web サイト クライアントの両方の認証メカニズムとして「Google でサインイン」を使用したいと考えています。
API は Node.js と Express.js を使用しています。ただし、新しいユーザー アカウントを生成するときに問題が発生します。クライアントからのデータを信頼したくないので、予想されるサインアップ プロセスは次のようなものでした。
ウェブサイトを通じて:
- ユーザーが Web サイトにアクセスし、[Sign up with Google] をクリックします。
- ユーザーは、Google の詳細を表示するアプリ リクエストを受け入れます。
- Web サイトは Google 認証トークンを取得し、それを API に送信します。
- API は、その認証トークンを使用して Google に連絡し、ユーザーの詳細を取得します。
- API は、独自の形式のアクセス トークンと共に、データベースに新しいユーザーを作成します。
- API は、将来の要求署名のために自分のアクセス トークンをクライアントに返します。
Android アプリから:
- ユーザーはアプリをダウンロードして実行し、[Sign up with Google] をクリックします。
- ユーザーは、Google によって提示された認証手順を受け入れます。
- アプリはトークンを取得し、それを API に送信します。
- API は、その認証トークンを使用して Google に連絡し、ユーザーの詳細を取得します。
- API はユーザーの存在を認識し、この新しいデバイスをそのユーザーに登録します。
- API は、将来の要求署名のために自分のアクセス トークンをアプリに返します。
ただし、トークンがサーバーに到達するとすぐに、ここで多くの問題が発生します。生成されたトークンを使用するたびに、「資格情報が無効です」というエラーが表示されます。
最初は Passport.js を使い始めましたが、見つけたのはこれでした。ドキュメントでは、セットアップは次のように行われると記載されています。
passport.use(new GoogleStrategy({
returnURL: 'http://www.example.com/auth/google/return',
realm: 'http://www.example.com/'
},
function(identifier, profile, done) {
User.findOrCreate({ openId: identifier }, function(err, user) {
done(err, user);
});
}));
しかし、「識別子」の内容をログに記録すると、実際には次のようになります
https://www.google.com/accounts/o8/id?id=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
IDは私に固有のものだと思いますが、それが何であるかを正確に発見できないようです。さらに、それが期間限定なのか、それとも永遠に続くのかはわかりません。最後の問題として、Android 経由でサインアップしたときに同じ値を取得できるかどうかさえわかりません。なぜなら、値がどこから来るのかわからないからです。私が期待していた種類の API アクセス トークンではありません。プロファイルの内容を出力すると、それは私の名前とメール アドレスだけです。Google API に連絡してユーザーを確認するために使用できるものは何もありません。
上記のソリューションは、クライアント サイトをホストしているサーバーが ID を API に渡すために API リクエストを作成する必要があることを意味するため、とにかく好きではありません。または、ID の詳細をクライアントに送信して、それらを API サーバーに渡すことができます。または、ウェブサイトサーバーがそれを api データベースに入れますが、これも悪い解決策です。
次に、Google サインイン ドキュメントの JavaScript ライブラリを使用することにしました。私はこのようなものを持っています:
ウェブサイト クライアント:
<script type="text/javascript">
function createUser(token)
{
$.ajax({
url:"http://api.example.com/user",
dataType: 'jsonp',
data: 'token='+token,
success:function(json){
alert("Success: "+json);
},
error:function(jqXHR, textStatus, errorThrown){
alert("Error "+textStatus+" "+errorThrown);
}
});
}
function signinCallback(authResult)
{
if(authResult['access_token'])
{
document.getElementById('signinButton').setAttribute('style', 'display: none');
alert('RES: '+JSON.stringify(authResult));
createUser(authResult['access_token']);
}
else if(authResult['error'])
{
alert('There was an error: ' + authResult['error']);
}
}
</script>
Node API ユーザー処理関数: function(req, res) { var callback = req.query.callback; if(callback == null) { res.send("{valid:false}"); } else { var トークン = req.query.token;
if(token == null)
{
res.send("{valid:false}");
}
else
{
var oauth2Client = new OAuth2Client('xxxxxx', 'xxxxxx', '');
oauth2Client.credentials = {
access_token: token
};
googleapis
.discover('plus', 'v1')
.execute(function(err, client){
if(client == null)
{
console.log("Client is null");
}
else
{
var request1 = client.plus.people.get({ userId: 'me' })
.withApiKey('xxxxxx');
request1.execute(function(err, result){
console.log("Result: " + (err ? err.message : result.displayName));
});
}
});
res.set('Content-Type', 'text/javascript');
res.send(callback+"({ret:'User Test'});");
}
}
}
これはクライアント側では正常に機能します。アクセス トークンとその他の詳細が表示されたアラート ボックスが表示されます。問題は、ユーザーの詳細を取得するために API サーバーで Google API 関数を呼び出すと、「無効な資格情報」が返されることです。これは、Web サイトの JavaScript でアクセス トークンを生成し、それを別の場所から使用しているためだと思います。
それで、それはほとんど私をアイデアから外します。私が見逃しているこれを達成する簡単な方法はありますか? ユーザーの詳細を検証するためにサーバーで使用できる Web サイトと Android アプリからトークンを生成できるようにしたいだけです。生成されたトークンは、ウェブサイトや Android アプリで動作する必要さえなく、API サーバーからのみ取得できます。API サーバーは、ユーザーが Google と直接対話しないため、認証のためにユーザーを Google に誘導するプロセスを実行できません。