이 영역을 누르면 첫 페이지로 이동
시간의화살 블로그의 첫 페이지로 이동

시간의화살

페이지 맨 위로 올라가기

시간의화살

행복하세요

[Spring Security] 인증 실패 오류 다루기

  • 2024.06.20 21:21
  • Solutions

 

 

 

스프링 시큐리티에서는 인증 관련 예외가 발생한 경우 AbstractUserDetailsAuthenticationProvider 가 클래스 내부의 hideUserNotFountExceptions 변수를 확인하고 발생한 예외를 BadCredentialsException 예외로 변환해 어떤 예외가 종류의 예외가 발생했는지 감춘다.

 

// AbstractUserDetailsAuthenticationProvider.class
@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication,
				() -> this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.onlySupports",
						"Only UsernamePasswordAuthenticationToken is supported"));
		String username = determineUsername(authentication);
		boolean cacheWasUsed = true;
		UserDetails user = this.userCache.getUserFromCache(username);
		if (user == null) {
			cacheWasUsed = false;
			try {
				user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
			}
			catch (UsernameNotFoundException ex) {
				this.logger.debug("Failed to find user '" + username + "'");
				if (!this.hideUserNotFoundExceptions) {
					throw ex;
				}
				throw new BadCredentialsException(this.messages
					.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
			}
			Assert.notNull(user, "retrieveUser returned null - a violation of the interface contract");
		}
		try {
			this.preAuthenticationChecks.check(user);
			additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
		}
		catch (AuthenticationException ex) {
			if (!cacheWasUsed) {
				throw ex;
			}
			// There was a problem, so try again after checking
			// we're using latest data (i.e. not from the cache)
			cacheWasUsed = false;
			user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
			this.preAuthenticationChecks.check(user);
			additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
		}
		this.postAuthenticationChecks.check(user);
		if (!cacheWasUsed) {
			this.userCache.putUserInCache(user);
		}
		Object principalToReturn = user;
		if (this.forcePrincipalAsString) {
			principalToReturn = user.getUsername();
		}
		return createSuccessAuthentication(principalToReturn, authentication, user);
	}

 

 

 

인증 방식에 따라 다른 예외를 뱉도록 설정하려면 AuthenticationProvider를 새로 정의한 후 시큐리티 설정에서 추가해 줘야 한다. 

 

 

public class CustomDaoAuthenticationProvider extends DaoAuthenticationProvider {    

    public CustomDaoAuthenticationProvider(UserDetailsService userDetailsService) {
        super();
        setHideUserNotFoundExceptions(false);
        setUserDetailsService(userDetailsService);
    }
    
}

// SecurityConfig.java
 @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        http                    
            ...
            .authenticationProvider(customDaoAuthenticationProvider());

        return http.build();
    }

 

 

 

기본적인 동작은 스프링 시큐리티가 사용하는 AbstractuserDetailsAuthenticationProvider 대로 사용하되, 프레임워크가 제공하는 기능 중 몇 가지만 수정해 애플리케이션의 요구사항을 반영하자.

 

 

 

@RequiredArgsConstructor
public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {

    private final UserDAO userDAO;

    @Override
	public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
			AuthenticationException exception) throws IOException, ServletException {

        String username = request.getParameter("username");
        String errorMessage = "아이디와 비밀번호를 확인해주세요. <br> 비밀번호 5회 오류 시 30분간 계정이 잠깁니다.";

        if (exception.getCause() instanceof AccountLockException) {
            errorMessage = exception.getCause().getMessage();
            request.getSession().setAttribute("error", errorMessage);
            super.onAuthenticationFailure(request, response, exception);
            return;
        }

        if (username != null) {
            UserVO userVO = userDAO.getUserInfoByAcctId(username);            

            if (userVO != null) {                

                userVO.setRetryCnt(userVO.getRetryCnt() + 1);                
                if(userVO.getRetryCnt() >= 5) userVO.setLockTime(LocalDateTime.now().plusMinutes(30));
                userDAO.updateUserInfo(userVO);
            }
        }

        request.getSession().setAttribute("error", errorMessage);
        super.onAuthenticationFailure(request, response, exception);
	}
    
}


public class AccountLockException extends AuthenticationException {

