본문 바로가기
Framework/Spring Framework

[Spring Boot] Spring Security 로그인 처리

by 원동호 2021. 5. 2.
반응형

HTTP Security

아래는 configure method에서 구성 가능한 함수들이다.

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http
        	// Form 로그인 인증 기능 작동
                .formLogin() 
                // SpringSecurity에서 기본 Form 로그인 화면 을 제공하지만
                // 아래 설정을 하면 사용자 정의 로그인 페이지를 사용할 수 있다.
                .loginPage("/loginPage") 
                // 로그인 성공 후 이동 페이지 URL
                .defaultSuccessUrl("/")
                // 로그인 실패 후 이동 페이지 URL
                .failureUrl("/login")
                // Form tag의 name 값, 기본적으로는 username이 사용되지만
                // 다른 값으로도 사용 가능함. 
                .usernameParameter("userId")
                // Form tag의 password 값, 기본적으로는 password가 사용되지만
                // 다른 값으로도 사용 가능함.
                .passwordParameter("passwd")
                // Fortm tag의 action URL
                .loginProcessingUrl("/login_proc")
                // 로그인 성공 이후 핸들러 호출               
                .successHandler(loginSuccessHandler())
                // 로그인 실패 이후 핸들러 호출
                .failureHandler(loginFailureHandler())
    } 

처리 PROCESS

 

 

1. UsernamePasswordAuthenticationFilter

→ Login Form 인증 처리를 총체적으로 담당하는 클래스이다. 필요한 여러 클래스를 불러들여 인증을 처리한다.

 

2. AntPathRequestMatcher(/login)

→ 요청 정보 URL(Form tag의 action)이 매칭 되는지 확인한다. ( default는 login이다)

 

3. Authentication(Username + Password)

→ Login Form 에서 넘어온 username , password값을 인증 객체에 저장하고 그 값을 인증 관리자에게 넘겨준다.

 

4. AuthenticationManager

인증 객체를 받아서 AuthenticationProvider에게 인증 처리를 위임한다.

  • 인증성공
  • Authentication 객체를 생성하여 유저정보, 권한정보를 저장하고 인증관리자에게 전달한다.
  • 인증 실패
  • AuthenticationException에게 전달하여 예외를 처리하도록 한다.

5. Authentication

→ AuthenticationManager 인증에 성공 하게 된 후 최종적으로 받은 Authentication 객체(유저 정보, 권한 정보)

 

6. SecurityContext

→ 인증 객체를 저장하는 보관소이다. 전역적으로 인증 객체를 참조할 수 있다.

 

7. SuccessHandler

→ 인증 성공 후 작업을 담당

 


로그인 PROCESS

AbstractAuthenticationProcessingFilter.java

private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
	//2번. 로그인 요청이 아닐 경우에는 다음 필터로 넘긴다.
	if (!requiresAuthentication(request, response)) {
		chain.doFilter(request, response);
		return;
	}
	try {
		/* 3번. 로그인 시도 -> UsernamePasswordAuthenticationFilter에서 Overirde한다.
		 * 4~5번 처리 후 최종적으로 Authentication 객체를 authenticationResult에 넣음.
		 */
		Authentication authenticationResult = attemptAuthentication(request, response);
		if (authenticationResult == null) {
			return;
		}
		this.sessionStrategy.onAuthentication(authenticationResult, request, response);
		// Authentication success
		if (this.continueChainBeforeSuccessfulAuthentication) {
			chain.doFilter(request, response);
		}
		//6~7번을 처리한다.
		successfulAuthentication(request, response, chain, authenticationResult);
	} catch (InternalAuthenticationServiceException failed) {
		this.logger.error("An internal error occurred while trying to authenticate the user.", failed);
		unsuccessfulAuthentication(request, response, failed);
	} catch (AuthenticationException ex) {
		// Authentication failed
		unsuccessfulAuthentication(request, response, ex);
	}
}

 

UsernamePasswordAuthenticationFilter.java

@Override
//3번. 
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
	throws AuthenticationException {
    
    if (this.postOnly && !request.getMethod().equals("POST")) {
    	throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
    }
    String username = obtainUsername(request);
    username = (username != null) ? username : "";
    username = username.trim();
    String password = obtainPassword(request);
    password = (password != null) ? password : "";
    UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
    // Allow subclasses to set the "details" property
    setDetails(request, authRequest);
    // 3번. 인증관리자에게 인증정보를 넘긴다.
    return this.getAuthenticationManager().authenticate(authRequest);
}

 

ProviderManager.java

//AuthenticationManager 을 implements했음.
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
	Class<? extends Authentication> toTest = authentication.getClass();
	AuthenticationException lastException = null;
	AuthenticationException parentException = null;
	Authentication result = null;
	Authentication parentResult = null;
	int currentPosition = 0;
	int size = this.providers.size();
	
	for (AuthenticationProvider provider : getProviders()) {
		if (!provider.supports(toTest)) {
			continue;
		}
		if (logger.isTraceEnabled()) {
                  logger.trace(LogMessage.format("Authenticating request with %s (%d/%d)",
                  provider.getClass().getSimpleName(), ++currentPosition, size));
		}
		try {
			//4번 provider에게 인증을 위임한다.
			result = provider.authenticate(authentication);
			if (result != null) {
				copyDetails(authentication, result);
				break;
			}
		} catch (AccountStatusException | InternalAuthenticationServiceException ex) {
			prepareException(ex, authentication);
			throw ex;
		}
		/* ...
		* 중략...
		* ...
		*/
	}
}

 

 

반응형

댓글