본문 바로가기
Framework/Spring

Core Spring Security | 인증 API | 03강 Form Login 인증

by YIAN 2021. 10. 31.

Core Spring Security

핵심 개념 및 아키텍처 이해와 실전 예제로 완성하는 스프링 시큐리티 프로그래밍

 

1장 Spring Security 기본 API & Filter 이해

03강 인증 API - Form Login 인증

 


👈 이전 글 | 📚 목차 | 다음 글 👉


 

1. 인증 처리 프로세스

 

 

인증 처리 프로세스를 한 번 살펴보겠습니다. 사용자(Client)가 GET 방식으로 /home 자원에 접근을 시도합니다. 참고로 강의에서는 "home"으로 나오는데, 저는 "Hello World"로 나옵니다. 서버(Server) 자원에 접근하기 위해서는 인증된 사용자만이 접근할 수 있도록 보안 설정이 되어있습니다. 사용자가 인증을 받지 않으면, 인증 실패이므로 로그인 페이지로 이동시킵니다. 그러면 Spring Security에서 기본으로 제공하는 로그인 페이지를 띄워줍니다. 이전 글에서 얘기한 것처럼 로그인 페이지는 별도로 만들 수도 있습니다.

 

POST 방식으로 username과 password를 포함한 form data를 전송하여 다시 인증을 시도합니다. 그러면 서비스는 SESSION ID에 접근하게 되고, 인증 결과를 담은 인증 토큰 객체를 생성합니다. 서버에서는 Security Context를 생성하게 되고 객체가 세션(SESSION)에 저장되는 처리가 이루어집니다. 그럼 다시 사용자가 GET 방식으로 자원에 접근하게 되면 세션으로부터 인증 토큰 여부를 판단하게 됩니다. 그러면 사용자는 인증 토큰으로 자원에 접근하게 되고, 세션에 저장된 인증 토큰이 있으면 인증된 사용자로 판단하고 인증을 유지합니다.

 

 

2. Form Login 인증 API

 

  • http.formLogin(): Form 인증 로그인 인증 기능이 작동함

 

예시코드

protected void configure(HttpSecurity http) throws Exception {
    http.formLogin()
        .loginPage("/login.html") // 사용자 정의 로그인 페이지
        .defaultSuccessUrl("/home") // 로그인 성공 후 이동 페이지
        .failureUrl("/login.html?error=true") // 로그인 실패 후 이동 페이지
        .usernameParameter("username") // 아이디 파라미터명 설정
        .passwordParameter("password") // 패스워드 파라미터명 설정
        .loginProcessingUrl("/login") // 로그인 Form Action Url
        .successHandler(loginSuccessHandler()) // 로그인 성공 후 핸들러
        .failureHandler(loginFailureHandler()) // 로그인 실패 후 핸들러
    ;
}
  • http.loginPage("경로"): 로그인 페이지 경로를 적으시면 커스텀 페이지 사용 가능함. 그러면 해당 로그인 페이지를 통해 인증하게 됨.
  • http.defaultSuccessUrl("경로"): 로그인이 성공한 이후에 이동할 페이지 경로
  • http.failureUrl("경로"): 로그인 실패 후 이동할 페이지 경로
  • http.usernameParameter("태그명"): form 태그 안에서 username에 해당하는 값을 의밋값으로 변경하면 "태그명"을 똑같이 적어야 함
  • http.passwordParameter("태그명"): form 태그 안에서 password에 해당하는 값을 의밋값으로 변경하면 form "태그명"을 똑같이 적어야 함
  • http.loginProcessinUrl("경로"): form 태그 안에서 action 정보 url을 변경할 수 있음. form 정보와 값이 동일해야 함.
    • username, password, action url 3개 값은 form 태그와 같아야 함
  • http.successHandler(): 로그인 성공했을 때 호출할 핸들러
  • http.failureHandler(): 로그인 실패했을 때 호출할 핸들러
    • 핸들러는 로그인 이후 작업을 처리할 수 있음

 

 

