force.comでは、Sitesがポータルログインのフロントとしてよく使われます。
Salesforceが提供するカスタマーポータルの標準画面はアレだからね…。
で、Sitesを入り口にするということはVF、Apexでログイン処理をするわけで
ログインのメソッドとしてSite.Login(username, password, startUrl)というのがあって、
ここにバインドしたユーザ名やパスワードを入れたらSitesに紐付けたポータルにログインできます。
が、ここで注意しておきたいのが、Site.Loginメソッドが以下の手順でログイン処理を実装していること。
エンドユーザがユーザ名とパスワードを入力してログインボタンを押下する。(htmlのformタグによるPOST)
Apex側でSite.Loginを呼び出し、セッションを発行する。
※発行するだけで、エンドユーザのブラウザのCookieに保存するわけではないことに注意!
Site.Loginのreturn値であるPageReferenceをメソッドの戻り値としてreturnする。
エンドユーザはSite.Loginのreturn値のURL(https://[site-domain]/secur/frontdoor.jsp)にリダイレクトする。
frontdoor.jspにsidパラメータ付きで渡されると、sid値をセッションIDとしてレスポンスのSet-Cookieによって
ブラウザにCookieが設定されて、認証完了となる。
- 認証後の画面(Site.LoginのstartUrl値)にリダイレクトする。
実際のレスポンス(HTTPヘッダ)はこんな感じ(firebug)
frontdoor.jspのレスポンス↓(ドメイン名やSessionIDや組織IDを隠そうとしたら、Cookieのほとんどが黒塗りw)
重要なのは、2の時点ではセッションを発行しているだけで、ブラウザにSet-Cookieを発行しているわけではなく、
frontdoor.jspに発行したセッションIDをパラメータで渡すことで
初めてブラウザにSet-Cookieが発行されるということ。
つまり、Site.Loginのreturn値を返さずに別のPageReference値を返すと
セッションが発行されるだけで、認証が完了しないということになります。
ただし、
PageReference loginPr = Site.login(username, password, startUrl);
String sessionId = loginPr.getParameters().get('sid');
のように、frontdoor.jspへのリダイレクトURLからセッションIDを取得して保持しておき
ログインするときにはfrontdoor.jsp?sid=[セッションID]のURLにリダイレクトさせてあげれば
Site.Loginを発行した直後ではない任意のタイミングでログインを実行させることも可能です。
また、上記でリダイレクトと書きましたが、これは301とかのステータスコードによるリダイレクトではなくて
JavaScript(location.href)によるオートリダイレクトになります。
つまり3でPOSTに対するレスポンスはlocation.href=[frontdoor.jspのurl]が書かれたhtmlで、
5のfrontdoor.jspに対するGETリクエストのレスポンスはlocation.href=[startUrl]が書かれたhtmlということ。
基本的にApexのPageReferenceでポストバックじゃない場合は、全部このリダイレクト方法っす。
ちなみに、Site.LoginでカスタマーポータルにログインしたときのドメインはSitesのドメインですが
デフォルトの/secur/login_portal.jspでログインしたり、login_portal.jspのformをハックする方法でログインすると
Salesforce組織のドメイン(csとかapとかnaとか)になります。
後者の方法でもPOSTすると、frontdoor.jspに飛ばされてCookieをセットするフローになります。
この後、/_nc_external/identity/legacylogin/server/PortalDoorっていうURLに飛ばされて
さらにリダイレクトしてstartUrlに遷移します。(legacyloginって思いっきり書いてあるw)