[Spring] Login Filter vs. Interceptor


Webに関するよくある質問を処理するには、HTTPヘッダまたはURLの情報が必要ですが、サーバフィルタまたはspring intercepterではHttpServeretRequestが

フィルタ


潮流
HTTPリクエスト->WAS->フィルタ->サーブレット->コントローラ//ログインユーザー
HTTPリクエスト->WAS->フィルタ(不適切なリクエストと判断してサーブレットXを呼び出す)/非ログインユーザー

1. Filter

@Slf4j
public class LoginCheckFilter implements Filter {

    // 로그인이 필요없는 URI
    private static final String[] whitelist = {"/", "/members/add", "/login", "/logout", "/css/*"};

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String requestURI = httpServletRequest.getRequestURI();

        HttpServletResponse httpServletResponse = (HttpServletResponse) response;

        try {

            if(isLoginCheckPath(requestURI)) {
                log.info("인증 체크 로직 실행 {}",requestURI);
                // false일 경우에는 세션이 없다면 만들어주지 않는다.
                HttpSession session = httpServletRequest.getSession(false);
                if(session==null || session.getAttribute(SessionConst.LOGIN_MEMEBER)==null) {
                    log.info("미인증 사용자 요청 {}",requestURI);
                    //로그인으로 redirect
                    //로그인 페이지로 넘기고 로그인 후에는 지금 페이지를 다시 리다이렉트 하기위해 requestURI를 넣어준다.
                    httpServletResponse.sendRedirect("/login?redirectURL="+requestURI);
                    return ;
                }
            }

            chain.doFilter(request, response);

        } catch (Exception e) {
            throw e;
        } finally {
            log.info("인증필터 체크 종료 {}",requestURI);
        }

    }

    /**
     * 화이트 리스트의 경우 인증체크X
     */
    private boolean isLoginCheckPath(String requestURI) {
        return !PatternMatchUtils.simpleMatch(whitelist, requestURI);
    }
}

2.Filter Beanの登録

@Configuration
public class WebConfig {

    @Bean
    public FilterRegistrationBean loginCheckFilter() {
        FilterRegistrationBean<Filter> filterFilterRegistrationBean = new FilterRegistrationBean<>();
        filterFilterRegistrationBean.setFilter(new LoginCheckFilter());
        filterFilterRegistrationBean.setOrder(2);
        filterFilterRegistrationBean.addUrlPatterns("/*");
        return filterFilterRegistrationBean;
    }

}

3.ログインコントローラ

@PostMapping("/login")
    public String loginV4(@Validated @ModelAttribute LoginForm loginForm, BindingResult bindingResult
            , @RequestParam(defaultValue = "/") String redirectURL
            , HttpServletRequest request) {

        if(bindingResult.hasErrors()) {
            return "login/loginForm";
        }

        Member loginMember = loginService.login(loginForm.getLoginId(), loginForm.getPassword());

        if(loginMember==null) {
            bindingResult.reject("loginFail", "아이디 또는 비밀번호 맞지 않습니다.");
            return "login/loginForm";
        }

        // 로그인 성공 처리 TODO
        // 세션이 있으면 있는 세션 반환, 없으면 신규 세션을 생성
        HttpSession session = request.getSession();
        // 세션에 로그인 회원 정보 보관
        session.setAttribute(SessionConst.LOGIN_MEMEBER, loginMember);

		// 로그인 페이지 이전 URL 리다이렉트
        return "redirect:"+redirectURL;
    }
注意:PatternMatchUtils.simpleMatch
public static boolean simpleMatch(@Nullable String[] patterns, String str) {
	if (patterns != null) {
		for (String pattern : patterns) {
			if (simpleMatch(pattern, str)) {
				return true;
			}
		}
	}
	return false;
}

受信者


1.遮断器の流れ


