스프링 시큐리티와 폼 로그인 인증처리 방식

Updated:     Updated:

Categories:

Tags: ,

게시판 프로젝트를 하던 도중, 인증처리에 대한 공부가 필요해 spring security를 공부하고 기록한다.

스프링 시큐리티에 대하여

스프링 시큐리티는 스프링 기반의 애플리케이션의 인증과 인가를 담당하는 스프링의 하위 프레임워크이다. 스프링 시큐리티가 제공하는 기능은 크게 인증과 인가이다.

  • 인증(Authenticate) : 보호된 리소스에 접근한 대상에 대해 누구인지를 확인하는 과정이다. 애플리케이션의 작업을 수행해도 되는 인증된 주체인지 확인하는 과정이 필요하다.

  • 인가(Authorize) : 인증 이후에 필요한 작업으로 해당 리소스에 대해 접근 가능한 권한을 가지고 있는지 확인하는 과정이다.

Principal 이라는 접근 주체라는 용어도 있는데, Principal은 보호된 리소스에 접근하는 대상이다.

스프링 시큐리티 특징

  • 스프링 시큐리티에서는 서블릿 필터와 이들로 구성된 filterChain으로 구성된 위임모델을 사용한다.
  • filter기반으로 동작하여 컨트롤러와 분리하여 개발할 수 있다.
  • 기본적으로 쿠키 세션방식으로 인증처리를 한다.
  • 인증 방식으로는 폼 로그인 방식과 httpbasic 로그인 방식을 제공한다.

인증 관리는 UsenamePasswordAuthenticationFilter 에서 수행되고, 접근 결정 관리는 FilterSecurityInterceptor 에서 수행된다.

사용자 정의 보안 기능 API

스프링 시큐리티에서는 인증 인가 API를 제공하여 이를 이용해 인증 인가를 처리할 수 있다.

인증 API

  • http.formLogin()
  • http.logout()
  • http.csrf()
  • http.httpBasic()
  • http.SessionManagement()
  • http.RememberMe()
  • http.ExceptionHandling()
  • http.addFilter()

인가 API

  • http.authorizeRequests().antMatchers(/admin)
  • http.authorizeRequests().hasRole(USER)
  • http.authorizeRequests().permitAll()
  • http.authorizeRequests().authenticated()
  • http.authorizeRequests().fullyAuthentication()
  • http.authorizeRequests().access(hasRole(USER))
  • http.authorizeRequests().denyAll()

폼 로그인 인증

  1. 클라이언트에서 서버에 GET 요청으로 home url에 자원접근을 요청
  2. 서버에서는 인증을 확인하고 인증이 안됬다면 로그인 페이지로 redirect
  3. 클라이언트는 form post방식으로 username과 password를 전달해 서버에 인증 요청
  4. 서버에서는 인증 확인 후 sessionId 생성후 세션에 저장하여 클라이언트에게 전달
  5. 클라이언트는 받아온 토큰으로 서버에 전달 후, 서버에서는 세션 확인 후 인증처리

security에서 폼 기반 인증처리 코드는 다음과 같다.

http
              .authorizeRequests()
              .anyRequest().authenticated() // 어떠한 요청에도 보안 검사
      .and()
              .formLogin()//Form 로그인 인증 방식
              .loginPage("/login.html")//사용자 정의 로그인 페이지
              .defaultSuccessUrl("/home")//로그인 성공 후 이동 페이지
              .failureUrl("/login.html?error=true")// 로그인 실패 후 이동 페이지
              .usernameParameter("username")//아이디 파라미터명 설정
              .passwordParameter("password")//패스워드 파라미터명 설정
              .loginProcessingUrl("/login")//로그인 Form Action Url
              .successHandler(loginSuccessHandler())//로그인 성공 후 핸들러 (해당 핸들러를 생성하여 핸들링 해준다.)
              .failureHandler(loginFailureHandler());//로그인 실패 후 핸들러 (해당 핸들러를 생성하여 핸들링 해준다.)
							.permitAll(); //사용자 정의 로그인 페이지 접근 권한 승인

