일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 자바
- 깃
- 스프링
- 개발
- 운영체제
- 컴퓨터공학
- 컴퓨터과학
- 깃허브
- 공채
- 신입
- Effective Java
- java
- 우리카드
- IT
- CS
- 스터디
- 디지털
- Public
- github
- 메모리
- 정보처리기사
- 세마포어
- 이펙티브 자바
- 프로그래밍
- spring
- package-private
- 알고리즘
- 뮤텍스
- OS
- 신입사원
- Today
- Total
주니어 개발자 성장기
3. Spring Security - 인증 과정 이해하기 (1) 본문
Overview
이번에는 Spring Security에서 일반 로그인(Form Login)을 구현하고, 로그인 요청이 필터를 거치며 어떻게 인증이 되는 지 그 과정을 정리하려고 한다.
- Why Form Login?
- Spring Security 로그인 과정 분석 (Feat. 템플릿 메서드 패턴)
- 유저 정보는 어떻게 불러오는가?
Why Form Login?
Spring Security 에서는 로그인 방식으로 3가지를 지원한다.
Reading the Username & Password :: Spring Security
- 폼 로그인
- 일반적으로 쓰는 로그인의 형태로
- 대체로
POST
메서드와form-data
형식으로 아이디와 패스워드를 전송한다. - 도청의 위험성이 있기 때문에 반드시 SSL/TLS 계층과 함께 사용한다.
- 표준 사양이 존재하지 않는다.
- 최초 Spring Security 로그인 기능 사용시 Default 값이다.
- Basic 로그인
- 헤더에 ID와 비밀번호를 붙여서 보내는 방식으로 암호화가 되지 않아 도청의 위험성이 있다.
- Digest 로그인
- 도청 방지를 위해 MD5라는 알고리즘을 이용해 인증하는 방식
- MD5가 보안에 취약하다.
참조: 11. HTTP를 이용한 인증방식 - BASIC, DIGEST, SSL, FORM
그래서 폼 로그인을 도입 할만한 이유는?
- Spring Security 에서 기본으로 제공하는 방식이다.
- SSL 인증서만 잘 적용한다면 보안은 문제가 없다고 한다.
- 클라이언트에서 어떤 식으로 요청하면 되는 지 내가 잘알고 있다.
- 나는 SSL 인증서 발급받는 법을 알고 있다.
단점은?
- 실 서비스에서 아이디, 비밀번호 찾기 등을 따로 구현해야 한다.
- 비밀번호 관리, 보안에 힘써야 한다.
- 상기 사항 때문에 소셜 로그인을 도입 했을 때에 비해 기회비용이 크다.
Spring Security Form Login의 흐름
Client가 로그인 요청(POST
, URI: /login
을 하면, 여러 필터들을 거쳐서 UsernamePasswordAuthenticationFilter
에 도착하게 된다.
UsernamePasswordAuthenticationFilter
필터링을 시도하는 AbstractAuthenticationProcessingFilter.doFilter
메서드를 우선 살펴보자.
private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
if (!requiresAuthentication(request, response)) {
chain.doFilter(request, response);
return;
}
try {
Authentication authenticationResult = attemptAuthentication(request, response);
if (authenticationResult == null) {
// return immediately as subclass has indicated that it hasn't completed
return;
}
//...
successfulAuthentication(request, response, chain, authenticationResult);
//...
}
}
attemptAuthentication(request, response);
라는 추상 메서드를 호출하는 것을 볼 수 있다. (이것은 subclass에 위임하고 있다) 그리고 Authentication
라는 인스턴스를 반환한다. Authentication
이란 인증 정보를 담고 있는 인터페이스이며, 뒤쪽에서 AuthorizationFilter
를 거치며 요청의 인증
과 인가
를 결정한다. 편의상 인증 토큰
으로 명명하겠다. (그리고 인증이 끝나면 Security Context Holder에 저장된다.)
어쨌든, 다시 말하자면 인증의 세부 구현은 UsernamePasswordAuthenticationFilter
에 위임하는 템플릿 메서드 패턴으로 구현되어 있는 것이다. 그러면 인증의 세부 구현을 파악하기 위해
UsernamePasswordAuthenticationFilter.attemptAuthentication
을 살펴보자.
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
// (1 )postOnly == true AND HTTP method 가 POST가 아니면 예외
if (this.postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
// (2) username과 password를 request로부터 가져온다.
String username = obtainUsername(request);
username = (username != null) ? username.trim() : "";
String password = obtainPassword(request);
password = (password != null) ? password : "";
// (3) username과 password를 통해 인증되지 않은 인증 토큰 생성
UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(username,
password);
// Allow subclasses to set the "details" property
// (4) 인증 토큰에 request로 부터 Detail 정보를 가져온다.
setDetails(request, authRequest);
// (5) AuthenticationManager 객체에 인증을 위임한다.
return this.getAuthenticationManager().authenticate(authRequest);
}
- postOnly값은 디폴트로 true인데,
request
의 HTTP method가POST
가 아니라면 예외를 던진다.
- 그리고
request
로부터 username(사용자 ID)과 password를 가져온다.
- username과 password를 담은
UsernamePasswordAuthenticationToken
을 생성한다. 이인증 토큰
은Authentication
을 상속 받고 있으며 아직UnAuthenticated
(인증이 되지 않은 상태)이다.
request
로부터인증 토큰
에 들어갈 Details 필드를 가져온다. 어떻게 가져오는 지는authenticationDetailsSource
에 위임하고 있다. (전략 패턴)
- 필드에 있는
AuthenticationManager
에인증 토큰
의 인증을 위임한다. 이 역시도 전략 패턴으로 구성되어 있다.
위에서 가장 중요한 부분은 (5)번이다. AuthenticationManager
는 인증의 세부사항을 구현하는 인터페이스다. 인증 토큰
을 전달 받고 완전한(인증된) 인증 토큰
을 반환하는 책임을 가지고 있다.
ProviderManager
Spring Security에서는 AuthenticationManager
의 구현체로 ProviderManager
를 사용한다. ProviderManager
는 필드로 List<AuthenticationProvider>
를 갖고 있으며 반복문을 돌면서 해당 인증 토큰
을 AuthenticationProvider
가 지원하는 지 찾은 다음, 인증을 시도한다.
ProviderManager
이후의 자세한 내용은 다음 포스팅에 올리도록 하겠다.
'예제 > Session' 카테고리의 다른 글
4. Spring Security - 인증 과정 이해하기 (2) (0) | 2023.06.15 |
---|---|
2. Spring Session (0) | 2023.05.18 |
1. 설정 (0) | 2023.05.16 |
0. 프로젝트 목적 (0) | 2023.05.16 |