- 보안 전문가들이 개발한 spring security를 사용함으로서 우리는 비즈니스 로직에만 집중할 수 있다.
- 최적화된 코드이기 때문에 최소한의 구성으로 웹 어플리케이션을 보호할 수 있다.
- 발전해가는 CSRF,CORS등의 취약점에 대비해 spring security팀은 항상 보안 코드를 업데이트 한다.
- 권한을 부여하여 접근을 제한할 수 있다.
- 다양한 방법으로 인증 및 인가를 구현할 수 있다. (JWT, OpenId등,, 추후에 배움)

- 모든 웹사이트는 http 프로토콜을 사용하여 소통한다.
- 그러나 우리의 자바코드는 그러한 http 요청을 이해할 수 없기에 중재자가 필요하다.
- 이 중개자를 우리는 서블릿 컨테이너라고 부른다.
- 서블릿의 컨테이너의 역할: http 요청 메세지를 자바 코드가 이해할 수 있는 서블릿 request object로 변환한다. 그리고 우리의 자바코드가 다시 response 메세지를 보낼 때 http 프로토콜로 감싸 호스트에게 보낸다.
- 그러나 서블릿은 너무 복잡해서 이러한 서블릿을 활용하는 spring이 등장했고, spring에 Controller, MVC path등을 정의하면 spring 내부에서 서블릿을 생성하도록 설계되어 있다.
- 필터란 서블릿의 특별한 종류 중 하나로서 클라이언트화 서블릿 사이에서 오고가는 요청을 가로채 특정 작업을 선행할 수 있게 해주는 거름망을 의미한다.
- 추후에 이 필터를 활용하여 권한을 확인하고 권한이 없다면 접근을 막는 등의 역할을 수행할 수 있다.

- post 요청으로 유저가 아이디와 비밀번호를 보낸다.
- 서블릿 컨테이너로 들어가기 전 Spring Security에 포함된 필터에 요청이 들어간다.(필터는 URL을 확인 후 누구나 접근할 수 있는 URL인지 아닌지를 판별한다.) 20개 정도의 필터가 존재하며, 필터는 각각의 고유한 역할을 지니고 있다.
- 필터에서 추출한 유저네임과 비밀번호를 가지고 Authentication 객체를 생성한다.
- Principal: Principal은 현재 사용자를 나타내는 객체다. 주로 사용자의 식별 정보(예: 사용자 이름, 이메일 등)를 포함한다.
- Credentials: Credentials는 사용자의 자격 증명(예: 비밀번호)을 나타낸다. 주로 암호화된 형태로 저장되며, 일반적으로 보안상의 이유로 실제 값을 포함하지 않는다.
- Authorities: Authorities는 사용자에게 부여된 권한을 나타내는 컬렉션이다. 각각의 권한은 문자열 혹은 객체로 표현될 수 있다. 이를 통해 애플리케이션에서 사용자의 권한을 확인하여 접근 제어를 할 수 있다.
- Authenticated Flag: 인증된 사용자인지 여부를 나타내는 플래그이다. 사용자가 인증되었으면 true를, 그렇지 않으면 false를 가진다.
현재 단계에서는로 객체를 전달하여 인증을 수행한다. - 만약 모든 provider에서 인증이 실패했을 경우 사용자에게 인증에 실패했다고 응답을 반환한다.
- UserDetails Manager/ Service 인터페이스를 통해 데이터베이스에 저장된 유저 정보를 가져와 엔드 포인트에서 전송된 정보를 비교하여 인증을 수행할수 있다.
- UserDetails Manager/Service를 이용하지 않고 Provider에서 바로 구현을 할 수도 있다.
- 데이터 베이스에 저장된 비밀번호는 Password Encoder를 활용하여 암호화하여 저장해야 하고 불러올 때도 Password Encoder를 활용하여 해싱해야 한다.
- 인증에 성공했다면 응답은 다시 필터로 돌아가게 된다.
- 필터에 돌아간 응답은 Security Context에 저장되게 되며 다음과 같은 내용을 포함한다.
- 인증이 성공적이었는지 아닌지.
- 세션 ID가 무엇인지
- 나중에 다시 로그인을 시도하면 Security Context에 저장된 내용을 바탕으로 재 로그인을 요청하지 않게 된다.
- 인증 권한을 관리하고, 로그인 페이지를 만들며 HDT 포지션 내부에 인증 정보를 저장하는 것을 도와주는 여러가지 필터가 존재한다.
- 엔드 유저가 접근하고자 하는 URL에 접근을 제한하는 역할을 한다.
- 공개된 URL이라면 자격증명 없이 바로 표시될 것이고, 그렇지 않다면 다음 필터로 보낸다.
- Do Filter는 클래스가 아니라 메소드이다. 클래스 내부에 정의되어 해당 클래스의 역할을 수행한 후 다음 필터를 호출하는 역할을 맡고 있다.
- 보안 페이지에 접속하려 하면 로그인 화면을 띄워주는 역할을 맡고있다. 밑에 코드를 보면 로그인 페이지 코드가 포함된 것을 확인할 수 있다.

