0. 시작하게 된 계기 및 다짐 😮

  • 이번 코드스테이츠의 백엔드 엔지니어링 개발자 부트캠프에 참여하게 되면서 현직개발자 분들의 빠른 성장을 위한 조언 중 자신만의 블로그를 이용하여 배운 것 들을 정리하는게 많은 도움이 된다 하여 시작하게 되었다.

    • 그 날 배웠던 것을 길지 않아도 좋으니 정리하며 복습하는 습관 기르기
    • 주말에 다음주에 배울 내용들을 예습
    • 코딩 문제와 java코드들은 꾸준히 학습
    • 자료구조를 이용한 알고리즘 문제 해결 학습

1. 학습 목표 😮

목표결과
Spring Security 인가 처리 과정 이해O
Spring Security의 인가 처리과정 학습O
Spring Rest Docs를 위한 기본 설정 및 사용 방법을 이해O
Spring Rest Docs를 사용해서 API 문서를 생성 및 배포O

2. 정리 😮




< Spring Security 인가 구성요소 이해 >

Spring Security의 인가 처리 흐름

0. Authorization - 인가

  • 인증 된 사용자가 특정 자원에 접근하고자 할 때, 접근 할 자격이 되는지 증명하는 것
  • 인증 받은 사용자라면, 해당 자격(권한)이 있는지 확인



1. Overview

1). 사용자가 HTTP 요청을 합니다.

2). FilterSecurityInterceptor는 SecurityContextHolder로부터 Authentication을 얻습니다.

3). FilterSecurityInterceptor는 FilterInvocation을 생성합니다,

4). FilterInvocation을 SecurityMetadataSource에 전달하고 ConfigAttribute를 생성합니다. ConfigAttribute는 다수가 존재할 수 있습니다.
[권한이 없을시, 권한 심사 없이 자원 접근 허용]

5). Authentication, ConfigAttribute를 AccessDecisionManager로 전달합니다.

6). AccessDecisionManager는 decide(Authentication, Collection) 메소드를 호출하여 AccessDecisionVoter에 처리를 위임합니다. AccessDecisionVoter 또한 여러개일 수 있습니다.

7). 각 AccessDecisionVoter는 vote() 메소드를 호출하여 해당 Authentication의 Authorities 와 ConfigAttribute 목록들을 비교하여 접근 권한을 부여하거나 제한합니다.

- 7-1. 권한이 존재하는 경우 AccessDecisionManager에 ACCESS_GRANTED를 전달합니다.
- 7-2. 권한이 존재하지 않는 경우 AccessDeniedException 예외를 발생시킵니다.



2. FilterSecurityInterceptor

  • 인가 처리 담당 필터로써, 사용자에 대한 특정 요청의 '승인' 및 '거부' 결정
  • 인증 객체 없이 접근시도(AuthenticationException), 권한이 없을시(AccessDeniedException)
  • 권한 제어 방식 중 HTTP 자원의 보안을 처리하는 필터
  • 권한 처리를 AccessDecisionManager에게 맡긴다.
  • 'FilterInvocation'을 생성



3. FilterInvocation

  • 사용자가 어떤 URL을 입력하였는지 알아내는 메소드



4. SecurityMetadataSource

  • 자원에 대한 권한을 매핑한 정보를 가지고 있는 클래스로, 이를 이용하여 권한 정보 유무 판단
  • ConfigAttribute(체크할 내용)타입으로 해당 요구 리소스에 대한 권한 정보를 가져옴



5. AccessDecisionManager

  • 인터페이스로 인증,요청,권한 정보를 이용하여 사용자의 자원 접근/허용 거부의 최종 주체

  • 여러 개의 Voter(AccessDecisionVoter)을 가질 수 있고 이를 통해 각각 접근 허용/거부등의 값을 리턴받음

  • decide()메소드를 호출하여 AccessDecisionVoter에 처리를 위임한다. 여러개 일 수 있음

  • AccessDecisionVoter는 vote() 메소드를 통해 Authentication의 Authorities, FilterInvocation, ConfigAttribute 목록들을 비교하여 접근 권한을 부여하거나 제한

    1). AffirmativeBased : Voter들 중 하나라도 통과하면 허가 , 'Or'
    2). ConsensusBased : Voter들의 통과 개수에 따라 다수결로 결정
    3). UnanimousBased : 'And'와 같음



