[Spring Boot] Spring Security와 JPA로 로그인 구현하기
안녕하세요
이번시간에는 지난시간에 회원가입을 했던 데이터로 로그인을 구현 해 보겠습니다.
📁 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을 발생시키도록 처리를 해 두었더니 의도한대로 로그인 실패화면으로 이동되지가 않고 로그인 화면을 재호출합니다.
해당 부분은 추후 핸들러를 설정하여 수정할 예정입니다.
💡 출처
[ 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