
스프링 기반 애플리케이션의 보안을 담당하는 스프링 하위 프레임워크
스프링 시큐리티는 필터 기반으로 동작하며, 다양한 필터들로 나눠져 있다.
각 필터는 인증, 인가와 관련된 작업을 처리한다.
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'
testImplementation 'org.springframework.security:spring-security-test'
1. User entity 작성 > UserDetails 상속
- UserDetails
스프링 시큐리티에서 사용자의 인증 정보를 담아두는 인터페이스
해당 객체를 가지고 인증 정보를 가져오려면 다음의 메서드들을 오버라이드 해야한다.
public class User implements UserDetails {
// 필요한 컬럼 작성하기
...
@Override // 권한 반환
public Collection<? extends GrantedAuthority> getAuthorities() {
return List.of(new SimpleGrantedAuthority("user"));
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername(){
// 사용자 이름으로 사용할 컬럼을 반환해준다. ex)email
return username;
}
// 계정 만료 여부 반환
@Override
public boolean isAccountNonExpired() {
// 만료되었는지 확인하는 로직
return true; //true > 만료되지 않음
}
// 계정 잠금 여부 반환
@Override
public boolean isAccountNonLocked() {
// 계정 잠금되었는지 확인하는 로직
return true; // true > 잠기지 않음
}
// 패스워드의 만료 여부 반환
@Override
public boolean isCredentialsNonExpired() {
// 패스워드 만료 확인 로직
return true; //true > 만료되지 않음
}
//계정 사용 가능 여부 반환
@Override
public boolean isEnabled() {
// 계정 사용 가능 여부 확인 로직
return true; // true > 사용 가능
}
}
2. 서비스 메서드 코드
@Service
@RequiredArgsConstructor
// 스프링 시큐리티에서 사용자 정보를 가져오는 인터페이스
public class UserDetailService implements UserDetailsService {
private final UserRepository userRepository;
// 사용자 이름으로 사용자의 정보를 가져오는 메서드
@Override
public User loadUserByUsername(String username){
// User에서 설정해준 컬럼을 넣어줘야한다. ex) email
return userRepository.findByUsername(username)
.orElseThrow(()->new IllegalArgumentException(username));
}
}
3. 시큐리티 설정
주요 메서드
- requestMatchers() : 특정 요청과 일치하는 url에 대한 액세스 설정
- permitAll(): 누구나 접근 가능 > 인증/인가 없이 접근 가능
- anyRequest() : requestMatchers에 설정하지 않은 url에 대한 요청
- authenticated() : 인가는 필요없지만, 인증이 성공된 상태에 접근 가능
// 경로 > config/WebSecurityConfig
@Configuration
@RequiredArgsConstructor
public class WebSecurityConfig {
private final UserDetailsService userService;
// 스프링 시큐리티 기능 비활성화 > 정적 리소스
@Bean
public WebSecurityCustomizer configure(){
return (web) -> web.ignoring()
.requestMatchers(toH2Console())
.requestMatchers("/static/**");
}
// 특정 http 요청에 대한 웹 기반 보안 구성
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
return http
.authorizeRequests()//인증, 인가 설정
.requestMatchers("/login", "/signup","/user").permitAll()
.anyRequest().authenticated()
.and()
.formLogin() // 폼기반 로그인 설정
.loginPage("/login") // 설정하지 않으면 시큐리티에서 기본 제공하는 로그인 페이지로 이동
.defaultSuccessUrl("/articles") // 로그인 성공시 이동
.and()
.logout()
.logoutSuccessUrl("/login")
.invalidateHttpSession(true) // 로그아웃 이후 세션 전체 삭제 여부 설정
.and()
.csrf().disable()
.build();
}
// 인증 관리자 관련 설정
@Bean
public AuthenticationManager authenticationManager(
HttpSecurity http,
BCryptPasswordEncoder bCryptPasswordEncoder,
UserDetailsService userService
) throws Exception {
return http.getSharedObject(AuthenticationManagerBuilder.class)
.userDetailsService(userService) // 반드시 userDetailsService를 상속받은 클래스
.passwordEncoder(bCryptPasswordEncoder)
.and()
.build();
}
//패스워드 인코더로 사용할 빈 등록
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
}
4. 컨트롤러, 서비스 작성하기
로그인, 회원가입시 반환할 viewController와 apiController를 작성한다.
◾ 로그아웃 메서드
@GetMapping("/logout")
public String logout(HttpServletRequest request, HttpServletResponse response){
new SecurityContextLogoutHandler().logout(request, response, SecurityContextHolder.getContext().getAuthentication());
return "redirect:/login";
}
@SpringBootApplication(exclude = SecurityAutoConfiguration.class)
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}