[Spring Security] 기초 1 (configuration)
<순서>
1. pom.xml 파일에 spring security dependency 추가
-> 프로그램의 모든 요청에 인증과 인가(권한)에 대한 조건을 판단
모든 요청(페이지 이동)에 있어서 반드시 인증을 받도록 setting
2. 설정 파일(SecurityConfig.java)을 생성하고, 코드 구현
@Configuration -> 해당 클래스가 Security설정 파일임을 Spring에게 인지시키는 역할
@EnableWebSecurity ->해당 클래스로부터 만들어진 객체가 security 설정 한다는 것을 인지
즉, 매개변수로 들어온 HttpSecurity객체를 사용하여 인증 및 인가에 대한 제어를 구성할 수 있다.
public class SecurityConfig{
@Bean -> SecurityFilterChain을 리턴하면 securityFilterChain이라는 객체 자동 생성되도록
public SecurityFilterChain filterChain(HttpSecurity security) throws Exception{
authorizeRequests() -> 권한(인증/인가)에 대한 설정 시작하겠다
antMatchers("/index") -> controller에서 요청받은 ("/index")에 대한 설정을 하겠다
permitAll() -> 인증/인가 절차없이 누구에게나 사용할 수 있게 허용하겠다.
★antMatchers("/index","/login", "/adim") 이런식으로 작성 가능
즉 로그인 없이도 접근 가능하도록 하겠다
security.authorizeRequests().antMatchers("/index").permitAll();
authenticated() -> 인증을 받아야 한다
security.authorizeRequests().antMatchers("/member").authenticated();
-> antMatchers("/member")페이지 들어갈 때 권한 받아라
anyRequest() -> 어떤 요청이라도
authenticated() -> 인증을 받아야 한다
security.authorizeRequests().anyRequest().authenticated();
}
}
security.authorizeRequests()
.antMatchers("/index").permitAll()
.antMatchers("/member").authenticated()
.antMatchers("/manager").hasAnyRole("MANAGER","ADMIN")
-> ("/manager")라는 요청은hasAnyRole("MANAGER","ADMIN") MANAGER, ADMIN라는 인가(권한)이 있어야 한다
.antMatchers("/admin").hasRole("ADMIN")
-> ("/admin")라는 요청은 hasRole("ADMIN") ADMIN라는 인가(권한)이 있어야 한다
미인증 시 스프링 기본 제공 로그인 페이지 이동하겠다.
.and().formLogin(); (and 작성하면 security부터 연결해서 작성 가능)
권한 문제로 접근 거부될 때 기본적으로 이동할 페이지 지정
security.exceptionHandling().accessDeniedPage("/accessDenied");
로그아웃 시 세션에 저장된 데이터 삭제 / 로그아웃 성공 시 logoutSuccessUrl("/index") 페이지로 가겠다
security.logout().invalidateHttpSession(true).logoutSuccessUrl("/index");
사이트 간 요청 위조 방지(csrf)하는 security 기본 기능 비활성화(보안문제)
csrf 공격을 막기 위한 기본 설정 해제(실습때문에 해제 시킨것)
security.csrf().disable();
return security.build();
최종 깔끔 버전
@Configuration
@EnableWebSecurity
public class SecurityConfig{
@Bean
public SecurityFilterChain filterChain(HttpSecurity security) throws Exception{
security.csrf().disable() //csrf 공격을 막기 위한 기본 설정 해제(현재 테스트를 위한 것)
//페이지 관련
.authorizeRequests() //인증, 인가에 대한 설정 시작하겠다
.antMatchers("/index","/login").permitAll() //index 요청은 누구나 접근 가능한!
.antMatchers("/manager").hasAnyRole("MANAGER","ADMIN") //manager 요청은 manager/admin 권한이 필요하다.
.antMatchers("/admin").hasRole("ADMIN") //admin 요청은 admin 권한 필요
.anyRequest().permitAll() //그 외에는 누구나 허용하겠다 반대 <-> authenticated() 인증을 받아라
.and()
//로그인 관련
.formLogin() //인증 및 인가가 없는 상태로 요청에 접근 시 로그인 페이지를 보여주기 위함
.loginPage("/login") //customizing한 로그인 페이지로 이동
.defaultSuccessUrl("/index")
.failureUrl("/loginFail")
.and()
//로그아웃 관련
.logout()
.invalidateHttpSession(true) //로그인 시 세션 데이터 삭제
.logoutSuccessUrl("/index")
.and()
.exceptionHandling().accessDeniedPage("/accessDenied");
return security.build();
}
3. 실제 DB와 security 연동
- 전제 조건(로그인과 로그아웃 기능은 우리가 만들지 않는다 -> security에서 기본 제공)
- security에서 제공하는 로그인 실행 코드 작성
- userDetailsService라는 인터페이스 제공
(구현할 클래스 하나 생성해야 함 -> UserDetailsServiceImpl을 우리가 만든다 )
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService{
이 인터페이스 안에 구현해야 하는 메소드 하나가 존재함
해당 메소드가 실행되면 로그인 기능을 수행한다.
- 이 메소드는 리턴 타입이 userDetails 타입이기 때문에
평소에 리턴받은 로그인 객체를 사용할 수 없다.
(평소 리턴받는 로그인 객체 MemberVO loginInfo)
그래서 userDetails 인터페이스를 구현하는 user라는 클래스를 제공한다.
이 user 클래스에 우리가 조회한 데이터를 전달하여 return할 수 있다.
UserDetails userDetails = User.withUsername("manager")
.password("{noop}manager123")
.roles("MANAGER")
.build()