Spring Boot

[Spring Boot] Spring Security와 JPA로 로그인 구현하기

ZIAHO 2024. 7. 21. 14:46

안녕하세요

 

이번시간에는 지난시간에 회원가입을 했던 데이터로 로그인을 구현 해 보겠습니다.


📁 UserDetails 구현하기

로그인 기능 구현을 위해 Spring Security의 UserDetails를 구현한 클래스를 만들어줍니다.

이 클래스를 통해서 Spring Security가 사용자의 정보를 담아두는 역할을 수행 할 수 있습니다.

 

MemberDetails.java

@RequiredArgsConstructor
public class MemberDetails implements UserDetails {

  private final Member member;

  /**
   * Member 계정의 권한
   */
  @Override
  public Collection<? extends GrantedAuthority> getAuthorities() {
    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
    authorities.add(new SimpleGrantedAuthority(member.getGrade()));

    return authorities;
  }

  /**
   * Meber 계정의 Id를 담아둠
   */
  @Override
  public String getUsername() {
    return member.getId();
  }

  /**
   * Member 계정의 패스워드를 담아둠
   */
  @Override
  public String getPassword() {
    return member.getPw();
  }

📁 UserDetailsService 구현하기

위와 마찬가지로 Spring Security의 UserDetailsService를 구현하는 클래스를 만듭니다.

로그인 요청 시 해당 서비스에서 요청을 가로채 로그인 처리를 시도합니다.

 

MemberDetailsService.java

@Service
@RequiredArgsConstructor
public class MemberDetailsService implements UserDetailsService {

  private final MemberRepository memberRepository;

  @Override
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    Member member = memberRepository.findById(username);
    System.out.println("username >>> " + username);
    System.out.println("member >>> " + member);

    if(member == null) {
      throw new UsernameNotFoundException(username + "을 찾을 수 없습니다.");
    }

    return new MemberDetails(member);
  }

}

📁 AuthenticationProvider 구현하기

로그인 정보를 가로 챈 후 비밀번호를 비교하고,

인증권한, 비밀번호 만료 등 인증정보를 반환하기 위한 클래스를 구현합니다.

(인증정보 반환 내용은 추후 업데이트 예정 입니다.)

 

MemberAuthenticationProvider.java

@Component
@RequiredArgsConstructor
public class MemberAuthenticationProvider implements AuthenticationProvider {

  private final MemberDetailsService memberDetailsService;
  private final BCryptPasswordEncoder bCryptPasswordEncoder;

  @Override
  public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    String username = authentication.getName();                   // 사용자가 입력한 id
    String password = authentication.getCredentials().toString(); // 사용자가 입력한 패스워드

    // 생성해둔 MemberDetailsService에서 loadUserByUsername 메소드를 호출하여 사용자 정보를 가져온다.
    MemberDetails memberDetails = (MemberDetails) memberDetailsService.loadUserByUsername(username);

    // 비밀번호 비교: 사용자가 입력한 비밀번호와 DB에 저장된(암호화) 비밀번호를 비교한다.
    String dbPassword = memberDetails.getPassword(); // DB에 저장된 비밀번호

    if (!bCryptPasswordEncoder.matches(password, dbPassword)) {
      System.out.println("[로그인 실패] " + username + "님의 비밀번호가 일치하지 않습니다.");
      throw new BadCredentialsException("[System] 아이디 또는 비밀번호가 일치하지 않습니다.");
    }

    // 인증이 성공하면 UsernamePasswordAuthenticationToken 객체를 반환
    // 해당 객체는 Authentication 객체로 추후 인증이 끝난 후 SecurityContextHolder.getContext()에 저장된다.
    return new UsernamePasswordAuthenticationToken(memberDetails, null, memberDetails.getAuthorities());
  }

  @Override
  public boolean supports(Class<?> authentication) {
    return authentication.equals(UsernamePasswordAuthenticationToken.class);
  }
}

📁 로그인 해보기

1) 비밀번호를 정확하게 입력 하였을 경우

 

 

로그인 성공 화면으로 이동

 

2) 비밀번호를 다르게 입력하였을 경우

에는 로그인 실패 화면으로 이동하도록 Config에 설정을 해 두었는데 Exception을 발생시키도록 처리를 해 두었더니 의도한대로 로그인 실패화면으로 이동되지가 않고 로그인 화면을 재호출합니다.

해당 부분은 추후 핸들러를 설정하여 수정할 예정입니다.


💡 출처

https://dev-log.tistory.com/4

 

[ Spring Security ] 스프링 시큐리티 로그인 5.7이상 버전 ( 6.x 버전 ) ( JPA , 로그인 기억하기 )

이번 스프링 시큐리티는 Spring Data JPA를 통한 로그인 입니다 Spring Boot 3.0.2 버전 , Spring Security 6 사용하여 기존 5.7 이하에서 사용하던, Deprecated 된 부분들(websecurityconfigureradapter , authorizeRequests)를 바

dev-log.tistory.com