Spring , passwordEncoder
A A

목차

    728x90

     

    PasswordEncoder의 주요 개념과 기능

     

    • 비밀번호 인코딩

    비밀번호를 데이터베이스에 직접 저장하지않고 , 해시(Hash) 알고리즘을 통해 변환한 값을 저장하는 방식.

    PasswordEncoder는 이를 위해 encode() 메서드를 제공

    encode(): 평문 비밀번호를 해싱하여 변환

    String rawPassword = "myPassword123";
    String encodedPassword = passwordEncoder.encode(rawPassword);

     

    • 비밀번호 매칭

    로그인 시 입력한 비밀번호가 저장된 해시 값과 일치하는지 검증하기 위해 matches() 메서드를 사용

    matches(): 입력한 비밀번호와 저장된 해시 값의 일치 여부를 확인

    비밀번호가 일치하면 true, 그렇지 않으면 false를 반환

    boolean isMatch = passwordEncoder.matches(rawPassword, encodedPassword);

     

     

    주입방식에 따른 차이

     

    1. 직접 생성방식
    PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

     

    2. @Configuration 및 @Bean을 사용한 방식
    @Configuration
    public class DemoConfig {
    	@Bean
    	public PasswordEncoder getPasswordEncoder() {
    		return new BCryptPasswordEncoder();
    	}
    }

     

     

    • new 키워드 방식은 간단하지만 객체 관리 측면에서 재사용이 어렵고, 코드 중복 및 관리 복잡성을 증가시킬 수 있다.
    • @Bean 방식은 스프링 컨텍스트 내에서 싱글톤으로 관리되어 애플리케이션 전체에서 효율적으로 재사용할 수 있고, 의존성 주입으로 필요한 곳에 간편하게 주입할 수 있어 더 유지보수에 유리하다.
    BCryptPasswordEncoder

     

    스프링 시큐리티에서 가장 흔히 사용하는 PasswordEncoder 구현체는 BCryptPasswordEncoder입니다.

    • BCrypt 알고리즘: 해시 함수로, 비밀번호 해싱에 매우 안전한 BCrypt 알고리즘을 사용합니다. 이 알고리즘은 속도를 조절할 수 있어 무차별 대입 공격(Brute Force Attack)에 강합니다.
    • 솔트(Salt): BCrypt는 자동으로 솔트(Salt)를 생성하여 해시 값에 포함시킵니다. 솔트는 같은 비밀번호여도 항상 다른 해시 값이 생성되도록 하는 추가 데이터입니다.
    • 강도 조절: 생성 시 강도를 설정하여 해싱에 걸리는 시간을 조정할 수 있습니다. 기본 강도는 10이며, 강도를 높일수록 해시 작업이 느려져서 공격에 더 강해집니다.
    PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(12); // 강도를 12로 설정

     

     

     

    PasswordEncoder의 장점
    • 안전한 비밀번호 저장 
      • 비밀번호가 직접 노출되지 않도록 보호하고 , 해시값으로 저장함으로 보안성을 높임
    • 다양한 구현체 ( PasswordEncoder 인터페이스를 통해 다양한 해싱 알고리즘 사용)
      • BCryptPasswordEncoder: 안전성 높은 BCrypt 알고리즘 기반.
      • Pbkdf2PasswordEncoder: PBKDF2 알고리즘 기반.
      • SCryptPasswordEncoder: 메모리 집약적인 Scrypt 알고리즘 기반.

     

     

    로그인 passwordEncoder (matches() 사용)
    @AllArgsConstructor
    @Controller
    @RequestMapping(value = "/member")
    public class MemberController {
    
    	
    	//@Autowired(required = false)
    	JoService joService;
    	MemberService service;
    	PasswordEncoder passwordEncoder;
    	//PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    	//주입받기 위해 , 생성되어있어야 하는데 , java-Config (DemoConfig.java)파일을 이용한다.

    DemoConfig.java에 Bean을 만들어 둠.

    	@RequestMapping(value = "/login", method = RequestMethod.POST)
    	public String mLogin(Model model, HttpServletRequest request, HttpSession session,MemberDTO dto, JoDTO jdto) {
    		//String id = request.getParameter("id");
            // => 요청을 처리하는 매핑메서드의 인자로 ~DTO 등의 객체를 정의하면,
            //    Parameter 들의 name 과 일치하는 필드의 값들은 자동으로 담겨짐(setter 사용함)
    		String password = dto.getPassword();
    		String uri = "redirect:/home";
    		dto = service.selectOne(dto.getId());
    		if(dto !=null && passwordEncoder.matches(password, dto.getPassword())) {
    			session.setAttribute("loginID", dto.getId());
    			session.setAttribute("loginName", dto.getName());
    			session.setAttribute("loginJno", dto.getJno());
    			System.out.println("성공 !");
    
    		}else {
    			System.out.println("실패 !");
    			model.addAttribute("message", "로그인 다시 하세요.");
    			uri="member/loginForm";
    		}
    		return uri;
    	}

     

    회원가입시 passwordEncoder(encode() 사용)
    	@RequestMapping(value = "/mjoin", method = RequestMethod.POST)
    	public String mjoin(Model model ,HttpServletRequest request , MemberDTO dto) throws IOException {
    		String uri = "member/loginForm";
    		//* passwordEncoder 적용
    		dto.setPassword(passwordEncoder.encode(dto.getPassword()));
    		//* 이미지 업로드처리 =====================================
    		...
    		...
    		// ========================================================
    		if(service.insert(dto)>0) {
    			model.addAttribute("message","회원가입 성공 ! 로그인 후 이용해주세요");
    		}else {
    			model.addAttribute("message","회원가입 실패 ! 다시 이용해주세요");
    			uri="member/joinForm";
    		}// 문자열로 , 경로를 보낼때는 폴더명부터 입력해줘야함.
    		return uri;
    	}

     

    Copyright 2024. GRAVITY all rights reserved