3. Form Login 인증방식 설정

 

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .anyRequest().authenticated()
        ;

        http
                .formLogin()
                .loginPage("/loginPage")
                .defaultSuccessUrl("/")
                .failureUrl("/login")
                .usernameParameter("userId")
                .passwordParameter("passwd")
                .loginProcessingUrl("/login_proc")
                .successHandler(new AuthenticationSuccessHandler() {
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                        System.out.println("authentication" + authentication.getName());
                        response.sendRedirect("/");
                    }
                })
                .failureHandler(new AuthenticationFailureHandler() {
                    @Override
                    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
                        System.out.println("exception" + exception.getMessage());
                        response.sendRedirect("/");
                    }
                })
                .permitAll()
        ;
    }
}

 

SecurityConfig.java에 코드를 작성해줍니다. 조금씩 뜯어서 살펴보겠습니다. 2번에서 다뤘던 것처럼 커스텀 페이지로  loginPage를 설정할 수 있습니다.

 

 

위처럼 Spring Security에서 기본적으로 생성되는 로그인 페이지가 있습니다. 이 페이지를 사용해도 되지만 이 화면보다 UI를 우리 설정에 맞게끔 만들어서 로그인을 제공할 수 있습니다. 

 

 

.successHandler(new AuthenticationSuccessHandler() {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        System.out.println("authentication : " + authentication.getName());
        response.sendRedirect("/");
    }
})
.failureHandler(new AuthenticationFailureHandler() {
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        System.out.println("exception : " + exception.getMessage());
        response.sendRedirect("/");
    }
})

 

successHandler와 failureHandler는 익명클래스를 생성해서 API를 설정해보겠습니다. 인증 객체를 파라미터로 전달해주고 있습니다. 이 클래스 안에 로그인 성공과 실패 시 구체적인 로직을 구현할 수 있습니다. 현재의 로직은 다시 루트 페이지로 넘어갑니다.

 

.permitAll()

 

.loginPage("/loginPage")에서 URL도 인증을 받지 않아도 접근이 가능해야 합니다. 누구나 접근이 가능하도록 해야 하기 때문에 .permitAll()을 사용합니다.

 

 

4. Controller 맵핑 설정

 

@RestController
public class SecurityController {

    @GetMapping("/")
    public String index() {
        return "Hello World";
    }

    @GetMapping("/loginPage")
    public String loginPage() {
        return "loginPage";
    }

}

 

이전 글에서 만든 컨트롤러인 SecurityController.java에 로그인 페이지를 맵핑해줍니다. 서버를 기동해서 실제 설정한 formLogin 방식이 정상적으로 작동하는지 확인합니다. https://localhost:8080의 루트 경로로 접속합니다.

 

이렇게 로그인 페이지로 이동됩니다. 설정 클래스(SecurityConfig)에서 인증을 해야 한다면 로그인 페이지로 이동하도록 설정했기 때문에 문자열이 출력됩니다. 나중에 작성될 글에서는 커스텀 로그인 페이지로 인증 시도되도록 구현을 해서 처리를 할 것입니다.

 

 

5. 로그인 기능 테스트

 

// .loginPage("/loginPage")

 

로그인 페이지 기능을 한 번 꺼보겠습니다. 다시 서버를 기동합니다.

 

 

 

다시 루트 페이지로 접속하게 되면 인증을 받을 수 있도록 Spring Security가 제공하는 로그인 페이지가 나옵니다. 이전 글에서 설정했던 application.properties 값을 이용해서 로그인해주세요.

 

 

 

로그인하게 되면 인증에 성공하여 우리가 작성한 익명클래스인 successHandler 구현체로 들어옵니다. 위 사진처럼 제가 디버깅 포인트를 찍은 부분을 확인하실 수 있는데요.

 

 

 

