Spring Boot

[Spring Security] 기초 1 (configuration)

머리방울 2022. 9. 22. 20:17

 

<순서>

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()