https://docs.spring.io/spring-security/reference/index.html
이전 포스팅에 이어서... 로그인 기능을 구현했으니 폼의 유효성 체크를 해줘야 한다.
기본적인 유효성 체크(input required 등)는 클라이언트 단에서 진행했다는 가정하에, 서버의 사용자 인증에 관한 오류 메시지를 뿌려줄 거다.
로그인 실패시 후처리를 해주는 커스텀 핸들러를 만들 거다. 지금 만드는 LoginFailureHandler는 SimpleUrlAuthenticationFailureHandler
를 상속받는데 이 클래스는 AuthenticationFailureHandler
의 구현체이다.
AuthenticationFailureHandler
가 아닌 SimpleUrlAuthenticationFailureHandler
를 상속받는 이유는, 오버라이딩한 메소드로 실패 후처리를 진행하고서 이동할 defaultUrl을 지정할 수 있기 때문이다!
public class LoginFailureHandler extends SimpleUrlAuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception)
throws IOException, ServletException {
String errmsg;
if(exception instanceof BadCredentialsException || exception instanceof InternalAuthenticationServiceException) {
errmsg = "아이디 또는 비밀번호가 일치하지 않습니다.";
} else if (exception instanceof AuthenticationCredentialsNotFoundException) {
errmsg = "인증 요청이 거부되었습니다. 관리자에게 문의하세요.";
} else {
errmsg = "알 수 없는 오류로 로그인 요청을 처리할 수 없습니다. 관리자에게 문의하세요.";
}
//한글 깨짐 방지
errmsg = URLEncoder.encode(errmsg, "UTF-8");
setDefaultFailureUrl("/login?error=true&exception="+errmsg);
super.onAuthenticationFailure(request, response, exception);
}
}
/login
경로에 error와 exception을 파라미터값으로 넘기게 되니 컨트롤러를 수정해야 한다.@Controller
public class UserController {
//로그인 페이지로 이동
@GetMapping({"", "/", "/login"})
public String loginPage(@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 "html/login";
}
}
value
속성으로 파라미터명을 지정해준다. required
속성으로 필수로 받는 파라미터인지 설정할 수 있다.<!-- loginForm -->
<form th:action="@{/login}" method="POST">
<p>로그인</p>
<!-- 검증 오류 메시지 -->
<div th:if="${error}">
<span th:text="${exception}" style="color : #be0000;"></span>
</div>
<input name="email" type="text" placeholder="이메일을 입력해주세요" required>
<input name="password" type="password" placeholder="비밀번호를 입력해주세요" required>
<button type="submit" th:text="로그인"></button>
</form>
true
일 경우에만 해당 태그를 화면에 출력한다.마지막으로 config에 핸들러 등록을 해줘야한다!
@Configuration
@EnableWebSecurity
public class SecurityConfig {
//해당 메서드의 리턴되는 오브젝트를 IOC로 등록해줌
@Bean
public BCryptPasswordEncoder encodePwd() {
return new BCryptPasswordEncoder();
}
@Bean
public LoginFailureHandler loginFailureHandler() {
return new LoginFailureHandler();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.cors().and()
//TODO: CorsConfigurationSource 만들어서 등록
.authorizeHttpRequests((authz) -> authz
.requestMatchers("/boards/**").authenticated()
.anyRequest().permitAll()
)
.formLogin()
.loginPage("/login")
.usernameParameter("email")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/boards")
.failureHandler(loginFailureHandler());
return http.build();
}
}
@Bean
으로 등록을 해야 filterChain에서 가져다 쓸 수 있다.