セッション、intercepter、クッキー


セッション、intercepter、クッキー


ログイン状態を維持する方法は主にセッションとCookieがあります.

セッション

@PostMapping
public String submit(LoginCommand loginCommand, Errors errors, 
HttpSession session) {

}
要求マッピングノイズ適用方法にHttpSessionパラメータが存在する場合、spring MVCはコントローラメソッドの呼び出し時にHttpSessionオブジェクトをパラメータに渡す.HttpSessionを生成する前に、新しいHttpSessionが生成されます.そうしないと、既存のHttpSessionが渡されます.
@PostMapping
public String submit(LoginCommand loginCommand, Errors errors,
HttpServletRequest req) {
	HttpSession session = req.getSession();
}
前の方法では常にHttpSessionが生成されますが、この方法では必要に応じてHttpSessionのみが作成されます.
    @PostMapping
    public String submit(
    		LoginCommand loginCommand, Errors errors, HttpSession session,
    		HttpServletResponse response) {
        new LoginCommandValidator().validate(loginCommand, errors);
        if (errors.hasErrors()) {
            return "login/loginForm";
        }
        try {
            AuthInfo authInfo = authService.authenticate(
                    loginCommand.getEmail(),
                    loginCommand.getPassword());
            // 세션에 정보 저장
            session.setAttribute("authInfo", authInfo);
            return "login/loginSuccess";
        } catch (WrongIdPasswordException e) {
            errors.reject("idPasswordNotMatching");
            return "login/loginForm";
        }
    }
ログインが成功すると、認証情報オブジェクトがHttpSessionのauthInfo属性に格納されます.
ログアウトするには、HttpSessionを削除するだけです.
@Controller
public class LogoutController {

	@RequestMapping("/logout")
	public String logout(HttpSession session) {
		session.invalidate();
		return "redirect:/main";
	}
}

受信者


ログインしていない場合にのみ使用できるリソースにアクセスすることは推奨されません.
このため、HttpSessionにauthInfoオブジェクトが存在するかどうかを確認し、存在しない場合はログインパスにリダイレクトできます.
しかし、実際のWebアプリケーションでは、ログインの検証が必要な機能がたくさんあります.各機能を実装したコントローラコードにセッション確認コードを挿入すると、大量の重複が発生します.
このような複数のコントローラに同じ機能を適用する必要がある場合、Handler Interceptorを使用することができる.

Handler Interceptorインタフェース


