Side-project : Spring Security + Session 로그인하기 (2)

우진·2023년 5월 18일
0
post-custom-banner


👾 Spring Security

https://docs.spring.io/spring-security/reference/index.html


👾 Validating Login form with Spring Security

이전 포스팅에 이어서... 로그인 기능을 구현했으니 폼의 유효성 체크를 해줘야 한다.

기본적인 유효성 체크(input required 등)는 클라이언트 단에서 진행했다는 가정하에, 서버의 사용자 인증에 관한 오류 메시지를 뿌려줄 거다.


(1) 📁 Create LoginFailureHandler

로그인 실패시 후처리를 해주는 커스텀 핸들러를 만들 거다. 지금 만드는 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);
    }
}
  • setDefaultFailureUrl:
    이렇게 되면 /login 경로에 errorexception을 파라미터값으로 넘기게 되니 컨트롤러를 수정해야 한다.

(2) 📁 Update UserController

@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";
    }
}
  • @RequestParam(): 쿼리 스트링으로 들어오는 파라미터를 자동 매핑해준다. value 속성으로 파라미터명을 지정해준다. required 속성으로 필수로 받는 파라미터인지 설정할 수 있다.
  • model.addAttribute(): 받아온 파라미터를 각각 model에 담아준다.

(3) 📁 Update login.html

<!--  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>
  • th:if="": 속성값이 true일 경우에만 해당 태그를 화면에 출력한다.

(4) 📁 Update SecurityConfig

마지막으로 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();
    }

}
  • public LoginFailureHandler loginFailureHandler(): @Bean으로 등록을 해야 filterChain에서 가져다 쓸 수 있다.
  • .failureHandler(): 폼 로그인 실패시 사용할 핸들러를 지정해준다.

(5) 📁 Use

profile
백 개발을 시작한 응애개발자
post-custom-banner

0개의 댓글