본문 바로가기
공부/springboot

스프링부트: 시큐리티(1)

by 샤샤샤샤 2023. 2. 20.

시큐리티

인증과 인가를 쉽게 다룰수 있게 도와주는 스프링 디펜던시.

인증을 받고 권한을 부여하는 과정을 대신해준다. 덕분에 각종 공격 및 해킹에 대한 방어를 사용자가 일일이 구현하지 않아도 된다.

 

루트 매핑("/")이 자체적인 로그인 화면으로 변한다. 이후 어떤 url을 요청하건 간에 자체적인 로그인 화면만 나오게 되는데, 이때 id는 username, 비밀번호는 스프링부트를 실행할때 나오는 일련의 숫자가 된다.

만약 본인이 원하는 비밀번호와 아이디로 바꾸고 싶다면  apllication.property 를 통해 설정해줘야만 한다.

# security
# defallt username/password
spring.security.user.name=user    # id설정
spring.security.user.password=1234    # pw설정

시큐리티 로그인 화면

시큐리티 로그인 화면에서 html소스를 확인해보면 아래와 같은 코드를 확인할수 있다.

csrf란 어떤 사람이 사이트에 로그인 되어 있을때, 해커가 로그인된 계정 주인인것 마냥 사이트 서버에 요청을 보내 계정 주인에게 허락된 권한을 마음대로 휘두르는 것을 말한다.

이를 막기 위해 시큐리티는 일련의 문자열을 html안에 숨겨두는데, 이는 매번 서버를 실행할때마다 바뀌며, 일종의 인증키 역할을 수행하게 된다. 만약 서버로 POST, PUT, PATCH, DELETE의 요청을 날릴때 그림과 같은 문자열을 같이 날리지 않으면 서버는 사용자의 정당성을 의심해, 응답하지 않게 된다. 따라서 GET요청이 아니라면 요청을 날릴때 해당값을 같이 날려줘야 하거나, 아예 이 설정을 꺼버리면 된다. 보안에는 취약해지겠지만, 공부를 목적으로 하는데 일일이 처리해주기도 귀찮으니 지금은 잠시 꺼두자.

 

HttpSecurity 객체에 내장된 함수를 사용하면 csrf 보안 설정을 무력화시킬수 있다.

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

	@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
 	}
 };

스프링 시큐리티는 기본적으로 누구에게 어느정도 수준의 권한을 줄것인가, 어느 정도의 접근을 허락할 것인가를 설정하는 디펜던시다. 따라서 @EnableWebSecurity 어노테이션을 통해 웹 보안을 위한 코드 접근을 허락해야 한다. 이 어노테이션 내부에는 기본적으로 @Configuration이 내장되어 있기에 따로 쓰지 않아도 되지만, @Configuration을 통한 커스텀이 필요한 상황이 있을수도 있기에 따로 썼다.

 

 

경로 제한

@Configuration
@EnableWebSecurity //웹보안 활성화를위한 annotation
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests() // 요청에 대한 보안설정을 시작
                .antMatchers("/**").permitAll(); //루트경로 아래 모든 요청을 허가한다 
                                //ant style matching,
                                // 예)"/*" : 루트/밑의 모든 파일과 폴더 
                                // 예)"/**" : 루트/밑의 모든 파일과 서브폴더와 서브파일들
                                // 예)"/member/**" : member폴더 밑의 모든 파일/서브폴더
    }
}

어떤 사이트에 접속했을때, 메인 사이트도 안나오고 무턱대고 로그인 화면이 나오면 매우 당황스러울 것이다. 스프링 시큐리티도 이점을 알고 특정 화면에 대해서는 접근을 허락할수 있게 .authorizeRequests() 라는 함수를 제공한다.   .antMatchers() 는 하위 경로를 선택할수 있게 해주는데, 예를 들어 위의 코드처럼 (" /** ") 로 설정하면 (" / ") 로 시작하는 모든 디랙토리와 파일을 의미한다.

