본문 바로가기

spring/security

[Spring] UsernamePasswordAuthenticationFilter 를 통한 폼 로그인 하기

로그인 구현하기

UsernamePasswordAuthenticationFilter 는 폼 양식을 통한 로그인 처리를 시도할 때, 최소한의 개발로 로그인 처리를 쉽게 처리할 수 있게 도와준다.

 

폼 로그인을 구현하기 위해서 폼의 액션과 메서드 POST 방식 그리고 인풋 name이 username, password이어야 정상적으로 동작하기에 이를 주의하자.

 

구현을 위한 절차는 이렇다.

1. UserDetailsService  구현하기

 

요청한 로그인 유저이름을 통해서 db에 유저 정보를 조회하여 UserDetails 객체에 담아서 반환하도록 구현해야한다.

2. UserDetails 구현하기

 

UserDetails 인터페이스에 따른 역할에 맞게 구현해주면 된다.  메서드 이름을 보면 어떤 것을 구현할지 명확해서 이해하기가 쉬웠다.

+) hasRole()이나 @Secured를 이용한 규칙, 권한 제한을 하는 경우는 디폴트로 "ROLE_" prefix가 사용됨으로 getAuthorities()를 호출할 때 이점을 고려하여 권한을 부여해야한다.

 

3. WebSecurityCustomizer 구현하기 API 시큐리티 설정하기

 

시큐리티에 로그인 설정을 해줘야 구현한 것을 써먹을 수 있다.

다른 블로그를 보면 WebSecurityConfigurerAdapter를 구현한 시큐리티 설정 클래스를 만들어서 configure(WebSecurity web) 메서드를 오버라이드하여 설정을 하는데 이방법은 Deprecated 되어서 HttpSecurity 객체를 주입받고 SecurityFilterChain을 설정해서 주입해야한다.

스프링 시큐리티 버전이 높아짐에 따라서 WebSecurityCustomizer은 Deprecated  되었다. 이제는 그냥 example 메서드를 그냥 사용해서 SecurityFilterChain을 빈으로 등록하는 방식으로 좀 더 간결하게 변경되었다. url 지정하는 방식도 람다를 활용하도록 변경되었다. 

 

+) csrf().disable() 설정을 해야 동작한다.

 

4. login 폼 페이지 만들기

 

시큐리티 규약에 맞게 앞서 말한대로 폼 페이지를 구축한다.

5. 완성 ~~~!

 

폼 로그인 구현 완성~~!


로그인 동작 방식 요약

시큐리티에 새로운 인증 필터를 생성하여 커스텀하기 위해서는 인증필터가 어떻게 인증을 책임지는지를 알아야할 필요가 있다. 

추상적인 메서드로 생각하면 이해하기 힘드니까 폼로그인 필터의 동작을 살펴보면서 어떻게 인증이 진행이 되는지를 이해해보자.

UsernamePasswordAuthenticationFilter 동작 방식

1. UsernamePasswordAuthenticationFilter  역할

  • HttpServletRequest 의 getParameter("key") 함수를 통한 로그인 정보 조회
    • key의 디폴트 값은 "username", "password", 커스텀 가능
    • key 값에 의존성을 가짐
  • 유저 이름과 비밀번호를 이용한 로그인 처리
  • AuthenticationFilter는 입력 받은 요청으로 부터 인증 정보를 추출하고 Provider에서 인증 책임을 넘기고 그 결과에 따라 분기를 수행하는 역할.

2. UsernamePasswordAuthenticationFilter 동작 흐름

  • 1. doFilter() 메서드 실행
  • 2. attemptAuthentication()  메서드 실행 : 유저 이름과 비밀번호를 이용한 인증 토큰 생성 후 DaoAuthenticationProvider 호출
    • Provider 호출은 AuthenticationProviderManager에 위임하여 처리
  • 3-1 성공 : successfulAuthentication() 메서드 실행 : 성공시 후 처리 핸들러 실행
  • 3-2 실패 : unsuccessfulAuthentication() 메서드 실행 : 실패시 후 처리 핸들러 실행

 

