상세 컨텐츠

본문 제목

[스프링1] 13장. MVC3: 세션, 인터셉터, 쿠키

22-23/22-23 Spring 1

by YUZ 유즈 2022. 12. 1. 10:01

본문

728x90

해당 포스트는 초보 웹 개발자를 위한 스프링 5 프로그래밍 입문 [최범균 저] 책 내용을 참고하였습니다.

❗ HttpSession

로그인 상태를 유지하기 위해서는 HttpSession을 이용하거나 쿠키를 이용하면 된다.

 

HttpSession을 사용하려면 다음의 두 방법 중 하나를 선택하면 된다.

  • 요청 매핑 애노테이션 적용 메서드에 HttpSession 파라미터를 추가한다.
  • 요청 매핑 애노테이션 적용 메서드에 HttpServletRequest 파라미터를 추가하고 HttpServletReuqest를 이용해서 HttpSession을 구현한다.

📌HttpSession 파라미터 추가

@PostMapping
public String(loginCommand loginCommand, Errors errors, HttpSession session) {
	... // session 사용
}

HttpSession이 생성되어 있으면 기존에 존재하는 걸 사용하고, 아니면 새로 만든다.

📌HttpServletRequest 파라미터 추가

@PostMapping
public String(loginCommand loginCommand, Errors errors, HttpServletRequest req) {
	HttpSession session = req.getSession();
	... // session 사용
}

이 방법을 사용하면 원하는 시점에만 HttpSession을 생성할 수 있다는 장점이 있다.

 

사용할 때는 setAttribute 메서드를 사용한다.

session.setAttribute("authInfo", authInfo);

로그아웃을 할 때는 HttpSesion을 제거하면 된다.

session.invalidate();

❗ 비밀번호 변경하기

비밀번호를 변경하는 기능은 다음과 같은 순서로 작성한다.

 

  1. 비밀번호 변경에 사용할 커맨드 객체와 Validator 클래스 작성하기
  2. 비밀번호 변경 컨트롤러 작성
  3. 비밀번호 변경 Form 작성
  4. ControllerConfig 설정에 비밀번호 변경 컨트롤러를 빈으로 등록

📌 커맨드 객체와 Validator 클래스 작성

ChangePwdCommand.java - 커맨드 객체

public class ChangePwdCommand {
	private String currentPassword;
    private String newPassword;
    
    public String getCurrentPassword() {
    	return currentPassword;
    }
    
    public void setCurrentPassword(String currentPassword) {
    	this.currentPassword = currentPassword;
    }
    
    public String getNewPassword() {
    	return newPassword;
    }
    public void setNewPassword(String newPassword) {
    	this.newPassword = newPassword;
    }
}

ChangePwdCommandValidator.java - 커맨드 객체 검증 클래스

public class ChangePwdCommandValidator implements Validator {
	@Override
    public boolean supports(Class<?> clazz) {
    	return ChangePwdCommand.class.isAssignableFrom(clazz);
    }
    @override
    public void validate(Object target Error errors) {
    	ValidationUtils.rejectIfEmptyOrWhitespace(errors, "currentPassword", "required");
        ValidationUtils.rejectIfEmpty(errors, "newPassword", "required");
    }
}

📌 비밀번호 변경 컨트롤러 작성

ChangePwdController.java - 비밀번호 변경 요청 처리 컨트롤러

@Controller
@RequestMapping("/edit/changePassword")
public class ChangePwdController {
	...
    @PostMapping
    public String submit(@ModelAttribute("command") ChangePwdCommand pwdCmd, Errors errors, HttpSession session) {
    	new ChangePwdCommandValidator().validate(pwdComd, errors);
        if(errors.hasErrors()) {
        	return "edit/changePwdForm";
        }
        AuthInfo authInfo = (AuthInfo) session.getAttribute("authInfo");
        ...
        
    }

📌ControllerConfig 설정에 비밀번호 변경 컨트롤러를 빈으로 등록

import controller.ChangePwdController;
import spring.ChangePasswordService;

@Configuration
public class ControllerConfig {
	@Autoried
    private ChangePasswordService changePasswordService;
    
    ...
    
