Backend

[SpringBoot] Spring Securtiy (1)

76 2024. 6. 11. 23:51
728x90

해당 포스트는 유튜브 '개발자 유미' 님의 스프링 시큐리티 강의 영상을 바탕으로 작성하였습니다.

https://www.youtube.com/playlist?list=PLJkjrxxiBSFCKD9TRKDYn7IE96K2u3C3U

 

스프링 시큐리티

스프링 시큐리티 : Spring Security

www.youtube.com

 

목표

스프링 시큐리티 프레임워크를 활용하여 인증(Authentication)과 인가(Authorization)을 구현한다.

 

구현 내용

1. 인증 : 로그인을 통한 사용자 인가

2. 인가 : 사용자의 권한에 따른 경로별 접근 허용/비허용

3. 회원가입

 

시큐리티 동작 원리

스프링 부트 어플리케이션은 서블릿 컨테이너(Servlet Container) 내부에 위치한다. 사용자의 요청이 도달하게 되면 서블릿 컨테이너 내부의 필터들(Servlet Filters)를 거친후에 스프링 부트 컨트롤러에 요청이 도착하게된다.

Spring Security Config 라는 구성파일을 만들어두면, 해당 구성파일에 의해 Spring Security Filter라는 Servlet Filter가 생성되고 해당 필터가 사용자의 요청을 가로채게 된다. 이후 사용자의 인증(사용자가 실제로 해당 서비스의 사용자인지 확인 => 데이터베이스에 존재하는 회원인지 확인)과 인가(사용자가 특정 요청을 할 수 있는 권한이 있는지 확인)를 거치게 된다.

 

버전

- Spring Boot 3.3.0

- Security 6.1.5

- Spring Data JPA - MySQL

- mustache

- IntellJ Ultimate

 

1. 프로젝트 생성

의존성

필수 의존성

- Spring Web

- Lombok

- Thymleaf

- Spring Security

- Spring Data JPA

- MySQL Driver

 

프로젝트 생성

 

 

버전 선택(3.3.0) 및 의존성 6개 추가 후 프로젝트 생성

 

데이터베이스 설정을 뒤로 미루기 위해 MySQL과 Spring Data JPA 주석 처리 후 재빌드

 

2.  Config 파일 작성

별도의 설정을 하지 않으면 스프링 시큐리티에 의해 모든 사용자 요청에 대해서 Spring Security Filter Chain의 인증과 인가 과정을 수행하게 된다.

 

아래와 같이 MainController.java와 resource - template 경로에 main.html 파일을 작성한다.

 

서버를 실행시키게 되면 스프링 시큐리티에 의해 인증(사용자가 실제로 존재하는 사용자인지 확인)절차를 수행하게 된다.

인증을 위해서는 기본 사용자가 필요한데, 스프링을 실행시킨뒤 로그를 살펴보면 기본 사용자명 user에 대한 비밀번호를 생성하여 제공한다. 

security password : 0fe01f78-e22f-431c-94cf-df32768e62bd 이 비밀번호에 해당한다.

 

localhost:8080/ 를 통해 루트 디렉토리에 접근하게 되면, main페이지로 이동하게 되는데 스프링 시큐리티에 의해 해당 요청을 스프링 시큐리티 필터가 가로채게 되고, 로그인 페이지로 넘어가게 되어 인증절차를 수행하게 된다.

 

여기서 Username : user, Password : 0fe01f78-e22f-431c-94cf-df32768e62bd (스프링에 의해 생성된 비밀번호)를 작성하고 Sign in을 누르게 되면 인증(Authentication)절차를 통과하여 루트 디렉토리로 넘어가게 된다.

 

 

Config 파일 작성

디폴트 설정은 위와 같이 모든 경로에 대해 인증과 인가 작업을 수행하도록 되어있지만 특정 요청(특정 페이지로의 접근,등)에 대해서만 인증 및 인가 작업을 수행하도록 시키고 싶다.

이를 위해 Spring Security Filter Chain을 생성하는 구성파일을 작성해주어야 한다.

 

config 디렉토리를 만들고 SecurityConfig.java 파일을 작성한다.

 

스프링 시큐리티의 구성파일로 활성화 시키기 위해, @EnableWebSecurity 를 붙여주고, 구성 클래스로 생성하기 위해 @Configuration을 작성한다.

 

authorizeHttpRequests는 사용자 요청에 대한 인가를 설정한다. 람다식의 형식으로 작성하게 되며 requestMatchers를 통해 사용자의 요청 경로에 따라 인증,인가 조건을 설정한다.

 

- requestMatchers() : 사용자의 요청에 따른 인증,인가 조건을 설정한다.

- permitAll() : 모든 사용자에 대해 접근을 허용한다.  위 예제에선, 루트 디렉토리와 로그인 페이지는 인증(Authentication)을 수행하지 않은 사용자도 접근을 허용하도록 하였다.

- hasRole(ROLE) : 인증 절차를 마친 사용자에 대해 ROLE 권한을 가진 사용자의 접근을 허용한다.

- hasAnyRole(ROLE1,ROLE2 ..) : ROLE1, ROLE2 .. 중 하나의 권한이라도 가진 사용자의 접근을 허용한다.

- anyRequest() : requestMatchers()를 통해 설정하지 않은 모든 요청 경로에 대해 설정한다.

- authenticated() : 인증된 사용자라면 모두 허용한다.

 

위와 같이 구성파일을 작성한 뒤 서버를 다시 실행시켜보면 메인페이지(localhost:8080/)로 접근시 우리가 정의한 Security Filter Chai의 새로운 인가 규칙에 따라 루트 디렉토리에 대해 permitAll()이 수행되어 더 이상 인증(로그인)을 하지 않고도 접근이 가능해진다.

 

 

그렇다면 localhost:8080/admin 으로 접근시 어떤 일이 일어나는지 확인해보자.

우선 아직 해당 경로에 대한 api가 작성되지 않았으므로 MainController 때처럼 AdminController를 작성하고, admin.html 파일을 작성한다.

 

서버를 다시 실행시킨 후 admin 페이지로 접근하게 되면 아래와 같이 '액세스가 거부됨' 이라는 페이지가 뜨는 것을 확인 할 수 있다

 

액세스가 거부되는 것은 요청한 사용자가 인증(Authentication)을 수행하지 않았으며 그에 따라 권한도 확인 할 수 없기 때문이다.

 

다음 포스트에서는 이처럼 사용자가 권한이 필요한 페이지에 접근시 로그인 페이지를 띄워 인증 절차를 수행하고 인증된 사용자의 권한을 확인하여 접근을 허용할지 비허용할지 결정하는 방법에 대해 작성하도록 하겠다.