스프링부트 로그인 유지 - seupeulingbuteu logeu-in yuji

로그인 인증

게시 글 목록을 회원만 조회하기 위해서는 접근하는 사용자가 데이터베이스 Member 테이블에 있는 사용자인지 확인을 하는 과정을 거쳐야합니다. 이를 위한 비즈니스 컴포넌트를 만든 후, LoginController을 작성해줍시다. Repository와 Service 인터페이스 및 구현에 대한 코드는 생략하도록 하겠습니다.

@SessionAttributes("member")
@Controller
public class LoginController {
	
	@Autowired
	private MemberService memberService;
	
	@GetMapping("/login")
	public void loginView() {

	}
	
	@PostMapping("/login")
	public String login(Member member,Model model) {
		Member findMember = memberService.getMember(member);
		
		if(findMember!=null && findMember.getPassword().equals(member.getPassword())) {
			model.addAttribute("member",findMember);
			return "forward:getBoardList";
		}
		else {
			return "redirect:login";
		}
	}
}

SessionAttributes는 세션에 데이터를 저장할 때 사용합니다. Model 객체에 "member"라는 이름으로 저장된 데이터를 자동으로 세션에 저장합니다. 로그인 폼에서 입력받은 커맨드객체를 서비스객체를 통해 확인하여 유효하다면 Model 객체에 조회한 데이터를 담고 유효하지 않다면 다시 로그인 페이지로 리다이렉트합니다. 

로그인 상태 유지

localhost:8080/getBoardList 와 같은 요청을 보내면 로그인을 하지 않았음에도 불구하고 게시 글 목록이 불러와지는 것을 확인할 수 있습니다. 우리가 저장한 세션을 BoardController에서 활용하도록 해봅시다. 

@Controller
@SessionAttributes("member")
public class BoardController {
	
	@Autowired
	private BoardService boardService;
	
	@ModelAttribute("member")
	public Member setMember() {
		System.out.println("*********setMember()*******");
		return new Member();
	}
	
	@RequestMapping("/getBoardList")
	public String getBoardList(@ModelAttribute("member") Member member,Model model,Board board) {
		System.out.println("getBoardList");
		if(member.getId()==null) {
			return "redirect:login";
		}
		List<Board> boardList =boardService.getBoardList(board);
		model.addAttribute("boardList",boardList);
		return "getBoardList";
	}

@SessionAttribute는 Model에 "member"라는 이름으로 저장된 데이터를 세션에 저장합니다. method level에서 사용된 @ModelAttribute는 @RequestMapping이 실행되기 전 Model의 "member" 키 값을 초기화해주는 역할을 합니다. parameter 에서 사용된 @ModelAtrritube는 세션에 저장된 member 객체를 확인하여 바인딩하게 됩니다. 만일 id값이 null이라면 세션이 존재하지 않는 것이므로 올바르지 않은 요청입니다. 즉 로그인 상태에서만 getBoardList 요청을 할 수 있게 되었습니다.

로그아웃

sessionStatus 객체를 받아 setComplete() 메서드를 호출하여 세션을 종료하도록 구현하면 됩니다.

