[스프링] 회원가입 암호화기능 분석
본문 바로가기

Backend

[스프링] 회원가입 암호화기능 분석

728x90
반응형

스프링에서 암호화 설정을 하는 법

설정하기
1단계: pom.xml에 spring security DI 주입
<!-- spring security --> 
		<dependency>
		    <groupId>org.springframework.security</groupId>
		    <artifactId>spring-security-core</artifactId>
		    <version>4.1.0.RELEASE</version>
		</dependency>

		<dependency>
		    <groupId>org.springframework.security</groupId>
		    <artifactId>spring-security-web</artifactId>
		    <version>4.1.0.RELEASE</version>
		</dependency>

		<dependency>
		    <groupId>org.springframework.security</groupId>
		    <artifactId>spring-security-config</artifactId>
		    <version>4.1.0.RELEASE</version>
		</dependency>
2단계: spring-security.xml
<!-- web.xml에  spring-security.xml 파일정보가 구성되어있어야 한다. -->
	<!-- bcryptPasswordEncoder 빈객체가   MemberServiceImpl클래스에서 주입되어 사용된다.-->
	<bean id="bcryptPasswordEncoder"
		class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></bean>
3단계: web.xml
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			/WEB-INF/spring/root-context.xml
			/WEB-INF/spring/spring-security.xml
		</param-value>

스프링 암호화 설정코드 작성법
1단계: MemberController.java
	// spring-security.xml BCryptPasswordEncoder클래스가 bean객체로 생성. 
	@Inject // 의존성 주입
	private BCryptPasswordEncoder crptPassEnc;
/* 회원가입(GET)  /member/join   */
	@RequestMapping(value="join", method=RequestMethod.GET)
	public void joinGET() {
	}
	
	/* 회원가입(POST) */
	@RequestMapping(value="join", method=RequestMethod.POST)
	public String joinPOST(MemberVO vo, RedirectAttributes rttr) throws Exception {
		
		// 비밀번호 암호화.   "1234" -> 다른 문자로 비번으로 생성
		vo.setMem_pw(crptPassEnc.encode(vo.getMem_pw()));
		
		service.join(vo);
		rttr.addFlashAttribute("msg", "REGISTER_SUCCESS");
		
		return "redirect:/";    // 루트 주소로 이동. HomeController 에 있음. home.jsp에서 "msg" 키사용
	}

 

1단계: 회원가입 요청 → 비밀번호 암호화 진행 → vo저장 → 회원가입 서비스 순으로 실행한다.

 

/* 로그인(GET)  /member/login   <a href="/member/login">로그인</a>   */
	@RequestMapping(value="login", method=RequestMethod.GET)
	public void loginGET() {
		// 리턴타입이 void인 경우에는 jsp파일명은 요청주소(/member/login)가 된다.
	}
	
	/* 로그인(POST)  /member/loginPost */
	@RequestMapping(value="loginPost", method=RequestMethod.POST)
	public String loginPOST(MemberDTO dto, RedirectAttributes rttr, HttpSession session, 
							Model model, HttpServletResponse response) throws Exception {
		
		logger.info("=====loginPost() execute...");
	
		MemberDTO memDTO = service.login(dto);  // service클래스에서 일반암호와 디비에서 가져온 암호문자열
		
		if(memDTO != null) { // 로그인 성공
			logger.info("=====로그인 성공");
			
			// 세션 작업 : 저장소 - 서버의 메모리(현재 연결된 사용자 사용이 가능)
			session.setAttribute("user", memDTO);  // session.getAttribute("user")
			
			// 쿠키를 사용할 경우. 저장소 : 클라이언트(브라우저).
			// <input type="checkbox" name="useCookie" /> Remember me
			if(memDTO.isUseCookie()) {
				
				// 쿠키 저장
				int amount= 60*60*24*7;  //  7일

				//  System.currentTimeMillis() : 서버의 현재시간을 밀리세컨드 읽어온다.
				Date sessionLimit = new Date(System.currentTimeMillis()+(1000*amount));
				
				/* 클라이언트 쿠키 설명 : Cookie클래스 사용*/
				// 쿠키는 클라이언트의 컴퓨터에 설정된 시간에 의하여 텍스트파일로 저장이 됨
				// 브라우저에서 쿠키를 작업해준 사이트 접속을 할때에 브라우저가 쿠키를 메모리상에서 읽고
				// 해당사이트에 쿠키정보가 전송이 이루어진다.

				// 브라우저를통하여 사이트에 접속할때에 서버에서 고유한 식별자에 해당하는 값을 쿠키형태로
				// 클라이언트에게 보내준다. 세션쿠키ID  session.getId()


				service.saveCookie(session.getId(), sessionLimit, memDTO.getMem_id());
			}
			
			
			rttr.addFlashAttribute("msg", "LOGIN_SUCCESS");
			return "redirect:/";  // 루트 주소로 이동. HomeController 에 있음. home.jsp에서 "msg" 키사용
			
		} else {		 // 로그인 실패
			logger.info("=====로그인 실패");
			
			//  RedirectAttributes 클래스 ? 주소이동시 정보를 제공하고자 할때 사용.

			// 주소이동시 "msg" 키가 노출이 안됨.
			rttr.addFlashAttribute("msg", "LOGIN_FAIL"); //로그인 페이지에서 "msg" 키가 사용됨.
			
			// return "/member/login";  jsp파일명
			return "redirect:/member/login"; // 주소이동
		}
		
	}

