시큐리티의 구조 참조사이트
시큐리티의 기초 참조사이트
시큐리티 예시 참조사이트
스프링 부트 2.7이상부터 사용이 가능하다.
인증자체가 비즈니스로직처럼 매번 개발하는 부분이 아니며 익숙하지 않고 팀내에서 이미 개발되어 있는 경우에는신규 프로젝트 할때 이외엔 볼일도 별로 없는 부분이라고 하지만 개발하는 경우도 있을수 있으니 알고 있어야 한다고 한다.
스프링시큐리티의 동작 구조를 이해하면 설정과 추가적인 구현 및 변경이 어느 부분에 적용되어야 되는지 파악이 빨라 집니다.
스프링시큐리티의 동작 구조
스프링시큐리티는 각각의 역할에 맞는 작업을 처리하는 여러개의 필터들이 체인형태로 구성되어 순서에 따라 순차적으로 수행됩니다.
그 중 UsernamePasswordAuthenticationFilter가 인증처리를 담당하고 있습니다.
[그림1] 스프링시큐리티 동작구조
1: doFilter(request: HttpServletRequest, response: HttpServletResponse)
브라우저의 로그인화면에서 아이디와 비번을 입력하고 확인을 누르면 서버에 로그인 인증 요청을 하게 되고 스프링시큐리티에 Chain형태로 구성된 Filter들의 doFilter메소드들이 순서에 따라 호출되어 각각의 역할로직들이 수행되게 됩니다.
2: attemptAuthentication(request: HttpServletRequest, response: HttpServletResponse):Authentication
For-login 기반일때 인증된 것이 들어온다면 다음으로 넘어가지만 인증되지 않았다면 로그인 페이지로 변환하게 되는형태 이 다.
AuthenticationManager가 적절한 AuthenticationProvider를 찾는다.
3: authenticate(authRequest):Authentication
AuthenticationManager는 인터페이스이며 구현체는 ProviderManager입니다. ProviderManager 는 실제 인증을 처리하는 로직이 포함된 AuthenticationProvider 인터페이스의 구현체들 중에 설정된 인증 처리방식의 구현체를 찾아 실행합니다.
실제 인증처리하는 AuthenticationProvider의 인증처리 메소드를 호출한다.
4: authenticate(authRequest):Authentication
일반적으로 클라이언트에서 아이디 비번을 받아 인증하는 방식을 사용한다면 AuthenticationProvider 인터페이스의 구현체 AbstractUserDetailsAuthenticationProvider 추상클래스를 호출하게 되고 실제 상속한 클래스의 DaoAuthenticationProvider에서 인증 처리를 하게 됩니다.
인증제공자는 UserDetailsService를 호출하여 사용자를 가져온다.
5: loadUserByUsername(username:String):UserDetails
개발자는 UserDetailsService 인터페이스를 구현해야합니다. UserDetailsService의 구현체에는 일반적으로 회원정보가 DB에 있다고 한다면 사용자의 이름(ID)로 DB를 조회하여 비밀번호가 일치하는지 확인하여 인증을 처리합니다. 인증이 완료되면 UsernamePasswordAuthenticationToken에 회원정보를 담아 리턴하게 됩니다.
SecurityContextHolder 에는 스프링 시큐리티로 인증을 한 사용자의 상세 정보를 저장한다.
SecurityContext 란? SecurityContextHolder 로 접근할 수 있으며 Authentication 객체를 가지고 있다.
// 예시코드
SecurityContext context = SecurityContextHolder.createEmptyContext();
Authentication authentication = new UsernamePasswordAuthenticationToken(principal, credentials, authorities);
context.setAuthentication(authentication);
SecurityContextHolder.setContext(context);
현재 인증된 사용자를 나타내며 SecurityContext 에서 가져올 수 있다.
principal : 사용자를 식별한다. Username/Password 방식으로 인증할 때 보통 UserDetails 인스턴스다.
credentials : 주로 비밀번호, 대부분 사용자 인증에 사용하고 다음 비운다.
authorities : 사용자에게 부여한 권한을 GrantedAuthority 로 추상화하여 사용한다.
<UserDetails>
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
UserRoleEnum role = user.getRole();
String authority = role.getAuthority();
System.out.println("authority = " + authority);
SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(authority);
Collection<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(simpleGrantedAuthority);
return authorities;
}
Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
UsernamePasswordAuthenticationToken는 Authentication을 implements한 AbstractAuthenticationToken의 하위 클래스로, 인증객체를 만드는데 사용된다.