Programming/스프링(spring) - Enterprise

스프링(spring)/ 회원 시스템 구축 4(암호화)

esoog Polaris 2023. 8. 2. 13:35
반응형

1. Spring Security를 사용하기에 먼저 pom.xml 설정을 해준다.(스프링 시큐리티)

 

<!-- 스프링 시큐리티 -->
<!-- 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. 보안 관련이라 컨테이너 관리 파일을 따로 만들어 사용했다. 

기존의 servlet-context이 있는 폴더에(src/main/webapp/WEB_INF/spring/appServlet)

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>

* 여기서 `<beans>`는 스프링 프레임워크의 설정 파일에서 사용되는 태그로서, 스프링 빈(Bean)을 정의하고 설정하는 역할. 빈<bean>은 스프링 컨테이너에 의해 생성되고 관리되는 객체를 말하며, 이러한 빈을 `<bean>` 태그를 사용하여 정의. `` 태그의 네임스페이스 선언은 스프링 프레임워크의 XML 설정 파일에서 사용할 수 있는 태그들과 스키마를 지정하는 역할. 네임스페이스를 선언하면 해당 스키마에 정의된 태그들을 사용할 수 있게 됨.

* 쉽게말해, 해당 프로젝트의 설정 관리xml을 하나 더 추가한다는 의미.

 

 

 

 

3. 그러면 이제 웹에서 시큐리티.xml파일을 읽을 수 있도록 web.xml파일로 가서 

아래 코드 추가(기존에 아래 spring-security관련 구문만 추가하면 된다.)

 

    <init-param>
     <param-name>contextConfigLocation</param-name>
     <param-value>
     	/WEB-INF/spring/appServlet/servlet-context.xml
     	
        <!--  스프링 시큐리티 xml파일 읽을 수 있게 -->
     	/WEB-INF/spring/appServlet/spring-security.xml
     </param-value>
    </init-param>

 

 

 

 

 

4. 그 다음부터는 이 시큐리티의 암호화 기능을 사용하는 것 뿐이다.

UserController파일에서 입력받은 값과 데이터베이스에 저장하는 데이터 간에 암호화 로직을 설정한다.

먼저 객체부터 생성.

 

	@Autowired
	private BCryptPasswordEncoder pwdEncoder;
	// 스프링 시큐리티 암호화 기능 사용.

 

 

그리고 다시 생각해봐야 할 것은, 회원가입 시 비밀번호를 새로 암호화 시키는 로직으로 수정해야 한다.(post)

 

	@PostMapping("/account/join")
	public String joinProcess(UserVO userVo) {
		// 회원가입 처리 코드
		String inputPass = userVo.getPwd();
		String pwd = pwdEncoder.encode(inputPass);
		userVo.setPwd(pwd);
		
		try {
			userService.join(userVo);
		} catch (Exception e) {
			// 예외 처리 로직 추가
			e.printStackTrace();
			// 실패 시 에러 페이지 또는 회원가입 실패 페이지로 이동하도록 처리
			return "error-page";
		}
		// 회원가입 성공 시 홈으로 리다이렉트
		return "redirect:/";
	}

*위에 pwd 관련 로직이 추가 되었는데; 입력값을 암호화 시켜 저장시키는 로직이다.

* pwdEncoder.encode(입력값)

 

 

그와 함께, 로그인 비밀번호 매치도 바뀌고, (post)

 

	@PostMapping("/account/login")
	public String login(UserVO vo, HttpServletRequest req, RedirectAttributes rttr) throws Exception{
		
		HttpSession session = req.getSession();
		UserVO login = userService.login(vo);

		if (login == null || !pwdEncoder.matches(vo.getPwd(), login.getPwd())) {
			rttr.addFlashAttribute("msg", "아이디와 비밀번호를 확인해주세요.");
	        return "redirect:/account/login"; // 리다이렉트하여 로그인 페이지로 돌아감
		}else {
			session.setAttribute("member", login);
		}
		// member라는 이름으로 login 객체를 저장함.
		
		return "redirect:/";
	}

*pwdEncoder.matches(입력값, 해시화된 암호) 를 비교하여 boolean값으로 낸다.

 

 

회원정보 수정 시 비밀번호 암호화 방식도 바뀌고,(post)

 

	@PostMapping("/account/update")
	public String postUpdate(UserVO vo) throws Exception{
		String inputPass = vo.getPwd();
		String pwd = pwdEncoder.encode(inputPass);
		vo.setPwd(pwd);
		
		userService.memberUpdate(vo);
		return "redirect:/";
	}

 

 

회원탈퇴 시, 비밀번호 확인 로직도 바뀔 것이다.(post)

 

	// 회원 탈퇴 post
	@PostMapping("/account/delete")
	public String postDelete(UserVO vo, HttpSession session, RedirectAttributes rttr) throws Exception{
		UserVO member = (UserVO)session.getAttribute("member");
		// 세션에서 데이터를 가져오려는 건데, 세션 데이터는 기본적으로 Object형이다.
		// 그래서 (UserVO)타입으로 형변환 해서 member에 담고 있다.
		
		// 현재 로그인 되어 세션에있는 비밀번호 UserVO 게터 사용.
		String sessionPass = member.getPwd();
		// vo로 들어오는 비밀번호
		String voPass = vo.getPwd();
		
		if(!pwdEncoder.matches(voPass, sessionPass)) {
			rttr.addFlashAttribute("msg", false);
			// msg라는 이름으로 false를 넘겨준다.
			return "redirect:/account/delete";
		}
		
		userService.memberDelete(vo);
		session.invalidate();
		return "redirect:/";
	}

 

 

 

 

 

5. 여기서 로직이 꼬일 수 있는데;

*pwdEncoder.matches(입력값, 해시화된 암호)는 단순 입력값해시화된 암호를 비교하는 거다.

이는 로그인/ 탈퇴 시 비밀번호를 DB의 데이터와 비교 할 때,입력값은 그대로 두고,

아이디 일치정보를 우선 셀렉트 하여, 그 레코드의 암호와 비교해야 한다.

결론은, 데이터와 일치 확인하는 쿼리문을 수정할 필요가 있다. 

일단, 아이디 일치하면 그 다음 암호를 꺼내서 비교해야 할테니.

accountMapper.xml파일에서 아래 코드를 수정한다.(비밀번호를 바로 검증했던 로직을 주석 처리.)

 

	<!-- 로그인 -->
	<select id="login" resultType="com.project.model.UserVO">
		SELECT *
		FROM user
		WHERE id = #{id}
		<!-- AND pwd = #{pwd} -->
	</select>

	<!-- 회원탈퇴 -->
	<delete id="memberDelete">
		DELETE FROM user
		WHERE id = #{id}
		<!-- AND pwd = #{pwd} -->
	</delete>

 

 

 

 

$2a$~로 시작하는 암호화

 확인. 나이스. 

 

 

 

 

 

728x90