[Spring Security] Form Login 과 UserDetails
2024.07.23 - [Spring] - [Spring Security] Spring Security Configuration 와 BCrypt 암호화 메서드
[Spring Security] Spring Security Configuration 와 BCrypt 암호화 메서드
이전에 JWT가 무엇인지 알고, 인가 인증에 대해서 글을 기록해뒀다.이번에는, 스프링에서 보안을 위해 쓰이는 Spring Security에 대해서 알아보고, 이를 어떻게 사용해볼 수 있는지 알아보겠다. 2024
jinnocode.tistory.com
이전 포스팅에서 form login에 대해서 간략하게 설명했다.
이번에 세부적으로 한번 알아보자.
Form Login이 뭐죠?
간단하게 말해서 Form Login 이란 스프링 시큐리티에서 제공하는 인증 방식이라고 생각하면 된다. 물론, API를 따로 만들어 사용하는 Authentication 도 많이 쓰지만 스프링 시큐리티에서 제공하는 Form Login을 알아서 나쁠게 없다고 생각한다.
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
http
.authorizeHttpRequests((auth) -> auth
.requestMatchers("/", "/login").permitAll()
.requestMatchers("/admin").hasRole("ADMIN")
.requestMatchers("/my/**").hasAnyRole("ADMIN", "USER")
.anyRequest().authenticated()
);
http
.formLogin((form) -> form
.loginPage("/loginPage")
.defaultSuccessUrl("/members")
.failureUrl("/loginFail")
.usernameParameter("userid")
.passwordParameter("passwd")
.loginProcessingUrl("/login_page")
.permitAll()
);
return http.build();
}
}
먼저 , configuration 클래스를 설정해준다.
앞선 포스팅에서 작성했던 설정 클래스인데, .formLogin 부분을 보면 된다. 로그인 페이지를 "/loginPage"로 설정해주고, 우리는 formLogin을 진행 해준다는 것을 알 수 있다.

위는 formLogin을 하는 과정이다.
세션을 사용하여 로그인을 하며 Login Page에서 로그인하여 인증을 성공하면 인증정보를 Session에 저장하고 이후 인증정보도 Session의 정보를 활용한다.
UsernamePasswordAuthenticationFilter를 사용하며, 로그인 요청이 아니면 해당 필터는 패스로그인 요청일 경우 인증정보 생성(UsernamePasswordAuthenticationToken) 후 로직을 수행한다.
이러한 기능을 사용하기 위해서는 UserDetail을 꼭 생성해주어야 한다. 이제 UserDetail이 무엇인지 알아보자.
UserDetail은 또 뭐죠?
public class CustomUserDetails implements UserDetails {
private UserEntity userEntity;
public CustomUserDetails(UserEntity userEntity) {
this.userEntity = userEntity;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> collection = new ArrayList<>();
collection.add(new GrantedAuthority() {
@Override
public String getAuthority() {
return userEntity.getRole();
}
});
return collection;
}
@Override
public String getPassword() {
return userEntity.getPassword();
}
@Override
public String getUsername() {
return userEntity.getUsername();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
먼저 내부필드를 살펴보자.
UserEntity는 유저를 나타내는 엔티티 그 자체를 의미한다. 그리고 우리는 UserDetails의 구현체를 생성해야 이를 사용할 수 있다.
나머지 구현해야하는 메서드들은 모두 이름이 직관적이고, 구현하기 벅차다고 생각하지 않아 스킵하고,
권한을 가져오는 getAuthorities() 메서드만 조금 살펴보겠다.
이 메서드는 사용자의 권한을 가져오기 위해 사용되며, userEntity 객체에서 역할(권한)을 가져와 GrantedAuthority 인터페이스를 구현하는 익명 클래스 객체로 감싸고, 이를 컬렉션에 추가한 후 반환한다. 이는 사용자 인증 및 인가 과정에서 해당 사용자가 어떤 권한을 가지고 있는지를 확인하는 데 사용된다.
UserDetailsService
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserEntity userData = userRepository.findByUsername(username);
if (userData != null) {
return new CustomUserDetails(userData);
}
return null;
}
}
위에서 만든 UserDetails의 구현체를 사용하여 간단한 로그인 로직을 구현할 수 있다.
이번에는 Spring Security에서 구현해준 폼 로그인 기능을 사용하였다. 여기서는 세션을 사용한다면, 우리는 이전에 배웠던 JWT와 Spring Security를 접목시킬 수도 있을 것이다. 그것에 대해 알아보자.
사실 너무 어렵다. 만만하게 봤는데, 스프링 시큐리티에 대해서 공부하는 동안 계속해서 눈뜨고 코베이는 기분이다... 어떻게 해야할까..