폼 로그인 동작 방식

  1. UsernamePasswordAuthenticationFilter 요청이 들어오면 해당 필터를 거쳐 인증 처리를 시작한다.

  2. AntPathRequestmatcher(/login) 요청한 URL이 /login으로 시작하는지 확인 후 /login URL 이라면 다음 단계로 인증 처리 프로세스 진행 / login URL이 아니라면 chain.doFilter로 다음 필터로 넘긴다.

  3. Authentication 로그인 페이지에서 넘겨받은 username과 password를 Authentication에 저장하여 인증을 처리해주는 Manager에게 객체를 전달

  4. AuthenticationManager 인증 관리자로 인증에 대한 처리는 AuthenticationProvider에게 위임한다.

    • 인증에 성공한 경우 : Authentication 객체를 생성하여 User객체와 Authorities객체를 담아서 AuthenticationManager에게 반환한다.
  • 인증에 실패한 경우 : AuthenticationException 예외를 반환한다.
  1. AuthenticationManager는 Provider로부터 반환받은 인증객체(user + authorities) 를 SecurityContext객체에 저장한다.

  2. SecurityContext는 Session에도 저장되어 전역적으로 SecurityContext를 참조할 수 있다.

  3. 인증 성공 이후에는 SuccessHandler에서 인증 성공이후의 로직을 수행하게 된다.


로그아웃 동작 방식

  1. 클라이언트에서 /logout 리소스 요청
  2. 서버에서 세션무효화, 인증토큰 삭제, 쿠키정보 삭제후 원하는 페이지로 리다이렉트

로그아웃 필터역시 로그인 필터와 비슷한 방식으로 처리되는 것을 볼 수 있다.

  1. logout url에 대한 요청인지 matcher를 통해 확인한다.
  2. 맞다면 SecurityContext에서 인증객체를 꺼내온다.
  3. SecurityContextLogoutHandler에서 세션 무효화, 쿠키삭제, clearContext()를 수행하고, SecurityContext객체역시 삭제하고 인증객체도 null로 만든다.
  4. SimpleUrlLogoutSuccessHandler 를 통해 redirect를 시켜준다.
http
                .logout()//로그아웃 처리
                .logoutUrl("/logout")// 로그아웃 처리 URL
                .logoutSuccessUrl("/login")//로그아웃 성공 후 이동페이지
                .deleteCookies("JSESSIONID","remember-me")//로그아웃 후 쿠키 삭제
                .addLogoutHandler(new LogoutHandler() {
                    @Override
                    public void logout(HttpServletRequest request,
                    HttpServletResponse response, 
					Authentication authentication) {
                        HttpSession session = request.getSession();
                        session.invalidate();
                    }
                })//로그아웃 핸들러
                .logoutSuccessHandler(new LogoutSuccessHandler() {
                    @Override
                    public void onLogoutSuccess(
                    HttpServletRequest request, 
                    HttpServletResponse response, 
					Authentication authentication) throws IOException, ServletException {
                        response.sendRedirect("/login");
                    }
                })//로그아웃 성공 후 핸들러
                .deleteCookies("remember-me");//쿠키 삭제

rememberMe를 통해 인증 유지하기

세션이 만료되거나 웹 브라우저가 종료된 경우, 다시 인증요청을 해야하지만 rememberMe를 통해 인증을 유지할 수 있다.

rememberMe 쿠키에 대한 HTTP 요청을 확인한 후 토큰 기반 인증을 사용해 유효성을 검사하고 토큰이 검증되면 사용자는 인증처리된다.

sessionId 쿠키를 삭제하여 인증에 대한 정보가 사라지더라도, rememberMe 쿠키가 있다면, 해당 쿠키를 decoding하여 다음 로그인 상태를 유지할 수 있다.

http
    .rememberMe()//rememberMe기능 작동
    .rememberMeParameter("remember-me") //기본 파라미터명은 remember-me
    .tokenValiditySeconds(3600)//default는 14일
    .alwaysRemember(true)//remember me 기능이 활성화되지 않아도 항상 실행. default false
    .userDetailsService(userDetailsService);//Remember me에서 시스템에 있는 사용자 계정을 조회할때 사용할 클래스

RememberMeAuthenticationFilter는 아래와 같은 프로세스로 쿠키를 추출해 토큰을 분해하여 정상유뮤를 판단 후, 새로운 Authentication을 생성하여 준다.


security 카테고리 내 다른 글 보러가기

Leave a comment