※ 로그인 할 시 입력된 비밀번호와 조회된 비밀번호를 일치시켜야 하기 때문에 비밀번호 조회 실행

2단계: 회원정보수정 / 비밀번호변경 / 회원탈퇴
/* 
	 * 비밀번호 재확인(POST) - 회원 정보 수정을 위함
	 * 받은 url에 해당하는 jsp를 출력
	 * 
	 * @Params
	 * String url: 이동할 jsp페이지 이름
	 * 
	 * @return
	 * String : 받은 url에 일치하는 jsp호출
	 */
	//1) 회원정보 수정 url=modify, 2) 비밀번호 변경 url=changepw, 3) 회원탈퇴 url=delete
	@RequestMapping(value="checkPw", method=RequestMethod.POST)
	public String checkPwPOST(@RequestParam("url") String url,
							  @RequestParam("mem_pw") String pw,
							  HttpSession session, Model model) throws Exception {
		
		logger.info("=====checkPw() execute..."); 
		logger.info("=====url: " + url + ", mem_pw: " + pw); 
		// 인증된 사용자
		MemberDTO dto = (MemberDTO) session.getAttribute("user");
		//logger.info("=====세션 저장 값: " + dto.toString());
		//스프링 security(보안)기술 
		if(crptPassEnc.matches(pw, dto.getMem_pw())) {
			// 비밀번호가 일치하는 경우, url 확인 
			if(url.equals("modify")) {
				model.addAttribute("vo", service.readUserInfo(dto.getMem_id()));
				return "/member/modify";
				
			} else if(url.equals("changePw")) {
				return "/member/changePw";
				
			} else if(url.equals("delete")) {
				return "/member/delete";
				
			}
		} 
		
		// 비밀번호가 일치하지 않거나, url이 정해진 url이 아닌 경우
		model.addAttribute("url", url);
		model.addAttribute("msg", "CHECK_PW_FAIL");
		return "/member/checkPw";
	}
	
	/*
	 * 비밀번호 확인 Ajax용
	 */
	@ResponseBody
	@RequestMapping("checkPwAjax")
	public ResponseEntity<String> checkPwAjax(@RequestParam("mem_pw") String mem_pw, HttpSession session) {
		
		logger.info("=====checkPwAjax() execute...");
		ResponseEntity<String> entity = null;
		MemberDTO dto = (MemberDTO) session.getAttribute("user");
		logger.info("=====mem_pw: " + mem_pw);
		logger.info("=====dto: " + dto.toString());
		
		if(crptPassEnc.matches(mem_pw, dto.getMem_pw())) {
			entity = new ResponseEntity<String>("SUCCESS", HttpStatus.OK);
			
		} else {
			entity = new ResponseEntity<String>("FAIL", HttpStatus.OK);
		}
		
		return entity;
	}
	
	
	/* 회원 정보 수정(POST) */
	@RequestMapping(value="modify", method=RequestMethod.POST)
	public String modifyPOST(MemberVO vo, RedirectAttributes rttr, HttpSession session) throws Exception {

		MemberDTO dto = new MemberDTO();
		dto.setMem_id(vo.getMem_id());
		dto.setMem_pw(vo.getMem_pw());
		
		// 비밀번호 암호와 작업
		vo.setMem_pw(crptPassEnc.encode(vo.getMem_pw()));
		service.modifyUserInfo(vo);	// 회원수정 

		/*
		처음 로그인시 세션에 저장됐던 정보를 다른 곳에서 사용이 되어질 경우 (회원수정 등)
		정보가 수정이 발생이 되면서 세션정보를 갱신해주어야한다.
		세션작업 : 수정중에 변경된 정보를 세션에 새로 반여아는 의미
		*/
		session.setAttribute("user", service.login(dto));
		
		rttr.addFlashAttribute("msg", "MODIFY_USER_SUCCESS");
		
		return "redirect:/";
	}

※ 회원정보 수정은 ajax을 이용하여 cryptPassEnc()요청