	@GetMapping("/logout")
	public String logout(SessionStatus status) {
		status.setComplete();
		return "redirect:index.html";
	}

++

https://stackoverflow.com/questions/9960337/modelattribute-and-sessionattribute-in-spring

[스프링 부트] 로그인 상태 유지하기 - 쿠키 사용

스프링에서 로그인 기능을 만들고나서

사용자가 회원가입 후 로그인을 하면,

하나의 의문점이 생깁니다.

로그인을 유지하기 위해서

쿼리 파라미터를 계속 유지하면서 보내는 건 매우 어렵고

번거로운 작업인데, 어떻게 유지할 수 있을까요?

바로 쿠키를 사용하면 됩니다.

웹 브라우저에서 로그인을 하고나면

클라이언트에서 서버로 전송이 됩니다.

그러면 서버가 로그인 성공 했다는 것을 쿠키로 만들어서

다시 클라이언트로 전달을 하게됩니다.

사진으로 보면 아래 사진과 같습니다.

스프링부트 로그인 유지 - seupeulingbuteu logeu-in yuji

그렇다면 로그인 이후 welcome 페이지로 접근하기 위해서는

어떤 과정이 있을까요?

먼저 memberID(임의)에 들어있는 쿠키를

클라이언트에서 서버로 항상 보내주게 됩니다.

즉 모든 요청에 쿠키 정보를 자동 포함하게 됩니다.

(항상 쿠키를 서버로 전송해준다는 뜻)

사진으로 보면 아래와 같습니다.

스프링부트 로그인 유지 - seupeulingbuteu logeu-in yuji

쿠키에는 영속 쿠키와 세션 쿠키가 있습니다.

영속 쿠키 : 만료 날짜를 입력하면 해당 날짜까지 유지

세션쿠키 : 만료 날짜를 생략하면 브라우저 종료시 까지만 유지

로그인 쿠키를 만드는 방법은 다음과 같습니다.

@Slf4j @Controller @RequiredArgsConstructor public class LoginController { private final LoginService loginService; @GetMapping("/login") public String loginForm(@ModelAttribute("loginForm") LoginForm form) { return "login/loginForm"; } @PostMapping("/login") public String login(@Valid @ModelAttribute LoginForm form, BindingResult bindingResult, HttpServletResponse response) { if(bindingResult.hasErrors()) { return "login/loginForm"; } Member loginMember = loginService.login(form.getLoginId(), form.getPassword()); if(loginMember == null) { bindingResult.reject("loginFail", "아이디 또는 비밀번호가 맞지 않습니다."); return "login/loginForm"; } // 로그인 성공 // 쿠키에 시간 정보를 주지 않으면 세션 쿠키(브라우저 종료시 모두 종료) Cookie idCookie = new Cookie("memberId", String.valueOf(loginMember.getId())); response.addCookie(idCookie); return "redirect:/"; } }

위에 코드에서

마지막 부분 주석 아래가 쿠키를 만드는 과정입니다.

로그인에 성공하면 쿠키를 생성하고

HttpServletResponse 에 담습니다.

쿠키 이름은 memberId이고 값은 회원의 id를 담아둡니다.

이렇게 되면 웹 브라우저는 종료 전까지 회원의 id를 서버로 계속 보내줍니다.

그렇다면 쿠키를 어떻게 처리해줄 수 있을까요?

@Slf4j @Controller @RequiredArgsConstructor public class HomeController { private final MemberRepository memberRepository; // @GetMapping("/") public String home() { return "home"; } @GetMapping("/") public String homeLogin( @CookieValue(name = "memberId", required = false) Long memberId, Model model) { if (memberId == null) { return "home"; } //로그인 Member loginMember = memberRepository.findById(memberId); if (loginMember == null) { return "home"; } model.addAttribute("member", loginMember); return "loginHome"; } }

위에 소스코드 처럼 @CookieValue 로 데이터를 받아와서

처리하면 됩니다.

@CookieValue 에서 memberId를 아까 String으로 바꿔줬는데,

이 어노테이션이 자동으로 처리를 해줘서

Long 타입으로 써줘도 상관이 없습니다.

이렇게하고 실행해주고 로그인을 하게되면

스프링부트 로그인 유지 - seupeulingbuteu logeu-in yuji

위에 사진처럼 로그인:[사용자명] 이 뜨는 것을

확인하실 수 있습니다.

로그아웃 로직은 아래와 같습니다.

package hello.login.web.login; import hello.login.domain.login.LoginService; import hello.login.domain.member.Member; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; @Slf4j @Controller @RequiredArgsConstructor public class LoginController { private final LoginService loginService; @GetMapping("/login") public String loginForm(@ModelAttribute("loginForm") LoginForm form) { return "login/loginForm"; } @PostMapping("/login") public String login(@Valid @ModelAttribute LoginForm form, BindingResult bindingResult, HttpServletResponse response) { if(bindingResult.hasErrors()) { return "login/loginForm"; } Member loginMember = loginService.login(form.getLoginId(), form.getPassword()); if(loginMember == null) { bindingResult.reject("loginFail", "아이디 또는 비밀번호가 맞지 않습니다."); return "login/loginForm"; } // 로그인 성공 // 쿠키에 시간 정보를 주지 않으면 세션 쿠키(브라우저 종료시 모두 종료) Cookie idCookie = new Cookie("memberId", String.valueOf(loginMember.getId())); response.addCookie(idCookie); return "redirect:/"; } // 로그아웃 구현 @PostMapping("/logout") public String logout(HttpServletResponse response) { expireCookie(response, "memberId"); return "redirect:/"; } private void expireCookie(HttpServletResponse response, String cookieName) { Cookie cookie = new Cookie(cookieName, null); cookie.setMaxAge(0); response.addCookie(cookie); } }

이전 코드에서 로그아웃 주석 아래부터 추가하면 됩니다.

쿠키의 잔여시간을 0으로 설정하시면

자동으로 로그아웃하게 됩니다.

위와 같은 방법은 실제로 사용하게 된다면, 보안에 굉장히 큰 문제가 있으니

원초적인 로그인 방법이라고 생각만 하시면 됩니다.