티스토리 뷰

< 스마트폰 어플리케이션의 백엔드 api 서버를 스프링으로 제작하면서 생긴 이슈에 대해 정리하였습니다. >

 

스프링 시큐리티의 간단한 동작 과정

  1.  스프링 시큐리티는 Role에 따른 url 접근 제어를 기본으로 합니다.
  2. WebSecurityConfigurerAdapter 을 상속받은  security config 객체에서 각 url 에 요구되는 role을 기술합니다. 
  3. security config 객체에서는 원하는 url 에 원하는 filter를 걸 수 있습니다.
  4. 다수의 url 에 다수의 filter 를 걸 수 있습니다.
  5. 특정 url 에 접근하려는 user는 url 걸려있는 필터를 통과해야하며, 모든 필터를 통과한 유저는 인증된 사용자로서 SecurityContext 에 저장됩니다.

 스프링 시큐리티의 동작 원리는 추후 포스터를 나눠 업로드할 예정입니다. 

 

 

로그인한 사용자의 정보 가져오기

1. HttpServletRequestWrapper 이용

  • 원리

HttpServletRequestWrapper 는 servlet 을 통해 들어온 request 를 처리하는 다양한 기능을 제공하는 class 로서 ServletRequestWrapper 클래스를 상속받고 있습니다. 

 

HttpServletRequestWrapperspring controller의 메서드의 인자로 받아 사용할 수 있습니다.

 

HttpServletRequestWrapper 타입의 request가 Spring Security 를 사용하여 security filter 를 거치게 되면 되면 SecurityContextHolderAwareRequestWrapper 클래스로 wrapping 됩니다.

 

SecurityContextHolderAwareRequestWrapper 는 사용자의 인증과 관련된 다양한 메서드를 제공합니다.

 

SecurityContextHolderAwareRequestWrapper 가 제공하는 메서드 중 getUserPrincipal() 을 이용하면
인증이 완료된 Authentication 객체를 꺼낼 수 있고,
이런 Authentication 객체로 부터 인증이 완료된 사용자의 정보를 얻을 수 있습니다.

 

  • 코드 예제

1. 가정

  1. user가 api/account 로 끝나는 url 에 접근하기 위해서는 인증이 필요합니다.
  2. user가 인증이 완료가 되면 Spring SecurityContext 에 사용자의 정보가 저장이 됩니다.
  3. Spring SecurityContext 저장되는 정보는 사용자의 고유 id 라고 가정하겠습니다.
  4. (위의 고유 id를 통해 db에서 사용자 정보 조회 가능) ex) Account account = accountRepository.findById(Long accountId)

 

2. 코드

Controller 의 메서드에서 SecurityContextHolderAwareRequestWrapper 를 인자로 받아 사용자의 고유 id를 꺼내 service 객체로 전달하는 코드 예제입니다.

@RestController
@RequestMapping(value = "api/account", produces = {"application/json"})
@RequiredArgsConstructor
public class AccountController {
    private final AccountService accountService;

    @GetMapping("")
    public ResponseEntity<AccountDTO> getMember(
    	SecurityContextHolderAwareRequestWrapper request
    ) throws UserNotFoundException {
        Long accountId = Long.valueOf(request.getUserPrincipal().getName());
        AccountDTO accountDTO = accountService.getAccount(accountId);
        return ResponseEntity.ok().body(accountDTO);
    }
 }

 

위의 코드에서 request가 중요한 역할을 하는데,
원래라면 HttpServletRequestWrapper 객체로 들어와야할 request 이름의 parameter 는 이미,

Security filter를 전부 거치고, 인증이 완료된 사용자에 대한 정보가 들어 있는 SecurityContextHolderAwareRequestWrapper 객체로 wrapping 되어 AccountController 에 전달됩니다.

 

우리는 이러한 SecurityContextHolderAwareRequestWrapper 타입의 request 에서 이미 Security filter 가 저장한 사용자의 정보만 뽑아내어 사용하면 됩니다.

 

 

 

 

2. SecurityContext 객체 이용

  • 원리

위와 같이 Servlet  → Security FilterController  를 거쳐전달된 SecurityContextHolderAwareRequestWrapper 를 사용하지 않고,

직접 SpringSecurityContext 에서 사용자 정보를 꺼낼 수 있습니다. 

 

  • 코드 예제

1. 가정

 

위의 HttpServletRequestWrapper를 이용할때의 상황과 동일합니다.

 

2. 코드

SpringSecurity Context 에서 직접 인증된 사용자의 정보를 뽑는 코드 예제입니다.

@RestController
@RequestMapping(value = "api/account", produces = {"application/json"})
@RequiredArgsConstructor
public class AccountController {
    private final AccountService accountService;

    @GetMapping("")
    public ResponseEntity<AccountDTO> getMember() throws UserNotFoundException {
        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        Long accountId = Long.valueOf(String.valueOf(principal));
        AccountDTO accountDTO = accountService.getAccount(accountId)
        return ResponseEntity.ok().body(accountDTO);
    }
}

 

'spring' 카테고리의 다른 글

[Spring] java long type 의 json 변환 에러  (2) 2021.06.27
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함