로그인에 성공하면 위와 같이 문자열이 출력됩니다. 로그인 실패하면 어떻게 되는지 보겠습니다.

 

 

 

로그인 실패했을 때는 위와 같이 문자열이 출력됩니다. 강의에서는 "Bad credentials"로 나오는데 저는 "자격 증명에 실패하였습니다."라고 한글로 나오네요. 이렇게 successHandler, failureHandler 이 2가지 핸들러의 기능이 정상 작동하는 것을 확인 할 수 있습니다. 

 

//.successHandler(new AuthenticationSuccessHandler() {
//    @Override
//    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
//        System.out.println("authentication : " + authentication.getName());
//        response.sendRedirect("/");
//    }
//})
//.failureHandler(new AuthenticationFailureHandler() {
//    @Override
//    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
//        System.out.println("exception : " + exception.getMessage());
//        response.sendRedirect("/");
//    }
//})

 

그럼 successHandler, failureHandler 이 부분들도 잠시 주석 처리하고 나머지 기능들도 살펴보겠습니다.  https://localhost:8080의 루트 경로로 이동해주세요.

 

 

 

로그인하시면 로그인에 성공했을 경우 루트 경로로 가게 됩니다. 

 

 

 

/logout 경로로 이동 후 로그인 페이지로 이동해주세요.

 

 

 

제가 일부러 비밀번호를 틀린 화면입니다. 위와 같이 로그인 실패했으면 메시지가 노출됩니다. 정상적으로 동작함을 확인할 수 있습니다. 그러면 개발자 도구인 F12 키를 눌러봅시다.

 

 

 

F12를 눌러 개발자도구를 보시면 이전 글에서 설정했던 name에 "username", "password"이 아닌 "userId", "passwd"로 다르게 설정된 것이 보입니다. action도 "/login_proc"으로 보입니다. SecurityConfig.java에서 각각 변경한 값으로 반영되어 있음을 확인할 수 있습니다. 해당 설정들은 Spring Security에서 기본으로 제공하는 로그인 페이지이기 때문에 반영된 것입니다.

 

.usernameParameter("userId")
.passwordParameter("passwd")
.loginProcessingUrl("/login_proc")

 

만약 별도의 로그인 페이지를 만든다면, 위 코드처럼 사용자 정의 보안 설정 클래스(SecurityConfig)와 form name와 action url을 동일하게 맞춰줘야 에러가 발생하지 않습니다.

 

본 글에서는 formLogin API 기능을 확인하고 테스트해 봤는데요, 다음 글에서는 인증 필터 UsernamePasswordAuthenticationFilter에 대해 알아보겠습니다.

 

 


👈 이전 글 | 📚 목차 | 다음 글 👉


 

 회고

 

이번 글은 하나씩 뜯어보았기 때문에 내용의 양이 많아 보입니다. 강의에서 설명해주는 내용 덕분에 인증 API 사용 방법에 대해 익혔습니다. 강의에 있는 내용을 참고하여 정리하면서 Form Login 인증 관련 개념을 정립했습니다. 수정해야 할 내용이 있다면 댓글로 피드백 부탁드립니다.

 

 

🍧 참고사항

  • 해당 강의는 인프런에서 정수원 님의 "스프링 시큐리티 - Spring Boot 기반으로 개발하는 Spring Security"를 통해 보실 수 있습니다.
  • 해당 포스팅을 진행하면서 생성된 코드들은 GitHub 저장소에 올리고 있습니다. 도움이 되실지 모르겠지만 하단의 GitHub Repository 주소를 참고해 주세요.
  • Code in GitHub: https://github.com/Yian-Kim/learning-Spring-Security
 

GitHub - Yian-Kim/learning-Spring-Security: 🔥 Wanna be Java Spring Security Master

🔥 Wanna be Java Spring Security Master. Contribute to Yian-Kim/learning-Spring-Security development by creating an account on GitHub.

github.com

 

댓글