* 0개 이상의 문자와 매칭 (matches zero or more characters)
** 0개 이상의 디렉토리와 파일 매칭 (matches all files/directories)
? 1개의 문자와 매칭 (matches single character)
{spring:[a-z]+} 정규문법 [a-z]+를 'spring'이라는 path variable과 매칭
(
matches the regexp [a-z]+ as a path variable named "spring")

 

종종 나오는 표현이니 숙지하자.

.permitAll() 은 이름에서 알 수 있다시피 모든 요청을 허락하는 함수다. 즉, 인가받지 않은 사용자라고 할지라도 (" / " ) 아래 모든 요청이 가능하도록 설정하는 것이다.

반대로 모든 요청에 대해 인증을 요구할수도 있다.

package com.study.springboot;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()// 요청에 의한 인증 시작
                .anyRequest().authenticated(); //어떤 요청에도 인증을 한다.
    }
}

위와 같이 설정을 하면 아래와 같은 화면을 볼 수 있다.

여기서 403에러를 볼수 있는데, 이는 사용자가 권한이 없다는  것을 의미한다. 

 

 

만약 특정 권한이나 역할을 가진 사용자에게만 허용하고 싶다면, .hasRole() 또는 .hasAuthrity() 를 사용해 설정하면 된다.

http
		.authorizeRequests() 
		.antMatchers("/admin/**").hasAnyRole("ADMIN") //ADMIN 역할을 가진 사용자에게만
    .antMatchers("/manage").hasAuthority("ROLE_ADMIN") //ADMIN 권한을 가진 사용자에게만
    .antMatchers("/order/**").hasAnyRole("USER"); //USER 역할을 가진 사용자에게만

 

 

 

 


@Configuration
@EnableWebSecurity //웹보안 활성화를위한 annotation
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //http.csrf().disable();
        http
                .authorizeRequests() // 요청에 대한 보안설정을 시작
                //루트밑의 모든 경로에 모든 요청을 허가한다.
                .antMatchers("/").permitAll()
                .anyRequest().authenticated() //어떤 요청에도 인증을 한다.
            .and()
                .formLogin() //로그인 인증에 대한 설정을 시작
                .loginPage("/loginForm") //로그인 페이지를 /loginForm URL로 하겠다.
                .loginProcessingUrl("/loginAction") //로그인 액션 URI를 지정한다.
                .successHandler( (request,response,authentication) -> {
                    System.out.println("로그인 성공했습니다.");
                    response.sendRedirect("/");
                })
                .failureUrl("/loginForm?error")
                .permitAll();//로그인 페이지를 모두에게 허용한다.
    }
}

.formLogin( ) : 로그인에 대한 설정을 선언한다.

.loginPage( ) : 로그인 페이지에 대한 요청을 설정한다. 즉, 해당 url의 페이지가 시큐리티 기본 로그인 페이지를 대체하게 된다.

.loginProcessingUrl() : 로그인 요청 URI 를 지정한다.

.successHandler() : 로그인 성공시 괄호안의 코드를 실행시킨다.

                                본래는 아래처럼 길게 적으나, 람다식의 타입추정을 이용해 코드를 줄일수 있다.

http.formLogin().successHandler(

     new AuthenticationSuccessHandler() {

   @Override
   public void onAuthenticationSuccess(HttpServletRequest request,
   					HttpServletResponse response, 
                                        Authentication authentication) throws IOException, 
                                        ServletException {
                                        
              System.out.println("로그인 성공했습니다.");
                response.sendRedirect("/index");
   }
);

(람다식 변환)

 

 

.successHandler( (request,response,authentication) -> {
                    System.out.println("로그인 성공했습니다.");
                    response.sendRedirect("/");
                })

.failureUrl() : 실패시 요청을 괄호안에 써넣을수 있다. error객체를 반환한다.

.permitAll() : 모두에게 해당 페이지(여기서는 로그인 페이지) 를 허용한다.

'공부 > springboot' 카테고리의 다른 글

좋은 객체지향이란?  (0) 2023.05.10
스프링이란?  (0) 2023.05.10
JPA 사용법(2) -- JPQL  (0) 2023.01.26
JPA 사용법(1) -- JPA 사용법  (0) 2023.01.26
개발용 임시 DB : H2DB  (0) 2023.01.25