LoginSignup
12
11

More than 5 years have passed since last update.

ApacheのProxy配下にSpringSecurity認証を入れたらハマった

Posted at

やりたいこと

Spring Bootで作ったアプリをサーバ上のTomcat配下のコンテキストに配置し、
ブラウザからはルートコンテキストでアクセスさせたい。
ログイン認証も中でやりたい。

Tomcatに複数アプリを設置する必要がある場合等、コンテキストがついてしまうケースがままあると思う。
コンテキストがつくと扱いが面倒なので開発はルートコンテキストでなんとかやりたい。

前提

  • サーバ上のTomcatにspring-bootアプリを配置

    • tomcatには複数アプリを配置する必要があったので、ルートコンテキストを専有できない
    • contextは/appとする
  • ブラウザからアクセスする際はhttp://app.example.com/のようにアクセスしたい

    • Apacheでlocalhost:8080/appにプロキシさせる感じで
  • ソースコード上でコンテキストを意識したくないので、server.contextPathは指定しない

  • appはSpring Securityによるセッションを使った認証を伴う

    • 事前にローカル環境でフォーム認証くらいができる状態にしておいた

とりあえずやってみたら

Tomcatにwarを配置。
Apacheにはとりあえず以下のようにプロキシさせてみた。
(例ではAJPを使わずにhttpでproxyしているけど、AJPでも同じ動作のはず)

<VirtualHost *:80>
  ServerName app.example.com
  ProxyPass / http://localhost:8080/app/
  ProxyPassReverse / http://localhost:8080/app/
</VirtualHost>

これでブラウザからhttp://app.example.com/にアクセスしたら
ログイン画面が表示された。
なんだ、簡単だなと思った矢先。

usernameとpasswordを打っても打ってもログイン画面に戻ってくる。
なんで?と思ってブラウザのcookieを調べたら何も存在(session idがない)していなかった。
ここからが長かった

Cookieをなんとかするには

色々調べた結果、リクエストのコンテキスト(今回はルートコンテキスト)とproxy後のコンテキスト(今回は/app)が違う場合、cookie pathが異なる為、ブラウザとサーバのcookieがうまくいかないらしい。

ただApacheのmod_proxyにはこれに対応する為、proxy時にcookie pathを書き換える機能が
存在するとのこと(ProxyPassReverseCookiePath)。
また、合わせてapp.example.comからlocalhostへとドメインが変わっていることから
cookie domainの書き換えも実施する(ProxyPassReverseCookieDomain)

早速やってみる

<VirtualHost *:80>
  ServerName app.example.com
  ProxyPass / http://localhost:8080/app/
  ProxyPassReverse / http://localhost:8080/app/
  ProxyPassReverseCookiePath /app/ /
  ProxyPassReverseCookieDomain localhost app.example.com
</VirtualHost>

これで再度ブラウザからアクセスすると、ブラウザ側にcookieが現れました!

よっしゃー!と喜び勇んでusernameとpasswordを打ち込むと相変わらずログイン画面に戻ってくる。
なんなのか。

続・Cookieをなんとかするには

どうもcookieを発行したが、サーバ側が認識していないっぽい。
ログイン画面アクセスの都度、新しいcookieが発行されてる。

色々調べた結果、以下のproxyでついにちゃんと動くようになりました

<VirtualHost *:80>
  ServerName app.example.com
  ProxyPass / http://localhost:8080/app/
  ProxyPassReverse / http://localhost:8080/app/

  RewriteEngine on
  RewriteRule /app/(.*)$ http://localhost:8080/app/$1 [P]

  ProxyPassReverseCookiePath /app/ /
  ProxyPassReverseCookieDomain localhost app.example.com
</VirtualHost>

proxyだけでなくmod_rewriteを使ってURLの書き換えもしました。
これでちゃんと動きます。

なぜか?
mod_proxyで飛ばすとHTTP Location headerだけ書き換えになるのですが
これだとSpring側がちゃんと書き換わったように受け取らないっぽい。
mod_rewriteでURLごと書き換えて上げるとちゃんとcookieもつながったみたいです。

まとめ

  • リクエストのコンテキストとproxy後のコンテキストが違う場合、cookieに問題が出る
  • proxy前と後でcookie pathとcookie domainを揃えてやる必要がある
    • ProxyPassReverseCookiePathProxyPassReverseCookieDomainを使う
  • springにちゃんとcookieを認識してもらうには更にmod_rewriteでURLの書き換えも必要

参考にさせて頂いたサイト。ありがとうございました。

12
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
11