6. AccessDecisionVoter

  • 사용자의 요청마다 접근 권한 판단 후 AccessDecisionManager에게 반환하는 역할
  • Authentication(인증정보), FilterInvocator(요청 정보), ConfigAttributes(권한 정보)를 기반으로 판단



Authorization Architecture

1. Overview

1). 사용자가 자원 접근(Request)

2). FilterSecurityInterceptor에서 요청을 받아서 인증여부를 확인한다.
- 인증객체를 가지고 있는지 확인한다.
- 인증객체가 없으면(null) AuthenticationException 발생
- ExceptionTranslationFilter에서 해당 예외를 받아서 다시 로그인 페이지로 이동하던가 후처리를 해준다.

3). 인증객체가 있을 경우 SecurityMetadataSource는 자원에 접근하기 위해 설정된 권한정보를 조회해서 전달해준다.
- 권한 정보를 조회한다.
- 권한정보가 없으면(null) 권한 심사를 하지 않고 자원 접근을 허용한다.

4). 권한 정보가 있을 경우 AccessDecisionManager 에게 권한 정보를 전달하여 위임한다.
- AccessDecisionManager는 최종 심의 결정자다.

5). AccessDecisionManager가 내부적으로 AccessDecisionVoter(심의자)를 통해서 심의 요청을 한다.

6). 반환된 승인/거부 결과를 가지고 사용자가 해당 자원에 접근이 가능한지 판단한다.
- 접근이 거부되었을 경우 AccessDeniedException이 발생한다.
- ExceptionTranslationFilter에서 해당 예외를 받아서 다시 로그인 페이지로 이동하던가 후처리를 해준다.

7). 접근이 승인되었을 경우 자원 접근이 허용된다.



2. Authorities

  • Authentication에서는 모든 '인증'구현체가 각 GrantedAuthority 객체 리스트로 받은 권한들

    1). GrantedAuthority

    • principal(사용자)에게 부여된 권한

    2). 인증

    • AuthenticationManager가 Authentication 객체에 설정

    3). 인가

    • AccessDecisionManager가 Authentication 객체에서 GrantedAuthority를 꺼내서 접근 권한을 결정
    • String으로 조회하고, 복잡한 케이스의 경우 null을 리턴하고 이는,
      AccessDecisionManager에 구체적인 코드가 있어야함을 의미
    • 한가지 GrantedAuthority 구현체와 SimpleGrantedAuthority를 제공
    • AuthenticationProvider는 Authentication객체에 값을 채울 때 SimpleGrantedAuthority(String형태 권한 문자열)사용



3. Pre-Invocation Handling

  • '웹 요청 같은 보안 객체'에 대한 접근을 제어하는 인터셉터 제공

  • 허용할지 말지는 결정하는 pre-invocation 결정은 AccessDecisionManager에서 결정



4. AccessDecisionManager

  • AbstractSecurityIneterceptor(FilterSecurityInterceptor 의 부모클래스)에서 호출되며, 최종적 접근 제어 결정

    1). decide 메소드

    • 권한 부여하기 위한 결정을 내리는 데 필요한 모든 정보(Authentication(인증정보), secureObject(요청 정보), Collection(권한 정보 컬렉션))가 메서드에 전달됨
    • AccessDecisionVoter에 처리를 위임

    2). supports(ConfigAttribute)

    • 기동 시점에 AbstractSecurityInterceptor가 호출하며 AccessDecisionManager가 전달된 ConfigAttribute(권한 문자열)의 처리 가능 여부를 결정

    3). supports(class)

    • SecureObject(요청 정조)의 Type을 지원하는 Manager, 즉 처리가 가능한지 확인

    4). 그 외 정보

    • Voting-Based AccessDecisionManager Implementations
    • RoleVoter
    • AuthenticatedVoter
    • Custom Voters



