저희는 사용자가 회원가입을 진행할 때 DB에는 암호화되지 않은 비밀번호가 저장이 되어있습니다.
이럴경우 개인정보의 피해를 받을 수 있는데 사용자의 개인정보를 암호화하여 이러한 피해를 방지할 수 있습니다.
1. pom.xml에 spring-security dependency 추가
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-core -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-web -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-config -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
2. spring-security.xml 작성
src -> main -> webapp -> WEB-INF -> spring 경로에
spring-security.xml파일을 생성하고 코드를 추가해줍니다.
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<beans:bean id="bcryptPasswordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
</beans:beans>
3. web.xml 작성
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/appServlet/servlet-context.xml
/WEB-INF/spring/spring-security.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
위와 같이 <param-value> 태그안에 spring-secyrity.xml의 위치를 작성하여
DispatcherServlet이 읽을 수 있도록 합니다.
4. UserController 추가
<!-- BCryptPasswordEncoder 추가 -->
@Inject
private BCryptPasswordEncoder pwdEncoder;
다음과 같이 암호화 기능을 사용할 수 있도록 BCryptPasswordEncoder를 추가합니다.
먼저 회원가입을 위한 코드에 암호화 기능을 적용합니다.
1. 회원가입
@RequestMapping(value = "/register", method = RequestMethod.POST)
public String registerPOST(UserVO vo, RedirectAttributes ra) throws Exception {
logger.info("registerPOST");
int result = service.idOverlap(vo);
System.out.println("중복은 1 아니면 0 = " + result );
if(result == 1) {
ra.addFlashAttribute("result", "registerFalse");
return "/user/register";
} else if(result == 0) {
String PlaintextPassword = vo.getPassword();
String encryptionPassword = pwdEncoder.encode(PlaintextPassword);
vo.setPassword(encryptionPassword);
service.register(vo);
ra.addFlashAttribute("result", "registerOK");
}
return "redirect:/";
}
해당코드는 일단 대략적으로
register.jsp의 script단에서 아이디 중복체크로 result의 값을 넣어주는데요.
보시다시피 중복이면 리다이렉트로 register.jsp로 보내주고,
중복이 아니라면 암호화를 적용하여 회원 가입을 실행합니다.
result 값이 0일때 설명을 하자면
사용자가 회원가입을 할 때 해당 정보들을 입력하고 가입 버튼을 누르면
vo의 setPassword로 해당 값들이 들어가는데
String 변수를 하나 만들어 vo의 있는 getPassword를 가져와 PlaintextPassword에 저장
이제 PlaintextPassword에 저장한 값을
BCryptPasswordEncoder의 encode속성을 사용하여 PlaintextPassword을 암호화 시키고,
암호화 시킨 비밀번호를 vo로 다시 보내주어
마지막으로 service의 register에 vo값을 넣어 실행하면 암호화된 비밀번호가 DB에 저장
2. 로그인
@RequestMapping(value = "/login", method = RequestMethod.POST)
public String loginPOST(UserVO vo, HttpServletRequest req, RedirectAttributes ra) throws Exception {
logger.info("post login");
// HttpServletRequest를 사용하면 값을 받아 올수 있다.
HttpSession session = req.getSession();
UserVO login = service.login(vo);
// 이렇게 안하면 db에 없는 아이디를 입력하고 로그인하면 에러코드 발생
if(login == null ) {
ra.addFlashAttribute("result", "loginFalse");
return "redirect:/";
}
logger.info("원래 비밀번호 : " + login.getPassword());
logger.info("로그인할때 입력한 비밀번호 : " + vo.getPassword());
boolean passwordMatch = pwdEncoder.matches(vo.getPassword(), login.getPassword());
logger.info("원래 비밀번호와 로그인할 때 입력한 비밀번호가 같으면 트루 : " + passwordMatch);
if(login != null && passwordMatch == true) {
session.setAttribute("user", login);
ra.addFlashAttribute("result", "loginOK");
} else {
session.setAttribute("user", null);
ra.addFlashAttribute("result", "loginFalse");
}
return "redirect:/";
}
로그인 부분은 헷갈릴 수 있기 때문에 암호화한 부분과 같이 설명하겠습니다.
1. 로그인을 할 때는 2가지 비밀번호가 필요하다.
- 회원가입을 할 때 입력한 비밀번호
- 로그인 입력폼에 입력한 비밀번호
2. 사용자가 로그인 페이지에서 아이디와 비밀번호를 입력한다.(중요)
1번에서 회원가입 할 때 입력한 비밀번호를 구해야 하는데
방법은 identification(아이디)를 이용한다.
userMapper의 로그인을 담당하는 mapper에서 where 조건을 id로 주었는데,
이는 로그인 할 때를 위해 설정해주었다.
왜? 라고 생각할 수 있겠지만 이해가 가도록 설명하자면
쿼리에서 where절을 identification을 주었고 검색결과는 identification, name, password인데
그 값을 resultType으로 인해 다시 UserVO로 주었기 때문에
로그인 폼에 존재하는 아이디를 입력하면 해당 쿼리로 인해 vo에는 아이디, 이름, 비밀번호가 들어가게 되는 것이다.
3. 이제 본격적으로 회원가입을 할 때 입력한 비밀번호를 login메서드에서 구현한다.
UserVO login = service.login(vo);
데이터타입이 UserVO login을 생성하고
이 login에다가 login쿼리를 조회하여 값을 넣어준다.
그러면 login에 사용자의 아이디, 이름, 비밀번호가 들어가게 되는것이다.
중간점검을 하자면 login.getPassword()에는 회원가입할 때 입력한 암호화된 비밀번호가 들어가겠고,
vo.getPassword()에는 로그인폼에 입력한 암호화 되지 않은 비밀번호가 들어갑니다.
이제 평문인 비밀번호와 암호화된 비밀번호를 비교하여 같으면 로그인처리
다르면 비로그인 처리를해야하는데요.
두 비밀번호가 동일한지 비교하기 위해 BCryptPasswordEncoder의 matches 속성을 이용할것입니다!!
boolean passwordMatch = pwdEncoder.matches(vo.getPassword(), login.getPassword());
데이터 타입은 boolean값을 주었고 matches 을 이용하여 원래비밀번호와 로그인폼에 입력한 비밀번호를 비교하여
같으면 true, 다르면 false를 출력하도록 합니다.
여기서 주의할 점은 matches를 사용할 때
첫 번째 인자에는 평문화된 비밀번호를 입력하고, 두 번째 인자에는 암호회된 비밀번호를 입력해야합니다.
이렇게 matches를 이용하여 두 비밀번호가 일치하면
if(login != null && passwordMatch == true) {
session.setAttribute("user", login);
ra.addFlashAttribute("result", "loginOK");
} else {
session.setAttribute("user", null);
ra.addFlashAttribute("result", "loginFalse");
}
다음과 같은 코드 처럼 login에 null이 아니면서 passwordMatch가 true이면 로그인이 되도록 처리합니다.
3. 회원 수정
@RequestMapping(value ="/modify", method = RequestMethod.POST)
public String modifyPOST(HttpSession session, UserVO vo, RedirectAttributes ra) throws Exception {
logger.info("modifyPOST");
String PlaintextPassword = vo.getPassword();
String encryptionPassword = pwdEncoder.encode(PlaintextPassword);
vo.setPassword(encryptionPassword);
service.modify(vo);
session.invalidate();
ra.addFlashAttribute("result", "updateOK");
return "redirect:/";
}
회원수정하는 로직은 로그인에 비하면 매우 간단합니다!
1. 사용자가 입력한 비밀번호를 가져와 PlaintextPassword에 저장한다.
2. 가져온 PlaintextPassword을 encode로 암호화시켜 encryptionPassword에 저장한다.
3. 이 암호화된 비밀번호를 setter를 이용하여 다시 vo에 보낸다.
4. 그러면 vo에 있는 password에는 암호화된 비밀번호가 들어있게 된다.
5. 이제 회원수정하는 쿼리에 vo값을 실어 쿼리를 실행하면 정상적으로 회원 수정이 된다.
4. 회원탈퇴
@RequestMapping(value="/remove", method = RequestMethod.POST)
public String removePOST(UserVO vo, HttpSession session, RedirectAttributes ra) throws Exception {
logger.info("removePOST");
UserVO user = (UserVO)session.getAttribute("user");
String oldPass = user.getPassword();
logger.info("로그인할 때 입력한 비밀번호 = " + oldPass);
String newPass = vo.getPassword();
logger.info("회원탈퇴할 때 입력한 비밀번호 = " + newPass);
boolean passwordMatch = pwdEncoder.matches(newPass, oldPass); // 첫번째 인자는 평문, 두번 째 인자는 암호화로 설정해야 오류가 안난다.
System.out.println("비밀번호 비교 : " + passwordMatch);
if(passwordMatch == true) {
service.remove(user);
ra.addFlashAttribute("result", "removeOK");
session.invalidate();
return "redirect:/";
} else {
ra.addFlashAttribute("result", "removeFalse");
return "redirect:/user/remove";
}
}
회원탈퇴는 로그인처리하는 메서드와 비슷합니다.
1. session에 담겨있는 "user"를 getAttribute로 가져와 UserVO로 형변환 시켜 데이터 타입이 UserVO인 user에 저장한다.
2. 그러면 user 인스턴스에는 로그인할 때 입력한 비밀번호가 들어가고
3. 회원탈퇴 폼에 입력한 비밀번호는 vo에 들어가게 된다.
4. 로그인과 마찬가지로 matches 속성을 이용하여 값을 비교한다.
5. 참이 나오면 원래 비밀번호가 담겨있는 user를 회원탈퇴 쿼리에 넣어 정상적으로 회원탈퇴가 진행된다.
6. 만약 passwordMatch 값이 false이면 다시 /user/remove페이지로 리다이렉트 처리한다.
'JAVA > blog' 카테고리의 다른 글
게시판 리스트 제목에 댓글 수 표시 (1) | 2020.08.05 |
---|---|
조회수 증가 (0) | 2020.08.05 |
아이디 중복검사 기능 (0) | 2020.08.04 |
회원(4) - 회원탈퇴 (0) | 2020.07.31 |
회원(3) - 비밀번호 변경 (0) | 2020.07.31 |