인프런 커뮤니티 질문&답변

Rain D님의 프로필 이미지

작성한 질문수

스프링 시큐리티

10) 인증 실패 핸들러 : CustomAuthenticationFailureHandler

error , exception 이 잘 안됩니다.

작성

·

168

·

수정됨

0

강사님 소스와 똑같이 했는데도 안되는데요 ....

로그인 실패해도 에러 문구가 안뜹니다.

 

디버깅하면 Controller 값이 null 로 들어오는데 왜그런걸까요 ??

 

security 설정에 /login?* 설정도 해줬습니다.

 

@Controller

public class LoginController {

 

// 에러가 있을때만 선택적으로 받는다.

@RequestMapping(value={"/login"})

public String login(@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 "login";

}

 

@GetMapping("/logout")

public String logout(HttpServletRequest request, HttpServletResponse response) {

 

Authentication authentiation = SecurityContextHolder.getContext().getAuthentication();

 

if (authentiation != null) {

new SecurityContextLogoutHandler().logout(request, response, authentiation);

}

 

return "redirect:/login";

 

}

}

 

 


package com.eazybytes.springsecsection3.security.handler;

 

import java.io.IOException;

 

import org.springframework.security.authentication.BadCredentialsException;

import org.springframework.security.authentication.InsufficientAuthenticationException;

import org.springframework.security.core.AuthenticationException;

import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;

import org.springframework.stereotype.Component;

 

import jakarta.servlet.ServletException;

import jakarta.servlet.http.HttpServletRequest;

import jakarta.servlet.http.HttpServletResponse;

 

// 인증 검증시 실패할때 인증 예외 발생

@Component

public class CustomAuthenticationFailureHandle extends SimpleUrlAuthenticationFailureHandler {

 

@Override

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

 

String errorMessage = "Invalid Username or Password";

 

if(exception instanceof BadCredentialsException) {

errorMessage = "Invalid Username or Password";

 

}else if(exception instanceof InsufficientAuthenticationException) {

errorMessage = "Invalid Secret";

}

 

setDefaultFailureUrl("/login?error=true&exception=" + errorMessage);

 

super.onAuthenticationFailure(request, response, exception);

 

}

}


package com.eazybytes.springsecsection3.security.config;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.autoconfigure.security.servlet.PathRequest;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.security.authentication.AuthenticationDetailsSource;

import org.springframework.security.authentication.AuthenticationProvider;

import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;

import org.springframework.security.config.annotation.web.builders.HttpSecurity;

import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;

import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import org.springframework.security.crypto.password.PasswordEncoder;

import org.springframework.security.web.SecurityFilterChain;

import org.springframework.security.web.authentication.AuthenticationFailureHandler;

import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import com.eazybytes.springsecsection3.security.provider.CustomAuthenticationProvider;

import com.eazybytes.springsecsection3.security.service.CustomUserDetailsService;

import jakarta.servlet.DispatcherType;

@Configuration

public class SecurityConfig {

 

@Autowired

private AuthenticationSuccessHandler customerauthenticationSuccessHandler; // 인증 성공후 핸들링 처리

 

@Autowired

private AuthenticationFailureHandler authenticationFailureHandlerl; // 인증 실패후 핸들링 처리

 

@Autowired

private AuthenticationDetailsSource authenticationDetailsSource; // FormWebAuthenticationDetails 을 security 가 사용할 수 있도록 등록

 

@Autowired

private CustomUserDetailsService userDetailsService; // 개발자가 만든 userDetailsService 를 사용

 

protected void configure (AuthenticationManagerBuilder auth) throws Exception{ // CustomAuthenticationProvider 를 seruciry 가 사용할 수 있도록 등록

auth.authenticationProvider(authenticationProvider());

}

 

@Bean

public AuthenticationProvider authenticationProvider() {

return new CustomAuthenticationProvider();

}

 

@Bean

SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {

http.csrf(AbstractHttpConfigurer::disable);

 

http.authorizeHttpRequests((auth) ->

auth

.dispatcherTypeMatchers(DispatcherType.FORWARD).permitAll()

.requestMatchers("/","/users","/users/login/**, /login*").permitAll() /* /login* /login?error=true&exception 접근 허용 */

.requestMatchers("/mypage").hasRole("USER")

.requestMatchers("/message").hasRole("MANAGER")

.requestMatchers("/config").hasRole("ADMIN")

.anyRequest().authenticated());

 

http.formLogin((form) ->

form.loginPage("/login")

.loginProcessingUrl("/login_proc")

.defaultSuccessUrl("/")

.authenticationDetailsSource(authenticationDetailsSource)

.successHandler(customerauthenticationSuccessHandler ) // 인증이 성공한 후 핸들링 처리

.failureHandler(authenticationFailureHandlerl) // 인증이 실패후 후 핸들링 처리

.permitAll()

);

return http.build();

}

 

 

@Bean

public PasswordEncoder passwordEncoder() {

return new BCryptPasswordEncoder();

}

 

 

@Bean

public WebSecurityCustomizer webSecurityCustomizer() {

// 정적 리소스 spring security 대상에서 제외

return (web) ->

web

.ignoring()

.requestMatchers(

PathRequest.toStaticResources().atCommonLocations()

);

}

}

 ---------------------

 

 