5. After Invocation Handling

1). 실제로 보안 객체가 리턴하는 객체를 바꿔야 하는 애플리케이션
- 직접 AOP 관심사를 구현해도 되지만, ACL 기능과 통합되는 몇 가지 구현체를 가진 훅도 제공

2). 그 외
- After Invocation Implementations
- Hierarchical Roles




2. 서블릿 아키텍처와 구현체를 기반으로 권한 부여

  1. 사진

  2. OverView

    0). FilterSecurityInterceptor는 HttpServletRequest를 사용해서 권한을 인가하고,
    인터셉터는 FilterChainProxy에 하나의 보안 필터로 추가

    1). FilterSecurityInterceptor가 SecurityContextHolder에서 Authenticaion 객체를 얻는다.

    2). FilterSecurityInterceptor가 넘겨받은 HttpServletRequest, HttpServletResponse, FilterChain으로 FilterInvocation을 생성한다

    3). ConfigAttributes를 얻기 위해 FilterInvocation을 SecurityMetadataSource에 전달한다.

    4). Authentication, FilterInvocation, ConfigAttribute를 AccessDecisionManager로 전달한다.
    - 인가 거절 → AccessDeniedException 예외를 던진다. (ExceptionTranslationFilter가 처리한다.)
    - 인가 승인 → FilterSecurityInterceptor는 일반적인 애플리케이션 프로세스를 실행할 수 있도록 FilterCahin을 이어간다.

2. 스프링 시큐리티에서 권한을 인가하려면, 기본적으로 모든 요청을 인증해야 한다.

[예제 Code]

http
		// ...
		.authorizeRequests(authorize -> authorize
				.anyRequest().authenticated()
		);



3. 표현식 기반 접근 제어

  1. Expression-Based Access Control
  • 스프링 시큐리티 3.0부터 간단한 설정 속성과 voter로 접근 권한을 결정하는 방법 외에도 스프링 EL 표현식을 사용해 인가 메커니즘을 구현 가능
  • 동일한 아키텍처를 사용하지만, 표현식 기반 접근 제어할 땐 복잡한 Boolean 로직을 간단한 표현식 하나로 캡슐화가능



  1. OverView



  1. 메서드 보안 표현식
  • 표현식을 종합적으로 지원하기 위한 새로운 애너테이션 도입

  • 사전/사후 권한 체크를 지원하고 제출한 컬렉션 인자나 리턴한 값을 필터링 할 수 있음

    1). @Pre

    2). @Post

    3). @PreAuthorize

    • 메소드가 실행되기 전에 검사
    • 실제로 해당 메서드를 호출할 권한이 있는지를 확인한다.

[예제Code]

@PreAuthorize("#contact.name == authentication.name")
public void doSomething(Contact contact);

4). @PostAuthorize
- 메소드가 실행 된 이후에 실행됨
- 메소드가 실행 된 이후의 return 값을 활용할 수 있음
- returnObject 예약어로 리턴 객체에 접근할 수 있음

[예제Code]

@PostAuthorize("isAuthenticated() and (( returnObject.name == principal.name ) or hasRole('ROLE_ADMIN'))")
@RequestMapping( value = "/{seq}", method = RequestMethod.GET )
public User getuser( @PathVariable("seq") long seq ){
    return userService.findOne(seq);
}

5). @PreFilter

6). @PostFilter




3. 피드백 😮

  • Spring Security의 인증정보를 바탕으로 인가(권한정보부여)하는 과정을 학습하였다.


  • Authentication, ConfigAttribute, FilterInvocator를 바탕으로 이 사람에게 권한 정보를 부가 할지 말지를 결정


  • AccessDecisionManager에서 내부적으로 AccessDesisionVotor를 통해 심의를 하고 최종 결정

4. 앞으로 해야 될 것 😮

  • 매일 꾸준히 할 것
    • 꾸준히 velog 작성
    • Java 언어 및 Algorithm 공부(Coding-Test)
    • 틈틈히 운동 하기

  • 내일 해야 할 것
    • Spring JWT 인증
profile
Will be great Backend-developer

0개의 댓글