관리 메뉴

bright jazz music

[Spring security] 1.3 Form Login 인증 본문

Framework/Spring Security

[Spring security] 1.3 Form Login 인증

bright jazz music 2022. 9. 9. 18:38

1. Form 로그인 절차 설명

 

1. 접근 시도

2. Form 리다이렉트

3. POST[ id + pw]

인증처리- 계정 정보가 맞는 경우 스프링 시큐리티가 세션 생성

객체 생성- 세션에 최종 성공한 인증결과를 담은 인증 토큰 객체(Authetication 클래스)를 시큐리티 컨텍스트에 생성.

저장 - 이 시큐리트 컨텍스트를 세션에 저장한다.

 

4. 클라이언트가 다시 접근을 시도하면, 스프링 시큐리티는 사용자가 가진 세션으로부터 토큰 존재 여부판단. 그 토큰으로 계속 접근. 스프링 시큐리티는 토큰에 기반해 인증 유지/

 

2. 폼 로그인 인증 방식에서 사용하는 API 설명

 

 

http.formLogin()을 적어주면 폼 로그인 인증 기능이 작동

  • loginPage() : 경로를 적어주면 사용자 정의 로그인 페이지 사용 가능
  • defaultSuccessUrl("/home") : 로그인에 성공한 이후 이동할 페이지
  • failureUrl("/login.html?error=true") : 로그인 실패 후 이동할 페이지

 

  • usernameParameter("username") : 아이디 파라미터명 설정. 폼 태그 안에서 유저 네임 값을 변경할 수 있음. 기본 값은 username. 값을 변경하면 UI 화면에서도 태그 명을 똑같이 적어줘야 한다.
  • passwordParameter("password") : 패스워드 파라미터명 설정. 폼 태그 안에서 패스워드 값을 변경할 수 있음. 기본 값은 password. 값을 변경하면 UI 화면에서도 태그 명을 똑같이 적어줘야 한다.

 

  • loginProcessingUrl("/login") : 로그인 Form Action Url. 폼태그에서 action태그에 들어갈 url을 설정한다.
  • successHandler(loginSuccesshandler()) : 로그인 성공 후 핸들러.
  • failureHandler(loginFailureHandler()) : 로그인 실패 후 핸들러

 

 

 

3.SecurityConfig 설정

위의 API들을 실제 적용해 보자.

package io.security.basicsecurity;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

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

@Configuration //설정파일이므로
@EnableWebSecurity //여러 클래스들을 임포트 해서 실행시키는  어노테이션이다. 그래야 웹 보안이 활성화 된다.
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception{
        http
                .authorizeRequests()    //요청에 대한 보안검사 시작
                .anyRequest().authenticated(); //어떤 요청에도 인가 받도록 설정. 안 받으면 접근 불가
        //그래서 인가를 받기 위해 /loginPage로 이동한다. 근데 이 경로도 인가가 필요하다.
        //그래서 이 경로는 인가를 받지 않아도 접근 가능하도록 처리한다.
        // .permitALL()을 붙여줘서 /loginPage로의 접근은 인가르 받지 않아도 되도록 처리한다.

        //이제 인증방식
        http
                .formLogin()
                .loginPage("/loginPage")
                .defaultSuccessUrl("/")
                .failureUrl("/login")
                .usernameParameter("userId")
                .passwordParameter("passwd")
                .loginProcessingUrl("/login_proc")
                .successHandler(new AuthenticationSuccessHandler() { //로그인에 성공했을 떄 성공 핸들러. AuthenticationSuccessHander 구현체를 넣어주면 된다. 우리는 걍 익명 클래스 사용
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                        //request, response, authentication 인증에 성공했을 때 그 결과를 담은 인증 객체까지 파라미터로 전달되어서 넘어온다.
                        //이걸 활요해서 구체적인 로직을 구현하면 된다.
                        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("/login");
                    }
                })
                .permitAll();

    }
}

 

위 코드대로라면 

localhost:8080/으로 접근 시 /loginPage 경로로 이동해야 할 것이다.

 

이에 맞춰 다른 파일들도 설정해 주자

 

4. SecurityController.java 설정

package io.security.basicsecurity;


import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SecurityController {

    @GetMapping("/")
    public String index(){
        return "home";
    }
    
	//아래의 코드 추가. 여기가 인증 폼 역할을 하게 된다.
    @GetMapping("loginPage")
    public String loginPage(){
        return "loginPage";
        //원래는 @Controller 어노테이션과 함께 실제 페이지를 반환해야 한다.
        // 여기서는 편의상 @RestController를 사용해서 문자열만 보이게 한다.
    }
}

 