- 유저가 자신의 아이디와 비밀번호를 입력하면 실행된다.
- attemptAutentication 이라는 메소드가 있다
- 이 메소드 내부엔 수신하는 http 요청으로부터 아이디와 비밀번호를 추출하는 로직이 짜여져있다. 추출한 정보를 바탕으로 UsernamePasswordAuthentication Token객체를 생성한다.
- UsernamePasswordAuthentication Token 클래스는 AbstractAuthentication Token을 상속하며 이것은 Authentication 인터페이스를 implements 한다.
- 따라서 UsernamePasswordAuthenticationToken은 Authentication 인터페이스의 실제 구현체라고 할 수 있다.
- 이 UsernamePasswordAuthenticationToken을 AuthenticationManager라는 인터페이스 내부의 authenticate메소드에 인자로 집어넣어 메소드를 호출한다.
- AuthenticationManager도 인터페이스 이므로 이를 구현한 클래스가 필요하다 그것은 ProviderManager클래스 이고 이 ProviderManager는 반복문을 돌리며 모든 가능한 AuthenticationProvider를 수행한다. 만약 인증에 성공한 AuthenticationProvider가 하나라도 나온다면 반복문은 즉시 중단되며 성공한 인증값을 반환하게된다.

- 즉 모든 인증 로직은 Authentication Provider에 구현되어 있따는 것이며 우리는 이 Authentication Provider를 구현해야할 것이다.
- 이 메소드 내부엔 수신하는 http 요청으로부터 아이디와 비밀번호를 추출하는 로직이 짜여져있다. 추출한 정보를 바탕으로 UsernamePasswordAuthentication Token객체를 생성한다.
- 다음은 실제 Authentication Provider의 예시이다.

- 내부 코드에 user가 null이라면 retrieveUser 메소드를 통해 UserDetatils객체를 가져오는 것을 볼 수 있는데, retireveUser 메소드는 UserDetailsService를 통해 유저 정보를 받아오는 걸 알 수 있다. 위의 흐름도에서 봤던것과 동일한 흐름이다.

- UserDetailsService는 정보를 어떻게 불러오느냐? 하면 UserDetailsService 내부에는 loadUserByUsername이라는 메소드가 정의되어 있는데 이 메소드에서 보통 jpaRepository의 findByUsername 메소드를 통해 User 객체를 찾아서 반환한다고 한다.
- 그렇게 반환된 User 객체를 additionalAuthenticationChecks 메소드에 넘기는데 이 메소드는 passwordEncoder를 활용하여 데이터베이스 내부에 저장된 비밀번호와 입력받은 비밀번호가 일치한지 확인하는 역할을 수행한다.
- 일치하는지 여부가 다시 Authentication Provider에게 반환되고 나면 이는 Spring Security 프레임워크에 전달되며 성공이 전달됐다면 URL의 접근이 허용될 것이다.
- REST 요청이 들어온다.
- Authorization 필터 실행(보안 URL인지 아닌지 확인)
- DefaultLoginPageGenerating 필터 실행 (로그인 페이지를 만든다)
- 아이디 비밀번호 입력
- UsernamePasswordAuthentication 필터 실행 (사용자에게 입력받은 아이디와 비밀번호를 바탕으로 UsernamePAsswordAuthenticationToken타입 객체를 생성한다.)
- 이후 Authentication 의 구현체인 Provider Manager 내부의 Authenticate 메소드를 호출한다. (인자는 UsernamePasswordAuthentication)
- 내부에서 모든 가능한 Authentication Provider 객체를 실행한다.
- retireveUser 메소드가 실행되고, UserDetatilsManager 내부에 구현된 LoaduserByUSername 메소드가 호출된다.
- 사용자에게 입력받은 아이디를 바탕으로 동일한 아이디가 있는지 데이터베이스에서 findByUsername 메소드로 찾아내고 해당 객체를 반환한다.
- Authentication Provider에 반환된 객체는 additionalAuthenticationChecks 메소드에 들어가고 비밀번호를 passwordEncoder를 통해 해독한뒤 서로 일치하는지를 확인한 후에 일치 여부가 프레임워크로 반환된다.
- Security Context에 인증 정보가 저장되며 자격증명이 자동으로 이뤄지게 된다.
- 로그인을 수행하면 백엔드에서 세션 아이디를 쿠키형식으로 브라우저에 전달해준다.
- 사용자의 컴퓨터 메모리에 쿠키정보가 저장되며 서버에 어떠한 요청을 할 때마다 이 쿠키가 http 요청의 헤더에 붙어서 서버로 전달된다.
- 서버는 쿠키 정보를 바탕으로 해당 유저의 요청을 처리한다.
본 게시글은 Spring Security 6 초보에서 마스터 되기 최신강의! (JWT , OAUTH2 포함) 을 공부한 후 정리한 글 입니다.
'spring > spring security' 카테고리의 다른 글
| Spring Security 기본 개념 공부 6. (권한 부여와 인증 방법) (0) | 2024.05.26 |
|---|---|
| Spring Security 기본 개념공부 5. (Cors, Csrf란?) (3) | 2024.04.07 |
| Spring Security 기본개념 공부 4. (0) | 2024.03.30 |
| Spring Security 기본개념 공부 3. (0) | 2024.03.24 |
| Spring Security의 기본개념 공부 2. (0) | 2024.03.24 |