HTTPリクエスト->WAS->フィルタ->サーブレット->スプリングインタフェース->コントローラ//ログインユーザー
HTTP要求->WAS->フィルタ->サーブレット->Spring Intercepter(適切でないと思われる要求、コントローラ呼び出しX)/非ログインユーザー
  • preHandle:コントローラ呼び出しの前に呼び出されます.(より正確には、Handlerアダプタを呼び出す前に呼び出す.)
  • 処理
  • プリHandleの応答値
    1)true:次のステップで、
    2)false:もう行わない.
  • PostHandle:コントローラ呼び出し後に呼び出されます.(より正確には、Handlerアダプタが呼び出された後に呼び出されます.)
  • afterCompletion:レンダリングビューの後に呼び出されます.
  • 2.異常フロー


  • 異常発生時は
  • である.
  • preHandle:コントローラ呼び出しの前に呼び出されます.
  • PostHandle:コントローラに異常が発生した場合、PostHandleは呼び出されません.
  • afterCompletion:afterCompletionは常に呼び出されます.この場合、パラメータとして例外(ex)を受信し、ログに出力して、どのような例外が発生したかを知ることができます.
  • afterCompletionも異常発生時に呼び出されます.
  • 異常が発生した場合postHandle()は呼び出されませんので、汎用的な処理を行うにはaftCompletion()を使用する必要があります.
  • 異常が発生した場合、afterCompletion()で異常情報(ex)が呼び出されます.
  • 1. Interceptor

    @Slf4j
    public class LoginCheckInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
            String requestURI = request.getRequestURI();
            HttpSession session = request.getSession();
    
            log.info("인증 체크 인터셉터 실행 {} ",requestURI);
    
            if(session==null || session.getAttribute(SessionConst.LOGIN_MEMEBER)==null) {
                log.info("미인증 사용자 요청");
                response.sendRedirect("/login?redirectURL="+requestURI);
            }
    
            return true;
        }
    }

    2.構成(intercepter設定)

    @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new LogInterceptor())
                    .order(1)
                    // /** : 모든 범위 적용
                    .addPathPatterns("/**")
                    // 이건 제외한다.
                    .excludePathPatterns("/css/**", "/*.ico", "/error");
            registry.addInterceptor(new LoginCheckInterceptor())
                    .order(2)
                    .addPathPatterns("/**")
                    // 필터에서는 체크 클래스에 설정한걸 인터셉터의 경우 세팅할때 할 수 있다. (패턴설정)
                    .excludePathPatterns("/", "/members/add","logout",
                            "logout", "/css/**", "/*.icon","/error");
        }

    整理する


    Sublit FilterとSpring Intercepterは、Web関連の共通の関心を解決するための技術です.
    スプリング防振器は平板フィルタに比べて開発者の立場でずっと便利である.

    1.フィルタの用途と例

  • 一般的なセキュリティおよび認証/認証タスク
  • すべてのリクエストを記録またはレビュー
  • 画像/データ圧縮および文字列符号化
  • Springから切り離す機能が必要
  • フィルタは、スプリングに実質的に関係のないグローバルタスクを処理することができます.
    典型的な例は、セキュリティに関連する一般的な操作です.フィルタは前段でインターセプタより動作するため、グローバルなセキュリティチェック(XSS防御など)が必要であり、正しい要求でなければブロックすることができる.これにより、要求がスプリング容器に伝達されず、ブロックされるため、安定性をさらに向上させることができる.
    さらに、フィルタは、画像やデータの圧縮や文字列符号化などのWebアプリケーション全体の使用機能を実現するのに適している.FilterはInterceptorよりもはるかに強力な技術で、次のチェーンに渡されるサーブレットRequest/ServeretResponseオブジェクトを操作することができます.

    2.インタフェースの用途と例

  • 詳細なセキュリティおよび認証/認証汎用タスク
  • 記録または監査
  • API呼び出し
  • コントローラの加工情報(データ)
  • Intercepterでは、クライアントリクエストに関連するグローバルタスクを処理できます.
    代表的なのは、詳細なアプリケーションの認証または承認が必要な場合、クライアント要求に関連する操作です.たとえば、一部のグループのユーザーは、コントローラに切り替える前にチェックする必要がある機能を使用できない場合があります.そのため、intercepterで処理するのに適しています.
    また、intercepterは、フィルタとは異なり、HttpServeretRequestやHttpServeretResponseなどのオブジェクトを提供するため、オブジェクト自体を操作することはできません.逆に,オブジェクトの内部値は操作可能であるため,コントローラに伝達される情報を加工しやすい.例えば、JWTトークン情報は、コントローラにユーザ情報を提供するようにブロック化することができる.
    それ以外にも、様々な目的でAPI呼び出しの情報を記録する必要がある場合があります.この場合、HttpServeretRequestまたはHttpServeretResponseを提供するインタフェースは、クライアントのIPまたは要求情報を含む記録が容易である.
    整理ソース:https://mangkyu.tistory.com/173[MangKyu'sDiary]