web-dev-qa-db-ja.com

Zuulを認証ゲートウェイとして使用する

背景

私はこの 記事 で提示されている設計を実装したいと思います。

以下の図で要​​約できます。 Security Architecture

  1. クライアントは最初にIDP(OpenID Connect/OAuth2)で認証します
  2. IDPはアクセストークン(ユーザー情報のない不透明なトークン)を返します
  3. クライアントは、Authorizationヘッダーのアクセストークンを使用して、APIゲートウェイを介して呼び出しを行います
  4. APIゲートウェイは、アクセストークンを使用してIDPに要求を行います
  5. IDPは、アクセストークンが有効であることを確認し、ユーザー情報をJSON形式で返します
  6. API Gatewayはユーザー情報をJWTに保存し、秘密鍵で署名します。次に、JWTは、公開キーを使用してJWTを検証するダウンストリームサービスに渡されます。
  7. サービスがリクエストを満たすために別のサービスを呼び出す必要がある場合、リクエストの認証と承認として機能するJWTを渡します

これまでに持っているもの

私はそのほとんどを使用して完了しています:

  • グローバルフレームワークとしてのSpring Cloud
  • 個々のサービスを起動するスプリングブート
  • APIゲートウェイとしてのNetflix Zuul

また、アクセストークンをチェックし、IDPにアクセスしてJWTを作成するZuul PREフィルターを作成しました。次に、JWTがダウンストリームサービスに転送されるリクエストのヘッダーに追加されます。

問題

さて、私の質問は、Zuulとそのフィルターに特化したものです。何らかの理由でAPIゲートウェイで認証が失敗した場合、ルーティングを停止し、フィルターチェーンを継続して呼び出しを転送せずに401で直接応答する方法を教えてください。

現時点では、認証が失敗した場合、フィルターはヘッダーにJWTを追加せず、401はダウンストリームサービスから取得されます。私のゲートウェイがこの不必要な呼び出しを防ぐことを望んでいました。

com.netflix.zuul.context.RequestContextを使用してこれを行う方法を確認しようとしましたが、ドキュメントが非常に貧弱で、方法が見つかりませんでした。

25
phoenix7360

現在のコンテキストでsetSendZuulResponse(false)を設定してみてください。これはリクエストをルーティングするべきではありません。コンテキストからremoveRouteHost()を呼び出すこともできますが、これは同じことを実現します。 setResponseStatusCodeを使用して401ステータスコードを設定できます。

11
mbragg02

Runメソッド内に次を追加すると、この問題が解決します

ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
4
Yongxin Zhang

私は答えるのが非常に遅いことを知っています。あなたはzuulのプレフィルターでアプローチできます。従う必要のある手順を以下に示します。

 //1. create filter with type pre
 //2. Set the order of filter to greater than 5 because we need to run our filter after preDecoration filter of zuul.
 @Component
 public class CustomPreZuulFilter extends ZuulFilter {

  private final Logger logger = LoggerFactory.getLogger(this.getClass());

@Override
public Object run() {
    final RequestContext requestContext = RequestContext.getCurrentContext();
    logger.info("in zuul filter " + requestContext.getRequest().getRequestURI());
    byte[] encoded;
    try {
        encoded = Base64.encode("fooClientIdPassword:secret".getBytes("UTF-8"));
        requestContext.addZuulRequestHeader("Authorization", "Basic " + new String(encoded));

        final HttpServletRequest req = requestContext.getRequest();
        if (requestContext.getRequest().getHeader("Authorization") == null
                && !req.getContextPath().contains("login")) {
            requestContext.unset();
            requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());

        } else {
              //next logic
            }
        }

    } catch (final UnsupportedEncodingException e) {
        logger.error("Error occured in pre filter", e);
    }

    return null;
}



@Override
public boolean shouldFilter() {
    return true;
}

@Override
public int filterOrder() {
    return 6;
}

@Override
public String filterType() {
    return "pre";
}

}

requestContext.unset()は、現在のスレッドのアクティブな要求のRequestContextをリセットします。応答ステータスコードを提供できます。

0
Vishnu KR