로그인
쿠키와 세션을 이용하여 로그인을 한다. 로그인의 상태에 따라 화면단에 보여지는 것도 달리 할 것이다.
1) index.jsp
1 2 3 | <li> <a href="/login">로그인</a> <li> | cs |
2) LoginCommand.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | package tody.lovely.util; import javax.persistence.Entity; import javax.validation.constraints.NotEmpty; @Entity public class LoginCommand { @NotEmpty(message="아이디를 입력해주세요.") private String id; @NotEmpty(message="비밀번호를 입력해주세요.") private String pw; private boolean rememberId; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getPw() { return pw; } public void setPw(String pw) { this.pw = pw; } public boolean isRememberId() { return rememberId; } public void setRememberId(boolean rememberId) { this.rememberId = rememberId; } } | cs |
Hiberante를 썼다. 여기는 null만 검증하면 되는 거라서 hibernate를 썼다.
3) LoginController.java
1 2 3 4 5 6 7 8 9 10 11 12 | @RequestMapping(value="/login", method=RequestMethod.GET) public ModelAndView loginForm(LoginCommand loginCommand, @CookieValue(value="REMEMBER", required=false) Cookie rememberCookie) throws Exception { if(rememberCookie!=null) { loginCommand.setId(rememberCookie.getValue()); loginCommand.setRememberId(true); } ModelAndView mv = new ModelAndView("user/login/loginForm"); return mv; } | cs |
- 3행 : 아이디 기억을 위한 Cookie 부분이다.
- 5~8행 : Cookie가 있으면(아이디 기억을 했으면) Cookie에 있는 id와 rememberId의 값을 보낸다.
4) loginForm.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <div class="panel-body"> <form:form role="form" commandName="loginCommand" action="/login" method="post"> <fieldset> <div class="form-group"> <form:input type="text" class="form-control" placeholder="ID" path="id"/> </div> <div class="form-group"> <form:password class="form-control" placeholder="Password" path="pw"/> </div> <div class="checkbox"> <label> <form:checkbox path="rememberId"/>아이디 기억 </label> </div> <button type="submit" class="btn btn-lg btn-success btn-block">로그인</button> </fieldset> </form:form> </div> | cs |
5) 확인
짠!
6) AuthInfo.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | package tody.lovely.util; //회원 정보 세션 유지 public class AuthInfo { private String id; private String name; private int grade; public AuthInfo(String id, String name, int grade) { this.id = id; this.name = name; this.grade = grade; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getGrade() { return grade; } public void setGrade(int grade) { this.grade = grade; } } | cs |
회원 정보 세션을 유지해주는 기능을 할 것이다. UserVO를 그대로 사용하게 되면 보안성에 취약할 뿐만 아니라, 불필요한 정보까지 유지가 된다. 그래서 따로 세션 정보 유지를 위해 만들었다.
- 10~14행 : 로그인이 성공하면서, 저장된다.
7) UserVO.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | package tody.lovely.vo; import java.util.Date; public class UserVO { private int IDX; private String ID; private String EMAIL; private String NAME; private String PASSWORD; private int GRADE; private Date REGDATE; //비밀번호 확인 public boolean matchPassword(String pw) { return this.PASSWORD.equals(pw); } /* Getter, Setter 생략 */ } | cs |
- 16~18행 : 비밀번호 확인을 위해서 추가했다.
8) LoginController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | @Resource(name="userService") private UserService userSer; @RequestMapping(value="/login", method=RequestMethod.POST) public ModelAndView loginSuccess(@Valid LoginCommand loginCommand, BindingResult bindingResult, HttpSession session, HttpServletResponse response) throws Exception { if(bindingResult.hasErrors()) { ModelAndView mv = new ModelAndView("user/login/loginForm"); return mv; } try { AuthInfo authInfo = userSer.loginAuth(loginCommand); session.setAttribute("authInfo", authInfo); Cookie rememberCookie = new Cookie("REMEMBER", loginCommand.getId()); rememberCookie.setPath("/"); if(loginCommand.isRememberId()) { rememberCookie.setMaxAge(60*60*24*7); } else { rememberCookie.setMaxAge(0); } response.addCookie(rememberCookie); } catch (IdPasswordNotMatchingException e) { bindingResult.rejectValue("pw", "notMatch", "아이디와 비밀번호가 맞지않습니다."); ModelAndView mv = new ModelAndView("user/login/loginForm"); return mv; } ModelAndView mv = new ModelAndView("login/loginSuccess"); return mv; } | cs |
- 5행, 8~11행 : @Valid 어노테이션을 이용해 유효성검사를 한다.
- 15~16행 : 로그인에 성공하면 authInfo를 반환한다.
- 18행 : 쿠키를 생성하여 로그인 될때 생성된 id를 쿠키에 저장한다.
- 19행 : 쿠키를 찾을 경로를 변경해준다.
- 20~21행 : 아이디 기억을 체크했다면, 7일 정도의 유효시간을 정해준다. ( 60*60*24*30 : 30일 )
- 23행 : 아이디 기억을 체크하지 않았다면, 설정하지 않는다.
- 25행 : 쿠키를 적용해준다.
- 27~31행 : Service에서 exception을 한 부분이다. 아이디가 없거나, 비밀번호가 맞지않으면 에러를 보낸다.
- 33행: 로그인에 성공하면 이동할 페이지를 정할 수 있다. 메인 페이지로 보내고 싶다면 redirect:/ 로 설정하면 된다.
9) UserService.java
1 2 | AuthInfo loginAuth(LoginCommand loginCommand) throws Exception; | cs |
Controller의 15행에 의해 만들어졌다.
10) UserServiceImpl.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @Resource(name="userDAO") private UserDAO userDAO; @Override public AuthInfo loginAuth(LoginCommand loginCommand) throws Exception { UserVO user = userDAO.selectById(loginCommand.getId()); if(user == null) { throw new IdPasswordNotMatchingException(); } if(!user.matchPassword(loginCommand.getPw())) { throw new IdPasswordNotMatchingException(); } return new AuthInfo(user.getID(), user.getNAME(), user.getGRADE()); } | cs |
- 8~9행 : 아이디가 있는 지 확인한다. 없으면 exception 처리한다.
- 10~12행 : 아이디와 비밀번호가 맞는 지 확인한다. UserVO에서 만들었다.
- 13행 : 아이디와 비밀번호가 확인되면, AuthInfo에 회원정보를 저장한다.
11) exception.java
1 2 3 4 5 | package tody.lovely.exception; public class IdPasswordNotMatchingException extends RuntimeException { } | cs |
12) UserDAO.java
1 2 3 4 5 6 7 8 | @Repository("userDAO") public class UserDAO extends AbstractDAO{ public UserVO selectById(String id) { return (UserVO) selectOne("user.selectById", id); } } | cs |
13) user_sql.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="user"> <select id="selectById" resultType="tody.lovely.vo.UserVO"> <![CDATA[ SELECT * FROM USER WHERE ID = #{id} ]]> </select> </mapper> | cs |
14) loginForm.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <div class="panel-body"> <form:form role="form" commandName="loginCommand" action="/login" method="post"> <fieldset> <div class="form-group"> <form:input type="text" class="form-control" placeholder="ID" path="id"/> <form:errors path="id"/> </div> <div class="form-group"> <form:password class="form-control" placeholder="Password" path="pw"/> <form:errors path="pw"/> </div> <div class="checkbox"> <label> <form:checkbox path="rememberId"/>아이디 기억 </label> </div> <button type="submit" class="btn btn-lg btn-success btn-block">로그인</button> </fieldset> </form:form> </div> | cs |
- 06, 10행: 에러메세지를 보여주기 위해 추가한다.
15) loginSuccess.jsp
1 | 로그인 성공! ${authoInfo.name }님, 반갑습니다. | cs |
controller에서 메인 페이지로 리다이렉트했다면 만들지 않아도 되는 페이지다. 각자 원하는 대로 꾸미면 된다.
${authInfo.name}은 세션에 넣어둔 정보를 가져와서 확인할 수 있다.
16) index.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <c:catch> <c:choose> <c:when test="${empty authInfo }"> <li> <a href="/login"><i class="fa fa-sign-in"></i> 로그인</a> </li> <li> <a href="/register/step1"><i class="fa fa-user"></i> 회원가입</a> </li> </c:when> <c:otherwise> <c:choose> <c:when test="${authInfo.grade eq '1' }"> <li> <p>관리자 ${authInfo.name }님, 환영합니다.</p> </li> <li> <a href="/logout"><i class="fa fa-sign-out"></i> 로그아웃</a> </li> </c:when> <c:otherwise> <li> <p>${authInfo.name }님, 반갑습니다!</p> </li> <li> <a href="/logout"><i class="fa fa-sign-out"></i> 로그아웃</a> </li> </c:otherwise> </c:choose> </c:otherwise> </c:choose> </c:catch> | cs |
- 5~12행 : 로그인을 하지 않아, 세션정보가 없다면 로그인/회원가입이 뜬다.
- 15~21행 : 로그인이 되어 세션정보가 있는데, grade가 1이면(관리자) 관리자 화면이 뜬다.
- 24~30행 : 로그인이 되어 세션정보가 있는데, grade가 1이 아니면 일반회원 화면이 뜬다.
17) 확인
17-1. 비밀번호나 아이디가 틀린 경우
에러 문구가 떴다.
17-2. 로그인 성공
authInfo 세션에 넣어둔 정보인 이름도 떴다.
그리고 메인 페이지의 수정으로 인해 로그인/회원가입도 로그아웃으로 바뀌었다.
로그인은 끝났다. 아이디 기억은 로그아웃을 완성하고 해보자.
로그아웃
로그아웃은 매우 쉽다. 그냥 세션만 끊어주면 되기 때문!
1) index.jsp
1 2 3 | <li> <a href="/logout">로그아웃</a> </li> | cs |
2) LoginController.java
1 2 3 4 5 6 | @RequestMapping("/logout") public ModelAndView logout(HttpSession session) { session.invalidate(); ModelAndView mv = new ModelAndView("redirect:/"); return mv; } | cs |
- 3행 : 세션 전체를 날려버린다.
- 4행 : 로그아웃 버튼을 누르면 바로 메인페이지로 리다이렉트한다.
3) 확인
3-1. 로그아웃을 누를 경우
세션이 모두 사라져서 다시 로그인/회원가입이 뜬다.
4) 아이디 기억 기능 확인
4-1. 아이디 기억을 하고 로그인 후 로그아웃하고 다시 로그인할 경우
아이디 기억을 누르고 로그인을 했다.
로그아웃 후 다시 로그인을 누르면, 아이디와 아이디기억부분의 체크가 자동으로 되어있다.
4-2. 아이디 기억을 하지않고 로그인 후 로그아웃하고 다시 로그인할 경우
아이디 기억을 하지 않고 로그인을 한다.
로그아웃 후 다시 로그인을 누르면 아이디 기억을 하지 않는 상태가 뜬다.
로그인, 로그아웃 끝!
2019.01.11
의외로 많은 분들이 이 글을 보시길래 깜짝 놀랐다. 통계보다가 놀랬다ㅎ 좀 빠진 부분이 있는 글이라서ㅠㅠ 그래서 나도 새로운 프로젝트에 그대로 복붙하면서 빠진 부분은 추가하고, 이상한 부분은 수정했다. 그대로 따라한다면 문제가 없을 것 같지만 그래도 생긴다면 ㅠㅠ.. 그리고 덧붙이자면 나는 이런 로그인, 로그아웃 보다는 Spring Security를 이용한 로그인, 로그아웃이 더 좋다고 생각한다. 보안적으로나.. 좀 더 있어 보이기도 하고.. 근데 스프링을 이제 배우는 단계라면 책에서도 이런 방법을 쓸 것이고, 굳이 보안까지 생각할 필욘 없다. 나중에 좀 더 스프링에 익숙해졌을 때 시큐리티를 이용해서 로그인, 로그아웃을 해보시길.. 그리고 제 블로그에 스프링 시큐리티를 이용한 로그인 로그아웃 글이 있으니 많이 놀러 와주세.. 읍읍
'공부 > Spring' 카테고리의 다른 글
Spring 개발 - 게시판 만들기 #목록 (15) | 2018.09.17 |
---|---|
Spring 개발 - HandlerMethodArgumentResolver 적용하기 (0) | 2018.09.13 |
스프링(Spring) 개발 - Hibernate를 이용한 회원가입하기 (7) | 2018.05.10 |
스프링(Spring) 개발 - Validator를 이용한 회원가입 만들기 (50) | 2018.05.09 |
스프링(Spring) 설정 - MySQL을 사용하여 마이바티스(MyBatis) 연동하기 (8) | 2018.05.02 |