2

で応答する場合、Zuul APIゲートウェイでOAuth2認証を起動する方法3つのSpringクラウド(ブート)アプリケーションを試しています。バックエンドサンプルに対するポート9999 ダウンストリームサービスが401.

    1. アン認証サーバポート9008
    2. に確保している基本的なバックエンドサンプルと保護されていないエンドポイントのいくつかの経路(固定および保護されていない)との基本的なZuul APIゲートウェイポートで9000

    バックエンド・サンプルのブートアプリケーションは、リソースサーバ(@EnableResourceServer)と注釈されているとResourceServerConfigurerAdapterで一部のエンドポイントを保護し

    Zuul APIゲートウェイで保護されているルートのうちの1つを最初に呼び出すと、認証サーバーのログインページにリダイレクトされます。そこにログインすると、最初に要求した保護されたルートにリダイレクトされます。保護されたバックエンド - サンプルエンドポイントは、期待どおりに動作します。つまり、バックエンドサンプルは、指定されたトークンに対して許可されたロールを取得します。私が適切な役割を持っていないバックエンドサンプルのエンドポイントにヒットした場合は、OAuth 403の応答が得られます。この場合はすべて問題ありません。

    APIゲートウェイの背後にもレガシーサービスを配置する必要があります。これらはhtmlをレンダリングし、ユーザーがそこで安全な領域にヒットしたときにログインを開始できるはずです。従来のバックエンドには、さまざまなサブURLの複雑な(成長した)アクセス許可モデルがあるため、APIゲートウェイルートレベルでこれらの領域を保護することはできません。

    このようなダウンストリーム401応答のケースで、SpringクラウドAPIゲートウェイを認証サーバーのログインにリダイレクトする良い方法は誰も知っていますか?私は "post"型のZuulFilterで単純なリダイレクトを試みましたが、応答が既にそこにコミットされているので失敗しました。

    バックエンドサンプルapplication.yml;

    server: 
     
        port: 9008 
     
        
     
    security: 
     
        oauth2: 
     
        resource: 
     
         userInfoUri: http://localhost:9999/uaa/user

    APIゲートウェイapplication.yml:

    server: 
        port: 9008 
    zuul: 
        proxy: 
         addProxyHeaders: true 
        sensitive-headers: 
        routes: 
         unsecured-backend-sample: 
         path: /unsecured-backend-sample/** 
         url: http://localhost:9008 
         authorized-backend-sample: 
         path: /authorized-backend-sample/** 
         url: http://localhost:9008/ 
         user-role-secured-backend-sample: 
         path: /user-role-secured-backend-sample/** 
         url: http://localhost:9008/ 
         xxx-role-secured-backend-sample: 
         path: /xxx-role-secured-backend-sample/** 
         url: http://localhost:9008/ 
    security: 
        oauth2: 
        client: 
         accessTokenUri: http://localhost:9999/uaa/oauth/token 
         userAuthorizationUri: http://localhost:9999/uaa/oauth/authorize 
         clientId: acme 
         clientSecret: acmesecret 
        resource: 
         userInfoUri: http://localhost:9999/uaa/user 
    
  • +0

    はあなたのポストフィルタは、前またはSendResponseFilter後に実行しましたか? – spencergibb

    +0

    スペンサーを見ていただきありがとうございます。私は私の最初の試みがSendResponseFilterの後にあったと思う。それは遅すぎる。私はZuulFilterソリューションを見つけて答えとして投稿します。あなたがそれをコメントすることができれば涼しいだろう。あなたがそれを気に入っていて、それがSpring Cloudのアーキテクチャコンセプトと互換性があると思うなら、私はそれをコミットしたいと思います。 –

    答えて

    2

    私は最終的に私のために素晴らしい作品解決策を見つけました。私は401の応答のみを処理し、ログインにリダイレクトするZuulFilterを書いた。また、拒否された要求をHTTPセッション要求キャッシュに保存して、SavedRequestAwareAuthenticationSuccessHandlerが最初に要求されたダウンストリームサービスURLにリダイレクトできるようにします。

    @Component 
    public class LoginOnDownstreamUnauthorizedResponseFilter extends ZuulFilter { 
    
        private Logger logger = LoggerFactory.getLogger(getClass()); 
    
        private AuthenticationEntryPoint authenticationEntryPoint = new LoginUrlAuthenticationEntryPoint("/login"); 
    
        private RequestCache requestCache = new HttpSessionRequestCache(); 
    
        @Override 
        public boolean shouldFilter() { 
         // Only handle downstream 401s 
         return RequestContext.getCurrentContext().getResponse().getStatus() == HttpStatus.SC_UNAUTHORIZED; 
        } 
    
        @Override 
        public Object run() { 
    
         RequestContext ctx = RequestContext.getCurrentContext(); 
         HttpServletRequest request = ctx.getRequest(); 
         HttpServletResponse response = ctx.getResponse(); 
    
         // We need to put the rejected request in the request cache for SavedRequestAwareAuthenticationSuccessHandler 
         // to find it's way back to the initial request URI after successful authentication. 
         requestCache.saveRequest(request, response); 
    
         String text = String.format("Downstream service %s responded with a status code 401.", request.getRequestURI()); 
         logger.debug(text + " Calling Authentication entry point."); 
         try { 
          authenticationEntryPoint.commence(request, response, new InsufficientAuthenticationException(text)); 
         } catch (IOException | ServletException e) { 
          logger.error("Failed to redirect to Authentication entry point", e); 
         } 
    
         return null; 
        } 
    
        @Override 
        public String filterType() { 
         return "post"; 
        } 
    
        @Override 
        public int filterOrder() { 
         // make sure to run before SendResponseFilter 
         return 500; 
        } 
    
    }