DaoAuthenticationProvider 동작 방식

1. DaoAuthenticationProvider 역할

  • 로그인 정보 확인
    • 정합성 확인 대상 : username, password
    • username을 통한 로그인 유저 정보 조회로 확인
    • 조회 정보와 입력정보 비교로 password 확인
    • 의존성
      • username 확인시 UserDetailsService 인터페이스를 구현한 빈이 필요
        • loadByUsername() 메서드로 로그인 정보 조회시 필요하기 때문이다.
      • password 확인시 UserDetails 인터페이스를 구현한 구현 클래스가 필요
        • getPassword() 메서드를 통한 비밀번호 조회시 필요하기 때문이다.
    • Provider는 입력 정보와 조회 정보를 비교하여 인증 여부를 판단하는 역할

2. DaoAuthenticationProvider 동작 흐름

  • 1. retrieveuser() 호출 : 로그인 username으로 로그인 유저의 정보를 조회
  • 2. addtionalAuthenticationChecks() 호출 : 입력 받은 로그인 비밀번호와 조회한 유저의 비밀번호 정보가 일치하는지를 확인
  • 3. 성공시 : createSuccessAuthentication 호출 : 인증 처리된 Authentication객체를 생성 후 반환한다.

 

디버깅하여 분석한 것을 보고 싶다면 다음 블로그를 참고하거나 직접 디버깅을 해보는 것을 추천한다.

 

Spring Security UsernamePasswordAuthenticationFilter

UsernamePasswordAuthenticationFilter는 Spring Security에서 formLogin을 할 때 사용할 수 있는 Filter 입니다.UsernamePasswordAuthenticationFilter 핵심 내용UsernamePasswordA

velog.io

 

추가 고려사항

  • 비밀번호 암호화 설정시 해독기 설정
    • PasswordEncoder 인터페이스 구현한 해독기 클래스를 빈으로 등록하면 자동으로 해독 처리함.
    • db에 비밀번호를 저장하기 전 암호화가 된 상태면 해독을 해야하는 과정이 필요하다. 이것도 고려해서 시큐리티는 해독하는 과정 역시 구현되어 있다.
  • 권한 설정
    • 경로에 따른 접근 권한을 열어줘야 로그인을 할 수 있음.

 

한계점

 

시큐리티를 통해서 간편하고 수준있는 로그인 처리가 가능하다. 하지만 MSA를 구현한 서비스라면 한계점이 보인다.

시큐리티 세션에 의존적이라는 단점이 있다. 왜냐하면 시큐리티에서 사용자 로그인을 처리한 이후에 인가 과정에서는 세션 아이디를 통해서 사용자의 인증 객체를 조회하고 이를 이용해서 인가과정이 진행되기 때문이다. 이를 해결하기 위해서는 인가 과정에서 시큐리티 세션에 의존적인 로직을 커스텀해서 다른 식으로 해결하는 방법이 필요하다.

 

해결법

해결 방법은 두가지 정도로 생각할 수 있을 것 같다.

하나는 인증 어플리케이션을 분리하여 서비스를 하는 것이다. 인증 서버를 분리하여 다른 서버에서는 인증서버로 인증, 인가 요청 API를 호출함으로써 해결할 수 있을 것 같다.

다른 하나는 세션 저장소를 인메모리 데이터 베이스로 변경하는 것이다. 

 

이를 위해서는 시큐리티에서 인증 객체가 어느 과정에서 저장되고 인가 과정에서 언제 세션 저장소에 접근하는지를 알아야 커스텀을 할 수 있을 것 같다.

 

다음으로는 그것을 알아보자.

 

[Spring security] Redis를 이용한 글로벌 세션 스토리지

시작글 Spring security는 Authentication 인증 객체를 세션에 보관하여 사용하는 것이 디폴트이다. 하지만 세션은 어플리케이션에 종속적이기 때문에 서비스를 확장하는 경우에 서버가 분산된다면 세

note-ydg.tistory.com