2023.02.26 - [Back-End/Spring Security] - 스프링 시큐리티(1) - 프로젝트 구성 및 의존성 추가
인증 API - 사용자 정의 보안 기능 구현
WebSecurityConfigurerAdapter
: 시큐리티의 기능 초기화 작업과 설정을 담당하는 클래스
HttpSecurity
: 세부적인 보안 기능을 설정할 수 있는 API를 제공해준다.
이번 장에서는 SecurityConfig
클래스를 생성하여 WebSecurityConfigurerAdapter
를 상속 받은 후에 HttpSecurity
를 사용해서 사용자 정의 클래스를 정의 할 것입니다.
초기화 작업 살펴보기
WebSecurityConfigurerAdapter
클래스를 살펴보면 서버가 기동 될 때,
HttpSecurity 객체를 생성 하고
그 후 해당 객체의 약 11가지 필드들을 초기화 시키는 작업들이 이루어 집니다.
이후에 http에서 보안을 적용 시켜주는 작업을 거칩니다.
anyRequest()
: 모든 요청에 대해서
authenticated()
: 보안검사를 진행 하겠다.
인증 방식은 formLogin()
방식과 httpBasic()
방식을 제공을 하겠다는 설정입니다.
사용자 설정 클래스 생성
SecurityConfig
클래스를 생성합니다. 해당 클래스는 WebSecurityConfigurerAdapter
를 상속받습니다.
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;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest()
.authenticated();
http
.formLogin();
}
}
configure()
메소드를 오버라이등 해주는데, 기본적인 설정과 비슷하게 모든 요청에 대해서 보안검사를 진행하게 설정을 하고, form로그인만 지원을 하게 합니다.
application.properties
spring.security.user.name=user
spring.security.user.password=1111
기본적인 user 설정은 application.properties 파일에서 바꿀수 있습니다.
로그인을 해 보면 우리가 사용자 설정 클래스를 통해서 진행되는 인증이 잘 진행되는 것을 알 수 있습니다.
Form인증
사용자가 form을 통해서 로그인을 하게되는 과정
- username과 password를 입력하고 요청
- 서버에서 SecurityContext객체를 생성하게 되고, Authentication 타입의 인증 토큰을 객체를 생성하여 해당 토큰을 session에 저장하게 됩니다.
form로그인에서 제공하는 API 사용하기
form로그인에서 제공해주는 여러가지 API들이 있습니다.
사용자 설정 클래스 수정
@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("login");
}
})
.permitAll()
;
}
}
formLogin에 대한 설정으로 API를 사용해서 여러가지 설정을 진행 하였습니다.
로그인 성공시에 인증토큰을 생성하고 루트 페이지로 리다이렉트 시켰고,
로그인 실패시에 오류내용 출력 및 login 페이지로 리다이렉트 시켰습니다.
컨트롤러 수정
@RestController
public class SecurityController {
@GetMapping("/")
public String index() {
return "home";
}
@GetMapping("/loginPage")
public String loginPage() {
return "loginPage";
}
}
Form 로그인 Filter 인증 과정
AbstractAuthenticationProcessFillter
가UsernamePasswordAuthenticationFilter
를 호출UsernamePasswordAuthenticationFilter
는AntPathRequestMatcher
을 이용해서 “/login” 같은 login URL로 접근했는지 확인하고, 해당 URL이 아니라면 다음 필터로 넘겨준다.Authentication
인증 객체를 만들고, Request에 들어있는 username / password 정보를 넣는다.- 필터는
AuthenticationManager
에게 인증 객체를 전달한다. AuthenticationManager
는 내부적으로AuthenticationProvider
를 가지고 있어서, 인증처리를 할 수 있다. 인증이 실패하면 Exception을 발생시킨다. 인증이 성공하면Authentication
객체에 user정보와 권한정보를 넣어서 반환 시킨다.- 필터는 해당
Authentication
객체를SecurityContext
에 저장 한다. - 성공 핸들러를 호출한다.
Form 로그인 Filter 인증 코드 추적하기
- 인증요청이 오면
AbstractAuthenticationProcessingFilter
의 doFilter() 메서드가 호출된다. - 그 후
requiresAuthentication
메서드를 이용해서 인증이 필요한 요청인지 확인하고, 인증이 필요없는 요청이라고 확인되면 다음 Filter로 체이닝을 해준다. - 인증이 필요한 요청인 경우,
attemptAuthentication
메서드를 통해서 인증을 실행한다. AuthenticationManager
는 내부적으로 여러 Provider를 가지고있는데, 매니저는 이 모든 Provider를 for문으로 순회하면서 인증이 가능한지 찾는다.Provider
를 찾은후, 인증을 실행하여 인증 성공또는 실패값이 담긴 결과를 리턴한다.- 해당 인증 결과를
SecurityContext
에 저장한다.
해당 글은 인프런의 스프링 시큐리티 - Spring Boot 기반으로 개발하는 Spring Security 을 공부하며 작성한 글입니다.
https://www.inflearn.com/course/코어-스프링-시큐리티/dashboard