    public AccountLockException(String msg) {
        super(msg);
    }
    
    public AccountLockException(String msg, Throwable cause) {
        super(msg, cause);
    }
}

 

 

 

인증 시 발생하는 오류에 따라 클라이언트에게 보여줄 예외 메세지를 다르게 설정할 때 사용한다.

 

스프링 시큐리티 프레임워크는 인증과 인가 프로세스를 기본적으로 제공하니.. 

 

제공하는 프로세스 중 특정 부분에서 수정이 필요한 경우 애플리케이션을 디버그 모드로 실행시키고 어떤 부분에서 어떻게 설정하는지 파악한 후 해당 부분을 조작하자. 

 

보통 상속과 오버라이드를 사용한다. 

 

 

반응형
저작자표시 (새창열림)

'Solutions' 카테고리의 다른 글

[PDF.js] PDF.js 완벽 가이드  (3) 2024.11.07
[Spring Batch] 메타데이터 테이블과 시퀀스  (0) 2024.11.05
[SQL Server] 지원하지 않는 TLS 버전 설정  (1) 2024.06.05
대용량 파일 업로드 처리 (30GB)  (1) 2023.12.03
[JavaScript] Shadow DOM 다루기  (0) 2023.11.22

댓글

이 글 공유하기

  • 구독하기

    구독하기

  • 카카오톡

    카카오톡

  • 라인

    라인

  • 트위터

    트위터

  • Facebook

    Facebook

  • 카카오스토리

    카카오스토리

  • 밴드

    밴드

  • 네이버 블로그

    네이버 블로그

  • Pocket

    Pocket

  • Evernote

    Evernote

다른 글

  • [PDF.js] PDF.js 완벽 가이드

    [PDF.js] PDF.js 완벽 가이드

    2024.11.07
  • [Spring Batch] 메타데이터 테이블과 시퀀스

    [Spring Batch] 메타데이터 테이블과 시퀀스

    2024.11.05
  • [SQL Server] 지원하지 않는 TLS 버전 설정

    [SQL Server] 지원하지 않는 TLS 버전 설정

    2024.06.05
  • 대용량 파일 업로드 처리 (30GB)

    대용량 파일 업로드 처리 (30GB)

    2023.12.03
다른 글 더 둘러보기

정보

시간의화살 블로그의 첫 페이지로 이동

시간의화살

  • 시간의화살의 첫 페이지로 이동

검색

방문자

  • 전체 방문자
  • 오늘
  • 어제

카테고리

  • 분류 전체보기 (607)
    • Algorithm (205)
      • Data Structure (5)
      • Theory && Tip (33)
      • Baekjoon (166)
      • ALGOSPOT (1)
    • Spring (123)
      • Spring (28)
      • Spring Web MVC (20)
      • Spring Database (14)
      • Spring Boot (6)
      • Spring 3.1 (11)
      • Spring Batch (6)
      • Spring Security (16)
      • JPA (12)
      • Spring Data JPA (5)
      • QueryDSL (4)
      • eGovFramework (1)
    • Programming Language (74)
      • Java (19)
      • JavaScript (15)
      • C (25)
      • C++ (12)
      • Python (1)
      • PHP (2)
    • Computer Science (69)
      • Operating System (18)
      • Computer Network (17)
      • System Programming (22)
      • Universial Programming Lang.. (8)
      • Computer Architecture (4)
    • Database (21)
      • Database (7)
      • MySQL (3)
      • Oracle (3)
      • Redis (5)
      • Elasticsearch (3)
    • DevOps (20)
      • Docker && Kubernetes (8)
      • Jenkins (4)
      • Github Actions (0)
      • Amazon Web Service (8)
    • Machine Learning (28)
      • AI Introduction (28)
    • Mobile (28)
      • Android (21)
      • Flutter (7)
    • Solutions (14)
    • Life Logs (0)
    • 낙서장 (25)

최근 글

나의 외부 링크

메뉴

  • 홈

정보

13months의 시간의화살

시간의화살

13months

블로그 구독하기

  • 구독하기
  • RSS 피드

티스토리

  • 티스토리 홈
  • 이 블로그 관리하기
  • 글쓰기
Powered by Tistory / Kakao. Copyright © 13months.

티스토리툴바