오늘은 회원가입, 로그인, 권한 설정까지 끝냈다!.!
드디어 OAuth를 건드릴 수 있음 후후,, 저녁 먹고 세팅만 해놔야지
// SecurityConfig.java
@Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
비밀번호 암호화를 위해서 SecurityConfig에 BCryptPasswordEncoder Bean을 생성해줬다.
(일단 예제에서 서비스를 따로 안 만들고 컨트롤러에서 구현해서 따라했는데 지금 보니까 나중에 서비스로 다시 빼야겠다.)
// IndexController.java
@Autowired
private UserRepository userRepository;
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
@PostMapping("/join") // 회원가입 요청
public String join(User user){
user.setRole("ROLE_USER");
// 패스워드 암호화해서 유저에 다시 세팅
String rawPassword = user.getPassword();
String encPassword = bCryptPasswordEncoder.encode(rawPassword);
user.setPassword(encPassword);
// 유저 DB에 저장
userRepository.save(user);
return "redirect:/loginForm";
}
너무나도 간단하게 회원가입 끝..아직 기본이니까요😬🙌
아무튼 bCryptPasswordEncoder 이용해서 비밀번호 암호화 후에 유저에 다시 세팅해서 DB에 저장해주기!
SecurityConfig에 추가된 부분 있는데
.formLogin(formLogin -> // 로그인 설정
formLogin.loginPage("/loginForm")
// 권한 없을 경우, 로그인 페이지로
.loginProcessingUrl("/login")
// /login 주소가 호출되면 시큐리티가 낚아채서 대신 로그인 진행
.defaultSuccessUrl("/")
// 로그인 페이지로 접속했을 경우, default 페이지로 -> 아닌 경우 요청했던 페이지로 감
)
이 부분으로 로그인 요청하면 시큐리티가 로그인 진행할 수 있게 하고
// Spring Security가 요청을 가로채서 PrincipalDetailsService의 loadUserByUsername() 호출
@Service
public class PrincipalDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
// security session(내부 Authentication(내부 UserDetails))
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User userEntity = userRepository.findByUsername(username);
if(userEntity != null){
return new PrincipalDetails(userEntity);
}
return null;
}
}
public class PrincipalDetails implements UserDetails {
private User user;
public PrincipalDetails(User user){
this.user = user;
}
// 해당 유저의 권한을 리턴하는 곳
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> collection = new ArrayList<>();
collection.add(new GrantedAuthority() {
@Override
public String getAuthority() {
return user.getRole();
}
});
return collection;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUsername();
}
...
라고 코드는 간단하지만,,,그래서 과정이 정확히 어떻게 되는건데 싶어서
SpringSecurity를 이용한 회원 로그인 구현과 동작 원리 정리
위처럼 너무 좋은 링크 발견과,,,지피티한테 물어봤다. 근데 링크가 너무 좋음ㅎㅎ
SecurityContext
에 인증 정보를 저장사용자의 로그인 요청:
/login
URL로 POST 요청을 보냅니다.인증 필터가 요청을 가로챔:
UsernamePasswordAuthenticationFilter
가 /login
요청을 가로채고, 사용자 이름과 비밀번호를 추출합니다.Authentication 객체 생성:
UsernamePasswordAuthenticationFilter
는 추출한 사용자 이름과 비밀번호로 UsernamePasswordAuthenticationToken
객체를 생성합니다. 이 객체는 인증되지 않은 상태입니다.AuthenticationManager에 전달:
UsernamePasswordAuthenticationToken
객체는 AuthenticationManager
로 전달됩니다. Spring Security의 기본 구현에서는 ProviderManager
가 AuthenticationManager
를 구현합니다.AuthenticationProvider 사용:
ProviderManager
는 하나 이상의 AuthenticationProvider
를 가지고 있으며, 각각은 특정 유형의 인증을 처리합니다. 기본 설정에서는 DaoAuthenticationProvider
가 주로 사용됩니다.UserDetailsService 호출:
DaoAuthenticationProvider
는 UserDetailsService
를 사용하여 사용자 정보를 로드합니다. 이 과정에서 PrincipalDetailsService
가 호출되어 데이터베이스에서 사용자 정보를 가져오고, PrincipalDetails
객체를 반환합니다.비밀번호 검증:
DaoAuthenticationProvider
는 UserDetails
에서 반환된 사용자 정보(PrincipalDetails
)와 입력된 비밀번호를 비교하여 인증을 진행합니다. 비밀번호가 일치하면 인증이 성공한 것으로 간주합니다.인증된 Authentication 객체 생성:
DaoAuthenticationProvider
는 인증된 UsernamePasswordAuthenticationToken
객체를 생성합니다. 이 객체에는 인증된 사용자 정보(PrincipalDetails
)와 권한 정보가 포함됩니다.SecurityContext에 저장:
Authentication
객체는 SecurityContextHolder
를 통해 SecurityContext
에 저장됩니다. 이로 인해 현재 사용자의 인증 상태와 정보를 애플리케이션의 모든 부분에서 참조할 수 있게 됩니다.인증 성공 후 처리:
UserDetails
:
PrincipalDetails
클래스가 이를 구현하여 사용자 정보를 제공합니다.UserDetailsService
:
PrincipalDetailsService
클래스가 이를 구현하여 데이터베이스에서 사용자 정보를 가져옵니다.Authentication
:
UsernamePasswordAuthenticationToken
클래스가 이를 구현하여 사용자 이름과 비밀번호를 포함합니다.AuthenticationProvider
:
DaoAuthenticationProvider
클래스가 이를 구현하여 UserDetailsService
를 사용하여 사용자 정보를 검증합니다.SecurityContext
:
SecurityContextHolder
를 통해 접근할 수 있습니다.