u-ryo's blog

various information for coding...

Category: Reverse proxy

Spring Auth and JWT Behind the Reverse Proxy

| Comments

JHipsterのSpring Authなapplicationを httpsのreverse proxy(nginx)の後ろに置いて、 GoogleのOAuth2でJWTな認証をしようとしました。 当然、backend serverからはGoogle APIに自分のhost名でaccessするような URLを返してしまい、Google APIから戻ってきたところでJWT認証は弾かれます。 backend serverはfrontend serverの名前を知らないんですから、 そりゃあ当然です。 こういうreverse proxyの後ろにbackend server置いてOAuth2 + JWTなんて そもそもダメなの? 何とかならないの? と調べてみると、 Spring Boot and OAuth2: redirect url over reverse proxyに、 reverse proxy側でX-Forwarded-Portとかのproxy用HTTP Response Headerを設定し、 Spring application側でserver.use-forward-headers=trueにすればいいよ、 とあったので、 じゃぁnginxではどうやるのだろうと調べると、 Nginx のリバースプロキシ設定のメモにありました。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
server {
  listen 80;
  server_name hoge.com;

  location / {
    proxy_set_header X-Real-IP $remote_addr;
    index index.html index.htm;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://127.0.0.1:3000;
  }
}

この通りやってみると、 何故かGoogle APIにはhttp://proxy-server/...で渡っており、 じゃぁっていうんでproxy_set_header X-Forwarded-Proto https; とベタ書きしてみてもダメで、 うーんとか思っていると、 nginx でリバースプロキシするときの Tipsoffじゃなくてproxy_redirect http:// https://;という記述があったので、 試してみると、上手く行きました。 あーちなみに、proxy_set_header X-Forwarded-Proto https;も ベタ書きじゃないとダメでした。 結局うちの場合は、以下の通りになりました。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
server {
        listen 80 default_server;
        listen [::]:80 default_server;

        # Everything is a 404
        location / {
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-Proto https;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $http_host;
                proxy_redirect http:// https://;
                proxy_pass http://walt.mydns.bz:10022/;
        }

        # You may need this to prevent return 404 recursion.
        location = /404.html {
                internal;
        }
}

で、sudo /usr/sbin/nginx -s reloadです。

でも、これでGoogle APIから無事戻ってくるようにはなったものの、 その後「No-providerで登録」になってしまい、 まだ完成しません。 ただ、その問題は別のもののようで、一歩は進んだと思うので、記事にしました。

↑その「No-providerで登録」になってしまうのは、 backendで以下のようなerrorが出ていて。

1
2
3
4
5
6
7
8
9
10
11
javax.validation.ConstraintViolationException: Validation failed for classes [bz.mydns.walt.canmatch.domain.User] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
        ConstraintViolationImpl{interpolatedMessage='must match "^[_'.@A-Za-z0-9-]*$"', propertyPath=login, rootBeanClass=class bz.mydns.walt.canmatch.domain.User, messageTemplate='{javax.validation.constraints.Pattern.message}'}
]
        at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.validate(BeanValidationEventListener.java:140)
        at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.onPreInsert(BeanValidationEventListener.java:80)
        at org.hibernate.action.internal.EntityIdentityInsertAction.preInsert(EntityIdentityInsertAction.java:197)
        at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:75)
        at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:626)
   :
   :

何なんでしょうね。 これは、account mail addressが「w.disney@somecompany.co.jp」みたいな 「.」が入るものなんですが、それがいけないとかなのでしょうか。 というのも、フツーの「gepetto@gmail.com」みたいなmail accountなら 全く同じcodeで何の問題もなく入れるのです。 「must match」の対象が何なのか、よく分かりません。