<!DOCTYPE html>

<html xmlns:th="http://www.thymeleaf.org">

<head th:replace="layout/header::userHead"></head>

<body>

<div th:replace="layout/top::header"></div>

<div class="container text-center">

<div class="login-form d-flex justify-content-center">

<div class="col-sm-5" style="margin-top: 30px;">

<div class="panel">

<p>아이디와 비밀번호를 입력해주세요</p>

</div>

<div th:if="${param.error}" class="form-group">

<span th:text="${exception}" class="alert alert-danger">잘못된 아이디나 암호입니다</span>

</div>

<form th:action="@{/login_proc}" class="form-signin" method="post">

<input type="hidden" th:value="secret" name="secret_key" />

<div class="form-group">

<input type="text" class="form-control" name="username" placeholder="아이디" required="required" autofocus="autofocus">

</div>

<div class="form-group">

<input type="password" class="form-control" name="password" placeholder="비밀번호" required="required">

</div>

<button type="submit" class="btn btn-lg btn-primary btn-block">로그인</button>

</form>

</div>

</div>

</div>

</body>

</html>

답변 2

0

정수원님의 프로필 이미지
정수원
지식공유자

코드상으로는 특별한 문제가 없어 보이는데요..

@RequestMapping(value={"/login"})

public String login(@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 "login";

}

위에 디버깅을 걸어놓고 데이터가 들어오는지 부터 확인해 보시기 바랍니다.

만약 들어오지 않는다면 실패 핸들러에서 디버깅을 걸어서 정확하에 어디로 이동하고 있는지 확인해 보시기 바랍니다.

어디에서 데이터가 누락이 되고 있는지 위치를 찾아내는 것이 중요합니다.

만약 도저히 못찾겠으면 소스를 공유해 주시면 제가 테스트 해 보도록 하겠습니다.

 

0

안녕하세요, 인프런 AI 인턴입니다.

RainD님의 문제를 해결하기 위해 여러분들이 제공한 정보를 확인하였습니다. 로그인 실패 시 에러 메시지가 나타나지 않는 문제가 발생하였군요. 이 문제를 해결하기 위해서는 몇 가지 점을 확인해볼 필요가 있습니다.

  1. CustomAuthenticationFailureHandle 클래스에서 실패 URL을 정확히 설정하셨는지 확인해보세요. 여기서 setDefaultFailureUrl("/login?error=true&exception=" + errorMessage); 부분이 로그인 실패 시 리다이렉트될 URL을 지정합니다. 이 URL이 뷰에서 정의된 URL과 일치하는지 확인해주세요.

  2. SecurityConfig 클래스의 http.formLogin() 설정 부분에서 failureHandler(authenticationFailureHandlerl)이 정확히 CustomAuthenticationFailureHandle을 참조하고 있는지 확인해보세요. 스프링 시큐리티 설정에서 로그인 실패 핸들러로 CustomAuthenticationFailureHandle을 사용하도록 설정되어 있는지를 다시 한번 검토해야 합니다.

  3. login 메소드의 @RequestParam(value = "exception", required = false) String exception 부분에서 에러 메시지가 모델에 정상적으로 추가되었는지 확인하세요. 이 부분에서 받은 exception 값을 뷰로 잘 전달하고 있는지 확인이 필요합니다.

  4. HTML 템플릿 내에서 에러 메시지를 올바르게 표시하고 있는지 확인해보세요. <div th:if="${param.error}" class="form-group">와 같이 조건을 체크하고, <span th:text="${exception}" class="alert alert-danger">잘못된 아이디나 암호입니다</span>를 통해 실제 발생한 예외 메시지를 사용자에게 보여주고 있는지 확인이 필요합니다.

위의 4가지 점을 검토해 보시고, 그래도 문제가 해결되지 않으면 추가적으로 보안 설정이나 컨트롤러의 로직에서 오류가 없는지 자세히 살펴보시기 바랍니다.

Rain D님의 프로필 이미지

작성한 질문수

질문하기