들어가기 앞서
본 글은 스프링 시큐리티 서적인 Spring Security in Action을 읽고 책 속에 나와 있는 예제를 공부하며 얻은 지식을 바탕으로 적은 글입니다.
오늘의 목표
- 스프링 시큐리티가 무엇인지 이해한다.
- 첫 스프링 시큐리티 프로젝트를 생성해본다.
- 스프링 시큐리티가 제공하는 기본 인증 과정을 살펴본다.
시리즈의 모든 글
[스프링 시큐리티 무작정 따라하기] 1. Hello Spring Security
[스프링 시큐리티 무작정 따라하기] 2. 회원 관리하기
[스프링 시큐리티 무작정 따라하기] 3. 인증 구현하기
[스프링 시큐리티 무작정 따라하기] 4. 권한 설정하고 인가(authorization) 처리 하기
[스프링 시큐리티 무작정 따라하기] 5. 필터(Filter) 이해하기
1. 스프링 시큐리티란?
스프링 시큐리티는 스프링 기반 애플리케이션의 보안을 담당하는 스프링 하위 프레임워크이다. 주로 인증과 인가를 담당하며 서블릿 필터가 작동되는 서버의 앞쪽 끝단(웹 클라이언트로부터의 요청은 필터 -> 인터셉터 -> 디스패처 서블릿 -> 컨트롤러의 순으로 들어 온다. 인터셉터는 엄밀히 말해 디스패처 서블릿 전후 총 3번에 걸쳐 동작하지만 편의상 저렇게 적었다.)에서 동작하기 때문에 클라이언트의 요청을 검증하는 보안 전문 서블릿 필터 구성체라고 봐도 무방하다. 스프링 시큐리티는 스프링을 배우는 사람들에게 '배우기 가장 어렵다'는 워딩으로 악명이 높지만 보안과 관련해 상당히 많은 옵션을 제공해주기 때문에 개발자가 놓치지 쉬운, 혹은 구현하기 어려운 보안 로직을 손쉽게 구성할 수 있다는 장점을 가지고 있다.
2. 스프링 시큐리티 프로젝트 생성
프로젝트를 위한 IDE로 Intellij를 사용하는 것을 가정합니다. Intellij를 사용하지 않는 분은 아래의 링크에서 커뮤니티 버전을 다운로드 받아 프로젝트를 진행하거나, Eclipse와 같이 사용하시기 편한 IDE를 사용해 주세요. (Intellij 얼티밋 버전은 유료입니다. 커뮤니티 버전을 다운받아 주세요.)
https://www.jetbrains.com/ko-kr/idea/download/#section=windows
아래의 링크로 들어가 스프링 부트 프로젝트를 생성한다. 스프링 부트는 환경 설정을 개발자가 직접 할 필요가 없게끔 스프링 프로젝트의 초기 환경 설정을 자동화 해 빠르고 간편하게 스프링 프로젝트를 실행할 수 있도록 도와주는 프레임워크이다. (https://start.spring.io/)
- Project - Gradle Project
- Language - Java
- Spring Boot - 괄호 안에 SNAPSHOT, M3가 적혀 있지 않은 가장 최신 버전 (위의 경우 2.7.1)
- Project Metadata
- Group - security [자유롭게 설정 가능]
- Artifact - study [자유롭게 설정 가능]
- Description - 프로젝트에 대한 설명을 자유롭게 기술한다.
- Name과 Package name은 자동으로 생성
- Packaging - Jar
- Java - 11 (자유롭게 설정 가능하나 필자는 11을 선택해주었다.)
- Dependencies - ADD 버튼을 누른 후 Spring Web과 Spring Security를 선택해준다.
설정이 완료되었다면 아래의 GENERATE 버튼을 클릭한다. 잠시 기다리면 스프링부트 프로젝트가 다운로드 되어진다. 자 이제 다운로드 된 파일의 압축을 푼 후 intellij를 통해 프로젝트를 열어준다.
프로젝트를 원하시는 폴더에 풀어주신 후, 인텔리제이 초기 화면에서 open 버튼을 눌러주세요. 이후 압축이 풀린 새로운 프로젝트 폴더 내 build.gradle 파일을 선택하신 후 OK를 누르시면 됩니다. 이후 Open as Project를 눌러주세요! 이후 경고 메세지가 나온다면 Trust Project를 눌러주시면 됩니다.
프로젝트를 열면, 프로젝트 실행에 필요한 의존성(Dependencies)를 다운받는 작업이 자동으로 진행된다. IDE의 오른쪽 하단, 다운로드 진행 상황을 확인할 수 있습니다. 의존성을 모두 다운 받았다면, 아래 보이는 삼각형 버튼을 클릭해 프로젝트를 실행한다. 스프링부트는 스프링과 달리 톰캣을 내장하고 있기 때문에 별도로 톰캣을 설정해주지 않아도 됩니다.
IDE의 콘솔에 아래와 같은 메세지가 출력되었다면, 프로젝트 생성 성공.
콘솔창에 캡처와 같이 두 가지의 메세지가 출력되었는지 확인합니다.
- Using generated security password: 5e753559-055c-4034-a1c8-7fb149cf3dd5
- Tomcat started on port(s): 8080 (http) with context path ''
3. 스프링 시큐리티의 기본 인증
구동 중인 애플리케이션을 잠시 중단한 후, src > main > java > security > study 패키지 내에 controller라는 패키지를 생성한다. 그리고 내부에 HelloController.java 파일을 생성한다. 스프링 부트 생성 설정에서 Group과 Artifact를 이름을 다르게 했다면 security와 study 패키지 이름이 다르게 나올 것입니다. 이상이 있는 것은 아니니 가장 xxxApplication.java가 위치한 패키지에 controller 패키지를 생성한 후 진행하시면 됩니다.
위의 캡처처럼 HelloController가 생성 되었다면 HelloController 내부에 다음과 같은 코드를 작성한다.
package security.study.controller; // 경우에 따라 package 경로가 다를 수 있으니 자신에게 맞는 경로를 적어주자.
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello")
public String helloSecurity() {
return "Hello Security!!";
}
}
다시 (세모 버튼을 눌러) 애플리케이션을 구동한 후 아래의 두 가지 옵션 중 하나를 실습한다.
옵션 1) 브라우저 창에서 실습하기
웹 브라우저를 켜고 주소창에 localhost:8080을 입력한다. 엔터를 눌렀을 때, 로그인 페이지가 뜨고 localhost:8080/login으로 이동하였다면 성공이다.
아무런 동작을 취하지 않은 상태로 다시 주소창으로 돌아가 localhost:8080/hello를 입력해본다. 다시 로그인 창으로 돌아온다는 것을 확인할 수 있다.
로그인 창의 username란에 "user"라고 적은 후 애플리케이션을 구동했을 때 콘솔에 찍혔던 부분 중 "Using generated security password:" 뒷부분을 복사해 password란에 붙여넣기 한다. 로그인이 성공하고 다시 localhost:8080/hello를 입력한다. 아래의 캡처처럼 hello Security!!가 출력된다면 성공이다.
옵션 2) 터미널을 이용해 실습하기
운영체제에 맞는 터미널을 연 후 curl을 입력해본다. 만약 윈도우 기반의 운영체제를 사용하고 있다면(혹은 '알 수 없는 명령어다' 라는 메세지가 뜬다면) 아래 블로그에 적혀 있는 가이드를 통해 curl을 설치해주자.
https://kitae0522.tistory.com/entry/Windows-%EC%9C%88%EB%8F%84%EC%9A%B010%EC%97%90%EC%84%9C-curl-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95
curl을 사용할 수 있게 되었다면 터미널에 curl http://localhost:8080/hello 를 입력한다. 아래처럼 아무런 결과 없이 다음 콘솔 창으로 이동된다면 성공이다. (성공이라는 표현이 조금 이상하기는 하다만, 인증 과정에서 인증되지 않는 사용자를 검출해 스프링 시큐리티가 컨트롤러로 요청을 넘기지 않은 것이니 '성공'이라고 표현했다.)
이번에는 다시 IDE 콘솔창에 있는 "Using generated security password:" 뒷부분을 복사해 터미널에 아래와 같은 명령어를 입력한다.
curl -u user:0717cc25-3d52-4350-a907-35910f44f070 http://localhost:8080/hello
# curl -u user(회원이름):[콘솔창에 있는 난수](비밀번호) http://localhost:8080/hello
아래처럼 결과값이 "Hello Security!!"로 나온다면 성공이다.
Q. 무엇을 한 것일까
우리는 사실 지금 스프링 시큐리티가 기본적으로 제공하는 인증 메커니즘을 실습한 것이다.
스프링 시큐리티는 개발자가 별도의 설정을 하지 않는다면 애플리케이션에 접근하는 모든 요청에 인증 작업을 수행한다. 아무런 인증 작업 없이, 즉 로그인을 하지 않은 상태로 /hello 경로로 입장을 하려고 했을 때, 스프링 시큐리티는 (로그인을 하지 않았으니) 인증된 사용자가 아님을 캐치하고 해당 경로로의 접근을 허용하지 않는다. 따라서 브라우저 창에서는 로그인 창으로 리다이렉트, curl에서는 빈 값을 결과값으로 받았던 것이다.
실습에서 사용한 username = user / password = [난수] 는 사실 스프링 시큐리티가 애플리케이션이 실행될 때 자동으로 생성했던 임의의 회원이었다. 이 임의의 회원은 우리가 애플리케이션을 실행했을 때, 스프링이 구동되는 프로세스의 메모리 상에 올라간다. 이 회원은 스프링 애플리케이션이 종료되고 다시 실행될 때마다 새로 생성되기 때문에 실제 사용하기에는 무리가 있지만, 지금처럼 간단하게 시큐리티의 기능을 테스트 하기에는 아주 적합하다.
즉, 우리가 앞서 실습을 통해 해본 것은, 스프링 시큐리티가 생성한 '인증'된 회원이 실제로 스프링 상에서 유효하게 작동한다는 점, 그리고 스프링 시큐리티는 인증되지 않는 회원에 대한 요청은 컨트롤러 단 이전에서 기각한다는 부분이었다. 이렇듯 스프링 시큐리티는 단순하게 의존성을 애플리케이션 내에 추가해주는 것만으로도 이미 인증, 인가와 관련된 기능을 제공한다는 것을 알 수 있었다.
그러나 이러한 시큐리티의 기본 설정은 앞서 설명한 부분처럼 실제 프로덕션 레벨에서 사용하기에는 무리가 있다. 첫 번째로 매번 애플리케이션을 구동할 때마다 회원 정보가 바뀌기 때문이고 두 번째로 회원 정보가 파일 시스템이나 데이터 베이스 시스템이 아닌 메모리 상에 저장되기 때문이다.
따라서 우리는 스프링 시큐리티의 설정을 일부 커스텀하여 우리에게 맞는 설정 정보를 반영할 필요가 있다. 그리고 우리는 이 시리즈를 지속하며 인증 작업을 하나하나 구체화 해 나갈 것이다.
다음 글에서는, 스프링 시큐리티의 인증이 어떠한 과정을 통해 진행되는지 간략하게 살펴본 후, 시큐리티 인증 과정에서 회원에 관련된 데이터를 저장하고 사용하는 각종 객체들에 대해 살펴볼 것이다. 구체적으로는 회원과 권한에 관한 정보를 기술하는 UserDetails, GrantedAuthority, 회원과 관련된 동작들을 제어하고 통제하는, 즉 회원을 직접적으로 '관리'하는 UserDetailsService, UserDetailsManager에 관해 살펴볼 것이다. 그리고 이를 통해 스프링이 기본적으로 제공해주는 회원이 아닌 개발자가 직접 생성한 회원을 메모리상에, 그리고 데이터베이스 시스템 상에 적재하여 활용하는 방법을 배워볼 것이다.
다음 글
'Spring Framework > 스프링 시큐리티' 카테고리의 다른 글
[스프링 시큐리티 무작정 따라하기] 3. 인증 구현하기 (2) | 2022.08.16 |
---|---|
[스프링 시큐리티 무작정 따라하기] 2. 회원 관리하기 (2) | 2022.07.31 |
[스프링 시큐리티 - 인증] 공식문서 번역하며 공부하기 - 서블릿 인증 아키텍처 (0) | 2022.01.11 |
[스프링 시큐리티 - 인증] 공식문서 번역하며 공부하기 - Authentication (0) | 2022.01.07 |
[스프링 시큐리티] 공식문서 번역하며 공부하기 - 아키텍처 (0) | 2022.01.05 |