    @Bean
    public ChangePwdController changePwdCOntroller() {
    	ChangePwdController controller = new ChangePwdController();
        controller.setChangePasswordService(changePasswordService);
        return controller;
    }
}

❗ 인터셉터

로그인하지 않은 상태에서 비밀번호 변경 폼으로 이동했을 때는 어떻게 해야 할까?

이때는 비밀번호 변경 폼 주소를 입력해도 로그인 창으로 넘기는 게 자연스럽다.

if(authInfo == null) {
	return "redirect:/login";
}

이러한 세션 점검 코드를 넣어야 할 곳이 많다면? 의도치 않게 중복만 늘어날 것이다.

이때 사용하는 것이 HandlerInterceptor다.

 

해당 인터페이스를 사용하면 세 시점에 공통 기능을 추가할 수 있다.

  • 컨트롤러(핸들러) 실행 전
  • 컨트롤러(핸들러) 실행 후, 아직 뷰를 실행하기 전
  • 뷰를 실행한 이후

HandlerInterceptor의 실행 흐름(p.372)

우리가 원하는 로그인 여부에 따라 로그인 폼으로 이동하는 로직은 preHandle() 메서드를 사용한다.

HandlerInterceptor 인터페이스의 각 메서드는 아무 기능도 구현하지 않은 디폴트 메서드이므로 필요한 메서드만 재정의하여 사용하면 된다.

📌HadlerInterceptor 작성

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;
    }   
}

📌HadlerInterceptor 설정

MvcConfig.java

@Override
public void addInterceptors(InterceptorRegistry registry) { // 인터셉터 설정
	registry.addInterceptor(authCheckInterceptor()).addPathPatterns("/edit/**); // 인터셉터를 적용할 경로 패턴 지정
}

❗ Ant 경로 패턴

  • * : 0개 또는 그 이상의 글자
  • ? : 1개 글자
  • ** : 0개 또는 그 이상의 폴더 경로

❗ 쿠키(Cookie)

다음에 로그인할 때에 이메일을 기억해주는 기능을 추가하고자 한다.

순서는 다음과 같다.

  1. 로그인 폼에 '이메일 기억하기' 옵션 추가
  2. 로그인 시에 '이메일 기억하기' 옵션을 선택했다면 로그인 성공 후 쿠키에 이메일 저장, 쿠키 유효기간 길게 설정
  3. 이후 로그인 시 이메일을 저장한 쿠키가 있으면 해당 이메일 보여줌

LoginCommand 클래스에 rememberEmail 필드를 작성한다.

public class LoginCommand {
	private String email;
    private String password;
    private boolean rememberEmail;
}

 

lginForm.jsp - 이메일 기억하기 체크박스 추가

<p>
	<!-- label.properties에 rememberEmail=이메일 기억하기 -->
	<label><spring:message code="rememberEmail" />:
    <form:checkbox path="rememberEmail" />
    <label>
</p>

LoginController.java의 form() 메서드 - @CookieValue를 이용해 쿠키를 전달받도록 수정

import javax.servlet.http.Cookie;
import org.springframework.web.bind.annotation.CookieValue;

@GetMapping
// 이름이 REMEMBER인 쿠키를 가져온다
// 쿠키가 없을 수도 있으므로 required는 false로 설정
public String form(LoginCommand loginCommand, @CookieValue(value="REMEMBER", required = false) Cookie rCookie) {
	if(rCookie != null) {
    	loginCommand.setEmail(rCookie.getValue());
        loginCommand.setRemeberEmail(true);
    }
    return "login/loginForm";
}

LoginController.java의 submit() 메서드 - 쿠키 설정

@Controller
@RequestMapping("/login")
public class LoginController {
	...
    @PostMapping
    public String submit(LoginCommand loginCommand, Errors errors, HttpSession session,
    	HttpServletResponse response) { // 쿠키 생성을 위한 HttpServletResponse 객체
    	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.isRemeberEmail()) { // 이메일 기억하기 선택했다면
            	rememberCookie.setMaxAge(60 * 60 * 24 * 30); // 30일 동안 유지되는 쿠키 생성
            } else {
				rememberCookie.setMaxAge(0); // 바로 삭제되는 쿠키 생성
            }
            response.addCookie(rememberCookie);
            ...// 로그인 성공        
    }

Spring 1

EDITOR: PORO

728x90

관련글 더보기