アングラー2、Springboot、Zuul、ShroはドメインCORSにまたがって、ピットの実録を踏んでもらうように要求します.

8459 ワード

前書き:前後端分離、業務分離、ゲートウェイルーティングなどが現在のウェブアプリ開発のトレンドとなっている.フロントエンドは単一ページルートを中心とするフレームワークを主体として、nodejsまたはinxに単独で展開することができます.バックエンドはspringbootに代表される分散式マイクロサービスのフレームワークを主体として、独立して任意のポートで実行できます.restful仕様に適合するインターフェースを介して相互にアクセスまたはデータ交換を行う.このような開発モードにおいて、まず解決すべきことは、ドメイン横断によるアクセス、クッキー転送及び権限管理の問題である.本文は今一番人気のAnglar 2、Sprigboot、Zuul、Shroを例にして、ベストな実践を提供します.
一、一般訪問
開発においてまず発生した問題は、フロントエンド運転ポートとバックエンド運転ポートが一致しないことによるクロスドメインアクセスです.Sprigboot項目にフィルタを追加することを推奨します.
@WebFilter
public class CorsFilter implements Filter {
    @Override
    public void destroy() {
        // TODO Auto-generated method stub

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
        response.setHeader("Access-Control-Allow-Credentials","true");
        chain.doFilter(req, res);
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {
        // TODO Auto-generated method stub

    }

}
二、身分認証auth
ユーザー登録後、理論的にバックエンドで現在のユーザーのセッションデータを取得できますが、まだ問題があります.この問題の主な原因はバックエンドがsessionidによってデータを確認します.通常の場合、ブラウザはcookieにデータを保存します.ドメインをまたぐ環境ではなく、ブラウザの訪問ごとに自分のクッキー情報を携帯します.しかし、Anglar 2のような非同期フレームhttpモジュールは、デフォルト要求時にはcookie情報を携帯しません.この問題の解決方法は先端要求が「withCredentials:true」フィールドを追加する必要があることです.
httpOptions: {
        headers: new HttpHeaders({ 'Content-Type': 'application/json' }),
        withCredentials: true
}
this.http.get(global.loginUrl + 'getUsers', global.httpOptions);
それだけでは足りません.もし私たちのフロントエンドが直接バックエンドサービスにアクセスするのではなく、Zuulのようなネットワークルーティングを通じて代理訪問をしました.バックエンドはまだ正確にセッションを取得できないことが分かります.理由はZuulがデフォルトでは要求ヘッダを転送しないか、または重要なヘッダ情報をフィルタしてしまうからです.したがって、Zuulのプロファイルに追加する必要があります.
zuul:
  routes:
    
      sensitiveHeaders: "*"
このようにフロントエンドが携帯するクッキー情報を要求すれば、バックエンドサービスにスムーズに送信され、バックエンドが正しいセッションを得ることができる.
三、シンロフィルター
正確なこの問題はドメインをまたぐことによるものではなく、現在のHTML 5のトレンドによって、PostとPut要求を送信する前にまずOptionsによって探知を要求します.シンロフィルターが配置されていない場合、これは問題ではありません.バックエンドサービスに根絶urlの権限フィルタリングが設定されれば、フロントエンドの要求に問題が発生します.理由はShroのデフォルトフィルタはリダイレクトを使用していますが、Optionsはリダイレクト後にアドレスが到達しないと考えていますので、正しい要求を送信し続けません.この問題を解決するには、ShroのFormAuthentication Filterを書き換える必要があります.
@Configuration
public class ShiroConfig {
    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager, @Qualifier("authFilter") Filter filter) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map filters = new HashMap<>();
        filters.put("authc", filter);
        filters.put("roles", filter);
        filters.put("perms", filter);
        shiroFilterFactoryBean.setFilters(filters);
        
        Map filterChainDefinitionMap = new HashMap();
        
        filterChainDefinitionMap.put("/*", "anon");
        filterChainDefinitionMap.put("/auth/*", "authc");
        filterChainDefinitionMap.put("/auth/admin/*", "roles[admin,administrator]");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }
    
    @Bean("authFilter")
    public Filter authenticationFilter() {
        return new FormAuthenticationFilter() {
            @Override
            protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
                if (request instanceof HttpServletRequest) {
                    if (((HttpServletRequest) request).getMethod().toUpperCase().equals("OPTIONS")) {
                        return true;
                    }
                }
                return super.isAccessAllowed(request, response, mappedValue);
            }

            @Override
            protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
                WebUtils.toHttp(response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
                return false;
            }
        };
    }
}
もちろんShroもインターフェースを残してくれました.必要に応じて配置すればいいです.
四、まとめ
今流行している前後端分離フレームがドメインを跨ぐのは私達が遭遇した最初の問題です.サーバー側にドメインを越えてアクセスできるように配置して解決します.具体的な方法はWebFilterフィルタを使うことを勧めます.しかし、デフォルトのrestはsessionidを要求していますので、リクエストヘッドにcookieを携帯させる必要があります.また、フロントエンドディスプレイとバックエンドサービスの前にゲートウェイを使用した場合、すべての要求ヘッダがフィルタリングされないようにゲートウェイサービスに許可される必要があります.最後に、セキュリティフレームを使用したら、url権限管理機能に基づいてすべてのOptions要求を実行させなければなりません.フロントエンドが要求アドレスが到達できないと誤解されないようにします.