5. 사용자 지정 로그인 페이지(/loginPage) 확인

 

서버 재기동 후 

브라우저에서 localhost:8080을 기입하여 접근해 보자.

 

로그인 페이지(/loginPage)로 이동 성공했다. 원래는 실제 같았으면 loginPage라는 문구 대신 로그인 폼이 있어야 할 것이다.

 

6. 스프링 시큐리티 기본 로그인 폼을 통한 API 설정 확인

우리의 사용자 지정 페이지(/loginPage)는 폼이 없고 문구만 있기 때문에 .loginPage("/loginPage") 아래에 설정한 API들이 잘 작동하는지 확인할 수 없다. 따라서 스프링 시큐리티 기본 폼을 사용하여 확인해 보자

 

6-1 .loginPage("loginPage") 주석처리

스프링 시큐리티 기본 폼을 사용하기 위해서 사용자 지정 페이지 사용을 주석처리

package io.security.basicsecurity;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

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

@Configuration //설정파일이므로
@EnableWebSecurity //여러 클래스들을 임포트 해서 실행시키는  어노테이션이다. 그래야 웹 보안이 활성화 된다.
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception{
        http
                .authorizeRequests()    //요청에 대한 보안검사 시작
                .anyRequest().authenticated(); //어떤 요청에도 인가 받도록 설정. 안 받으면 접근 불가
        //그래서 인가를 받기 위해 /loginPage로 이동한다. 근데 이 경로도 인가가 필요하다.
        //그래서 이 경로는 인가를 받지 않아도 접근 가능하도록 처리한다.
        // .permitALL()을 붙여줘서 /loginPage로의 접근은 인가르 받지 않아도 되도록 처리한다.

        //이제 인증방식
        http
                .formLogin()
                //.loginPage("/loginPage")
                .defaultSuccessUrl("/")
                .failureUrl("/login")
                .usernameParameter("userId")
                .passwordParameter("passwd")
                .loginProcessingUrl("/login_proc")
                .successHandler(new AuthenticationSuccessHandler() { //로그인에 성공했을 떄 성공 핸들러. AuthenticationSuccessHander 구현체를 넣어주면 된다. 우리는 걍 익명 클래스 사용
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                        //request, response, authentication 인증에 성공했을 때 그 결과를 담은 인증 객체까지 파라미터로 전달되어서 넘어온다.
                        //이걸 활요해서 구체적인 로직을 구현하면 된다.
                        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("/login");
                    }
                })
                .permitAll();

    }
}

 

 

 

6-3 로그인에 성공한 경우

.successHandler(new AuthenticationSuccessHandler() { //로그인에 성공했을 떄 성공 핸들러. AuthenticationSuccessHander 구현체를 넣어주면 된다. 우리는 걍 익명 클래스 사용
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                        //request, response, authentication 인증에 성공했을 때 그 결과를 담은 인증 객체까지 파라미터로 전달되어서 넘어온다.
                        //이걸 활요해서 구체적인 로직을 구현하면 된다.
                        System.out.println("authentication : " + authentication.getName());
                        response.sendRedirect("/"); //루트페이지로 이동
                    }
                })

// 콘솔에 다음의 내용이 출력된다.
//authentication : user

 

6-4 로그인에 실패한 경우

.failureHandler(new AuthenticationFailureHandler() {
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        //인증 예외 객체를 파라미터로 전달 받는다.
        System.out.println("exception : " + exception.getMessage()); //예외 메시지 출력
        response.sendRedirect("/login");
    }
})

//콘솔에 다음의 내용이 출력된다.
// exception : 자격 증명에 실패하였습니다.

 

 

6-5 폼 태그 변경 확인하기

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

폼 태그는 어떻게 설정 되었을까?

 

로그인 페이지에서 개발자 도구(크롬의 경우 F12)를 눌러 소스를 보자.

 

폼 태그의 내부 값들이 아래와 같이 자동으로 변경돼 있는 것을 볼 수 있다.

 

  • action="login_proc"
  • name="userId"
  • name="passwd"

 

 

 

6-6 로그아웃

 

로그인에 성공한 후 로그아웃 하려면

 

  • url에 /logout을 적어주면 된다.

 

Comments