Posted at

クロスドメインのAjax通信でセッションを維持する

More than 1 year has passed since last update.


xxxx.net と api.xxxx.net の間でアカウント認証を行い、セッションIDをクッキーで書き込んでもらう際にハマった話。

xxxx.net のログインページのフォームにアカウント名とパスワードを入力し、api.xxxx.net のWebAPIにAjaxを使用して送信する。


HKUser.js

HKUser.signin = function(form, callback)

{
var postdata = form.serialize();
$.ajax({
type:"POST",
async:true,
dataType:"json",
cache:false,
url:"https://api.xxxx.net/1/user/signin",
data:postdata,
success:function(data) {
.....
},
error:function(error) {
.....
}
});
}

クロスドメインでAjax通信を行う際は、応答側(この場合、api.xxxx.net側)で「Access-Control-Allow-Origin」を設定する必要がある。

Access-Control-Allow-Originには、通信するプロトコルとドメインを記述する。

header("Access-Control-Allow-Origin: https://xxxx.net");

header("Content-Length: {$len}");
header("Content-Type: application/json");
echo $out;

さぁ、これでクロスドメインでやりとりすることができるようになった。

アカウント認証後、セッションクッキーを受信した後、セッションデータを受け取ろうとしたら、送信側のセッションIDと受信しているセッションIDの値が違う。

xxxx.net 側で作成されたセッションIDになっている。api.xxxx.net で発行されたセッションIDがクッキーに書き込まれていない。

クロスドメインでクッキーをやりとりするには、以下の設定が必要です。

XMLHttpRequest のwithCredential をtrueに設定して下さい。


HKUser.js

HKUser.signin = function(form, callback)

{
var postdata = form.serialize();
$.ajax({
type:"POST",
async:true,
dataType:"json",
cache:false,
url:"https://api.xxxx.net/1/user/signin",
data:postdata,
xhrFields: {
withCredentials: true
},
success:function(data) {
.....
},
error:function(error) {
.....
}
});
}

XMLHttpRequest.withCredentials


XMLHttpRequest.withCredentialsプロパティは、Cookie、承認ヘッダー、TLSクライアント証明書などの資格情報を使用してクロスサイトアクセス制御要求を行う必要があるかどうかを示すブール値です。

WithCredentialsを設定しても、同じサイトのリクエストには影響しません。

加えて、このフラグは、クッキーがレスポンスで無視される時期を示すためにも使用されます。 デフォルトはfalseです。

別のドメインのXMLHttpRequestは、要求を行う前にwithCredentialsがtrueに設定されていない限り、独自のドメインのCookie値を設定できません。

withCredentialsをtrueに設定して取得したサードパーティのCookieは、同じ発信元ポリシーを引き続き遵守するため、要求元のスクリプトがdocument.cookieまたは応答ヘッダーからアクセスすることはできません。


また、サーバ側(api.xxxx.net)の応答に以下のヘッダが必要です。

Access-Control-Allow-Credentialsを、trueに設定してください

この場合、Access-Control-Allow-Origin でワイルドカードの使用が許可されません。

header("Access-Control-Allow-Credentials: true");

header("Access-Control-Allow-Origin: https://xxxx.net");
header("Content-Length: {$len}");
header("Content-Type: application/json");
echo $out;

Access-Control-Allow-Credentials


Access-Control-Allow-Credentialsレスポンスヘッダーは、要求に対する応答をページに公開できるかどうかを示します。 真の値が返されたときに公開されます。

証明書は、Cookie、承認ヘッダー、またはTLSクライアント証明書です。

プリフライトリクエストに対する応答の一部として使用される場合、実際の要求が資格情報を使用して行われるかどうかを示します。

単純なGETリクエストはプリフライトされていないので、資格情報を持つリソースに対してリクエストが行われた場合、このヘッダがリソースと共に返されないと、レスポンスはブラウザによって無視され、Webコンテンツに返されません。

Access-Control-Allow-Credentialsヘッダーは、XMLHttpRequest.withCredentialsプロパティまたはFetch APIのRequest()コンストラクターの資格情報オプションと共に使用します。

資格情報を持つCORS要求が成功するためには、資格情報を両方の側(Access-Control-Allow-CredentialsヘッダーとXHRまたはフェッチ要求)に設定する必要があります。


これでセッションIDをSet-Cookieヘッダで送信すれば、ブラウザに保存されているはずです。