スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

IE11 & JSONP で Authentication Cookie(ACSID) がHTTPヘッダに乗らない件を調べてみた

久々にハマったのでメモがわりに。
Google App Engineを使ってJSONを返すWebサービスを作ってみたのですが、
Chromeだと上手くいくのに、IE11だと上手くいかない(´・ω・`)

具体的な内容を説明すると、
1. まず、GAE上にサクっと簡単なJSONPを返すサーブレットを作る。URLマッピングは"/user"とする。

import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;

// UserServiceからメールアドレスを取得してJSONPで返す
public class UserServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String mailAddr = "unavailable";
UserService service = UserServiceFactory.getUserService();

if (service.getCurrentUser() != null)
{
mailAddr = service.getCurrentUser().getEmail();
}

String callback = req.getParameter("callback");
String jsonStr = callback + "({'email':'" + mailAddr + "'});";

resp.setCharacterEncoding("utf-8");
resp.setContentType("application/json");
resp.getWriter().print(jsonStr);
}
}

2. ついでにUserServiceの利用を認証するサーブレットも作っておく。URLマッピングは"/login"とする。

public class LoginServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
UserService service = UserServiceFactory.getUserService();
if (service.getCurrentUser() == null)
{
String url = service.createLoginURL(req.getRequestURI());
resp.sendRedirect(url);
}
}
}

3. 最後に上記"/user"からJSONPを取得して表示するHTMLを作る(AngularJS使用)。

<html lang="ja" xmlns:ng="http://angularjs.org" ng-app="myApp">
<head>
<title>AngularTest</title>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.28/angular.min.js"></script>
<script>
var app = angular.module('myApp',[]);
app.controller('testController', function($scope, $http)
{
var api = 'http://1-dot-taepontest-966.appspot.com/user';

$scope.callAPI = function ()
{
var params =
{
callback: 'JSON_CALLBACK'
};

$http.jsonp(api, { params: params })
.success(function (data, status, headers)
{
$scope.email = data.email;
$scope.status = status;
})
.error(function(data, status)
{
$scope.email = "ERROR";
$scope.status = status;
});
}

$scope.callAPI();
});
</script>
</head>

<body ng-controller="testController">
<div>result: {{email}}</div>
<div>status: {{status}}</div>
</body>
</html>

で、一旦"/login"でGoogleにログインした後に、上記のHTMLをローカルから実行した結果がこちら。
blog-entry-109.png
。。。どういう訳かブラウザによって挙動が違うorz
Wiresharkで2つのリクエストを比較してみた所、
JSONPのリクエスト時にIE11の方だけHTTPヘッダにCookie(ACSID)が乗っていない事が判明。
ちな、上記HTMLもサーブレットと同じドメイン上にあるならIEでも問題ない。つまりクロスドメインなのが問題。
色々調べてみたんですが、これはIEの仕様でどうにもならないぽい(というかChromeがユルいだけなのか?)。
[2015/09/22 追記&解決しました]
自分も盛大に勘違いしていたww上記"/login"のサーブレットに以下を追記する事で解決しますた。

Cookie cookie = new Cookie("testCookie", "testes");
resp.addCookie(cookie);
resp.addHeader("P3P", "CP='UNI CUR OUR'"); // <=これが必要

ここら辺の詳細は以下の記事が参考になると思いまふ(´・ω・`)
http://blog.kjirou.net/p/495
http://bakera.jp/ebi/topic/3594

よくよく考えてみると、これって下手を打つとXSSからのセションハイジャックに繋がりかねないので、かなり微妙な仕様。。。
上記以外の解決方法として以下の方法もありますが、ユーザー側のブラウザで設定しないと駄目なので現実的ではない。
blog-entry-109-2.png
スポンサーサイト

Pagination

Utility

プロフィール

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。