본문 바로가기

Spring Security

로그인 실패시 Failure Handler

728x90

securityConfig.java

private final AuthenticationFailureHandler customAuthFailureHandler;


@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable();
    http.authorizeRequests()
            .antMatchers("/","/user/**","/image/**","/subscribe/**","/comment/**","/api/**").authenticated()
            .anyRequest().permitAll()
            .and()
            .formLogin()//위에있는 url말고 다른곳에 들어갈 경우 loginPage로 redirect시킴
            .loginPage("/auth/signin")//get
            .loginProcessingUrl("/auth/signin")//post-> 스프링 시큐리티가 로그인 프로세스진행
            .failureHandler(customAuthFailureHandler)  //로그인 실패시 이를 처리할 핸들러
            .defaultSuccessUrl("/")
            .and()
            .oauth2Login()// form 로그인을 포함하여 oauth2 로그인도 할거임
            .userInfoEndpoint()//oauth2 로그인을하게되면, 바로 회원정보를 돌려줘
            .userService(oauth2DetailsService);
}

 

 

 

CustomAuthFailureHandler.java

package com.cos.photogramstart.handler.aop;

import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;

@Component
public class CustomAuthFailureHandler extends SimpleUrlAuthenticationFailureHandler {

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

        String errorMessage;

        if (exception instanceof BadCredentialsException) {
            errorMessage = "아이디 또는 비밀번호가 맞지 않습니다. 다시 확인해 주세요.";
        } else if (exception instanceof InternalAuthenticationServiceException) {
            errorMessage = "내부적으로 발생한 시스템 문제로 인해 요청을 처리할 수 없습니다. 관리자에게 문의하세요.";
        } else if (exception instanceof UsernameNotFoundException) {
            errorMessage = "계정이 존재하지 않습니다. 회원가입 진행 후 로그인 해주세요.";
        } else if (exception instanceof AuthenticationCredentialsNotFoundException) {
            errorMessage = "인증 요청이 거부되었습니다. 관리자에게 문의하세요.";
        } else {
            errorMessage = "알 수 없는 이유로 로그인에 실패하였습니다 관리자에게 문의하세요.";
        }

        errorMessage = URLEncoder.encode(errorMessage, "UTF-8");
        setDefaultFailureUrl("/auth/signin?error=true&exception=" + errorMessage);
        //즉, 위와 같은 예외가 발생하면 특정 에러 메시지를 저장하여 setDefaultFailureUrl() 메소드를 통해 컨트롤러로 전달하는 것입니다.

        super.onAuthenticationFailure(request, response, exception);
    }
}

AuthContoller.java

private final AuthService authService;

@GetMapping("/auth/signin")
public String signinForm(@RequestParam(value = "error", required = false) String error,
                         @RequestParam(value = "exception", required = false) String exception,
                         Model model) {
    model.addAttribute("error",error);
    model.addAttribute("exception",exception);
    return "/auth/signin";
}

PrincipalDetailService

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {



    User userEntity = userRepository.findByUsername(username);

    if(userEntity==null){
        throw new UsernameNotFoundException("유저가 존재하지않습니다");
    }else{
        return new PrincipalDetails(userEntity);
    }


}

signin.jsp

<c:if test="${error}">
    <p class="exception">${exception}</p>
</c:if>

 

동작과정은 다음과 같습니다

 

1. 사용자가 로그인요청을 시도한다.

2. PrincipalDetailsService에 loadbyUsername을 통해 사용자를 확인하고 로그인에 실패하게되면

3.ThrowException을 날리게되고 SercurityConfig에 등록된 FailHalder가 처리를 시도하고.

4.해당 하는예외에 맞는 에러메세지를 Controller에 get방식으로 넘겨주게되면

5.컨트롤러는 모델에 에러유무 및 Exception종류를 담아서 view 에 전달하게 된다.

 

728x90

'Spring Security' 카테고리의 다른 글

aAuth2 client를 통해 facebook 로그인하기  (0) 2023.02.13
Spring Security CSRF  (0) 2023.02.02