org.springframework.web.Handler Interceptorインタフェースを使用すると、3つの時点で共通の機能を追加できます.

  • コントローラ(ハンドル)運転前

  • コントローラ運転後(ビュー運転前)

  • ビューの実行後
  • boolean preHandle(HttpServletRequest request, HttpServletResponse response,
    	Object handler) throws Exception;
        
    void postHandle(HttpServletRequest request, HttpServletResponse response,
    	Object handler, ModelAndView modelAndView) throws Exception;
        
    void afterCompletion(HttpServletRequest request, HttpServletResponse response,
    	Object handler, Exception ex) throws Exception;
    preHandle()メソッドは、コントローラオブジェクトを実行する前に必要な機能を実現するために使用されます.handlerパラメータは、Webリクエストを処理するためのコントローラオブジェクトです.この方法では、「ログインしていないときにコントローラを実行しない」、「コントローラを実行する前に必要な情報を生成する」などを実現できます.
    preHandle()メソッドの戻りタイプはbooleanです.preHandle()メソッドがfalseを返す場合、コントローラは実行されません.
    postHandle()メソッドは、コントローラが正常に動作した後に追加の機能を実現するために使用されます.コントローラがエクスポートされた場合、postHandle()メソッドは実行されません.
    afterCompletion()メソッドは、ビューがクライアントに応答を送信した後に実行されます.コントローラの実行中に異常が発生した場合、このメソッドの4番目のパラメータに渡されます.エクスポートが発生しない場合、4番目のパラメータはnullです.従って、コントローラの運転後に予期せぬ異常が発生したことを記録したり、運転時間を記録したりするなど、後続の処理に非常に適した方法である.

    Handler Interceptorインタフェースの各メソッドは,何の機能も実現していないJava 8のデフォルトメソッドである.したがって,すべてのHandler Interceptorインタフェース手法を実装する必要はない.このインタフェースを継承し、必要なメソッドを定義するだけです.
    ここで,Handler Interceptor実装クラスはpreHandle()メソッドを用いる.HttpSessionにauthInfo属性が存在しない場合、インプリメンテーションはパス再起動を指定します.
    public class AuthCheckInterceptor implements HandlerInterceptor {
    
    	@Override
    	public boolean preHandle(
    			HttpServletRequest request,
    			HttpServletResponse response,
    			Object handler) throws Exception {
    		HttpSession session = request.getSession(false);
    		if (session != null) {
    			Object authInfo = session.getAttribute("authInfo");
    			if (authInfo != null) {
    				return true;
    			}
    		}
    		response.sendRedirect(request.getContextPath() + "/login");
    		return false;
    	}
    
    }
    HttpSessionにauthInfo属性がある場合、preHandle()メソッドはtrueを返します.存在しない場合は、リダイレクト応答を生成しfalseに戻ります.trueを返すとコントローラが実行されるため、ログイン状態でのみコントローラが実行されます.逆にfalseを返すと、ログイン状態ではないため、指定したパスが返されます.
    request.getContextPath()は、現在のコンテキストパスを返します.Webアプリケーションパスが「http://localhost:8080/abc」の場合、コンテキストパスは「/abc」です.したがって、応答は「/abc/login」に送信されてリダイレクトされる.

    Handler Interceptor設定


    Handler Interceptorを実装した後、適用先を設定します.
    @Configuration
    @EnableWebMvc
    public class MvcConfig implements WebMvcConfigurer {
    
    	@Override
    	public void addViewControllers(ViewControllerRegistry registry) {
    		registry.addViewController("/main").setViewName("main");
    	}
    }
    WebMvcConfigurator#addInterceptor()メソッドは、インタフェースを設定する方法です.
    Interceptor#addInterceptor()メソッドHandler Interceptorオブジェクトを設定します.
    Interceptor#addInterceptor()メソッドは、インタフェースを適用するパスパターンを指定する、InterceptorRegistrationオブジェクトを返します.パスはAntパスモードを使用します.
    Antモードはパスを表すために3つの特殊文字を使用します.
  • '*':0文字以上
  • '?' : 1文字
  • "**":0以上のフォルダパス
  • クッキー


    ユーザーを便利にするために、次のログイン時に自動的にユーザー名を追加するサイトが多い.この機能を実装するときにクッキーを使用します.
        @GetMapping
        public String form(LoginCommand loginCommand,
        	@CookieValue(value = "REMEMBER", required = false) Cookie rCookie) {
    		if (rCookie != null) {
    			loginCommand.setEmail(rCookie.getValue());
    			loginCommand.setRememberEmail(true);
    		}
        	return "login/loginForm";
        }
    Spring MVCでCookieを使用する方法の1つは@CookieValue宣言を使用することです.@CookieValue宣言は、要求マッピング宣言アプリケーションメソッドのCookieタイプパラメータに適用されます.これにより、クッキーパラメータにクッキーを容易に渡すことができる.
    @CookieValueが宣言したvalueプロパティは、Cookieの名前を指定します.REMEMBERという名前のクッキーをCookieタイプに伝えます.指定した名前のCookieが存在しない場合は、required属性値をfalseとして指定します.
    requiredプロパティのデフォルト値はtrueです.requiredがtrueの場合、指定した名前のCookieが存在しない場合、spring MVCがエクスポートされます.
    @PostMapping
        public String submit(
        		LoginCommand loginCommand, Errors errors, HttpSession session,
        		HttpServletResponse response) {
            new LoginCommandValidator().validate(loginCommand, errors);
            if (errors.hasErrors()) {
                return "login/loginForm";
            }
            try {
                AuthInfo authInfo = authService.authenticate(
                        loginCommand.getEmail(),
                        loginCommand.getPassword());
                
                session.setAttribute("authInfo", authInfo);
    
    			Cookie rememberCookie = 
    					new Cookie("REMEMBER", loginCommand.getEmail());
    			rememberCookie.setPath("/");
    			if (loginCommand.isRememberEmail()) {
    				rememberCookie.setMaxAge(60 * 60 * 24 * 30);
    			} else {
    				rememberCookie.setMaxAge(0);
    			}
    			response.addCookie(rememberCookie);
    
                return "login/loginSuccess";
            } catch (WrongIdPasswordException e) {
                errors.reject("idPasswordNotMatching");
                return "login/loginForm";
            }
        }
    実際,REMEMBER Cookieを生成する部分は登録を処理するsubmit()メソッドである.Cookieを作成するにはHttpServertResponseオブジェクトが必要なので、submit()メソッドのパラメータを使用してHttpServertResponseタイプを追加します.