티스토리 뷰
< 스마트폰 어플리케이션의 백엔드 api 서버를 스프링으로 제작하면서 생긴 이슈에 대해 정리하였습니다. >
스프링 시큐리티의 간단한 동작 과정
- 스프링 시큐리티는 Role에 따른 url 접근 제어를 기본으로 합니다.
- WebSecurityConfigurerAdapter 을 상속받은 security config 객체에서 각 url 에 요구되는 role을 기술합니다.
- security config 객체에서는 원하는 url 에 원하는 filter를 걸 수 있습니다.
- 다수의 url 에 다수의 filter 를 걸 수 있습니다.
- 특정 url 에 접근하려는 user는 url 걸려있는 필터를 통과해야하며, 모든 필터를 통과한 유저는 인증된 사용자로서 SecurityContext 에 저장됩니다.
스프링 시큐리티의 동작 원리는 추후 포스터를 나눠 업로드할 예정입니다.
로그인한 사용자의 정보 가져오기
1. HttpServletRequestWrapper 이용
- 원리
HttpServletRequestWrapper 는 servlet 을 통해 들어온 request 를 처리하는 다양한 기능을 제공하는 class 로서 ServletRequestWrapper 클래스를 상속받고 있습니다.
HttpServletRequestWrapper 는 spring controller의 메서드의 인자로 받아 사용할 수 있습니다.
HttpServletRequestWrapper 타입의 request가 Spring Security 를 사용하여 security filter 를 거치게 되면 되면 SecurityContextHolderAwareRequestWrapper 클래스로 wrapping 됩니다.
SecurityContextHolderAwareRequestWrapper 는 사용자의 인증과 관련된 다양한 메서드를 제공합니다.
SecurityContextHolderAwareRequestWrapper 가 제공하는 메서드 중 getUserPrincipal() 을 이용하면
인증이 완료된 Authentication 객체를 꺼낼 수 있고,
이런 Authentication 객체로 부터 인증이 완료된 사용자의 정보를 얻을 수 있습니다.
- 코드 예제
1. 가정
- user가 api/account 로 끝나는 url 에 접근하기 위해서는 인증이 필요합니다.
- user가 인증이 완료가 되면 Spring SecurityContext 에 사용자의 정보가 저장이 됩니다.
- Spring SecurityContext 저장되는 정보는 사용자의 고유 id 라고 가정하겠습니다.
- (위의 고유 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 Filter → Controller 를 거쳐전달된 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 |
---|