/* 비밀번호 변경(POST) */
	@RequestMapping(value="changePw", method=RequestMethod.POST)
	public String changePWPOST(MemberDTO dto, RedirectAttributes rttr, HttpSession session) throws Exception {
		
		logger.info("=====changePWPOST() execute...");
		// 비밀번호 암호화 후 변경
		dto.setMem_pw(crptPassEnc.encode(dto.getMem_pw()));
		service.changePw(dto);
		
		// 세션의 비밍번호 재설정
		MemberDTO memDTO = (MemberDTO) session.getAttribute("user");
		memDTO.setMem_pw(dto.getMem_pw());
		session.setAttribute("user", memDTO);
		
		rttr.addFlashAttribute("msg", "CHANGE_PW_SUCCESS");
		return "redirect:/";
	}
	
	/* 회원 탈퇴{POST) */
	@RequestMapping(value="delete", method=RequestMethod.POST)
	public String deletePOST(String mem_id, HttpSession session, RedirectAttributes rttr) throws Exception {
		
		logger.info("=====deletePOST() execute...");
		
		service.deleteUser(mem_id);
		// 회원탈퇴시 세션소멸작업
		session.invalidate();
		rttr.addFlashAttribute("msg", "DELETE_USER_SUCCESS");
		
		return "redirect:/";
	}
3단계 : passBcrypt.jsp 작성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
비밀번호: ${ogi_pass} <br />
암호화된 비밀번호: ${enc_pass} <br />
암호화된 비밀번호2: ${enc_pass2} <br />
</body>
</html>
4단계 : memberMapper.xml
<?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="com.demo.mappers.MemberMapper">
	
	<!-- MemberVO 가져오기 -->
	<select id="readUserInfo" parameterType="string" resultType="MemberVO">
		select  mem_id, mem_name, mem_pw, mem_email, mem_zipcode, mem_addr, mem_addr_d, 
			mem_phone, mem_nick, mem_accept_e, mem_point, 
			mem_date_sub, mem_date_up, mem_date_last, mem_authcode
		from member_tbl
		where mem_id = #{mem_id}
	</select> 
	
	<!-- 로그인(MemberDTO 가져옴) 비번을 파라미터 사용안하고 있음에 주의 -->
	<select id="login" parameterType="MemberDTO" resultType="MemberDTO">
		select mem_id, mem_pw, mem_nick, mem_name, mem_point, mem_date_last
		from member_tbl
		where mem_id=#{mem_id}
		
	</select>
	
	<!-- 로그인 시간 업데이트 -->
	<update id="loginUpdate" parameterType="string">
		update member_tbl
		set mem_date_last = sysdate
		where mem_id = #{mem_id}
	</update>

	<!-- 회원가입 -->
	<insert id="join" parameterType="MemberVO">
		insert into member_tbl(mem_id, MEM_NAME, MEM_PW, MEM_EMAIL, MEM_ZIPCODE, 
			MEM_ADDR, MEM_ADDR_D, MEM_PHONE, MEM_NICK, MEM_ACCEPT_E)
		values(#{mem_id}, #{mem_name}, #{mem_pw}, #{mem_email}, #{mem_zipcode},
			#{mem_addr}, #{mem_addr_d}, #{mem_phone}, #{mem_nick}, #{mem_accept_e})
	</insert>

	<!-- 아이디 중복 체크 -->
	<select id="checkIdDuplicate" parameterType="string" resultType="int">
		select count(*)
		from member_tbl
		where mem_id = #{mem_id}
	</select>
	
	<!-- 회원정보 수정 -->
	<update id="modifyUserInfo" parameterType="MemberVO" >
		update member_tbl
		set mem_name=#{mem_name}, mem_nick=#{mem_nick}, mem_email=#{mem_email},
			mem_phone=#{mem_phone}, mem_zipcode=#{mem_zipcode}, mem_addr=#{mem_addr}, 
			mem_addr_d=#{mem_addr_d}, mem_accept_e=#{mem_accept_e}, mem_date_up=sysdate
		where mem_id=#{mem_id}	
	</update>
	
	<!-- 비밀번호 변경 -->
	<update id="changePw" parameterType="MemberDTO">
		update member_tbl
		set mem_pw = #{mem_pw}
		where mem_id=#{mem_id}
	</update>
	
	<!-- 회원 탈퇴 -->
	<delete id="deleteUser" parameterType="string">
		delete from member_tbl
		where mem_id=#{mem_id}
	</delete>
	
	<!-- 로그인 정보 쿠키 저장-->
	<update id="saveCookie" parameterType="Map">
		update member_tbl
		set mem_session_key = #{mem_session_key},
			mem_session_limit = #{mem_session_limit}
		where mem_id=#{mem_id}
	</update>
	 
	
	<!-- 쿠키에 저장된 세션값으로 로그인 정보 가져옴 -->
	<select id="checkUserSession" parameterType="string" resultType="MemberVO">
		select * 
		from tbl_user 
		where mem_session_key = #{value} and mem_session_limit > now()
	</select>
	
	
</mapper>

※ 조건에 있는 비밀번호는 주석처리


홈페이지 구축할 시에는 운영측 관점에서

1. 사용자 모드 / 2. 관리자 모드

1. 사용자 모드에서 주요 기능 :

- 회원기능 : MemberController.java

2. 관리자 모드에서 주요 기능 :

- 로그인 : AdminController.java

- 카테고리 : DB에서 데이터를 직접구성

- 상품관리

반응형

'Backend' 카테고리의 다른 글

[Nest.js] Nest.js란 무엇인가 (번역)  (0) 2022.03.27