-
Notifications
You must be signed in to change notification settings - Fork 28
인가 과정
Donghoon Shin edited this page Nov 21, 2022
·
1 revision
- AuthMemberPrincipal 은 멤버의 권한 설정 (Interceptor)
- AccessToken 이 Null or Empty 면 ANOYMOUS (비회원 사용자)
- 토큰이 있고, 유효한 토큰이면 MEMBER
- 토큰이 있는데, 유효하지 않은 토큰이면 TokenNotValidExcetpion 발생
- MemberOnly 는 멤버만 접근할 수 있도록 함 (AOP)
- 권한을 확인해야 하기 때문에 해당 요청의 파라미터에
@AuthMemberPrincipal
필수 등록 - 권한이 MEMBER 가 아니면 MemberNotAllowedException 발생
- 권한을 확인해야 하기 때문에 해당 요청의 파라미터에
@PostMapping
@MemberOnly
public ResponseEntity<Void> create(@AuthMemberPrincipal LoginMember member,
@RequestBody LevelLogRequest levelLogRequest) {
final LevelLogResponse response = levelLogService.insertLevellogs(member.getId(), levelLogRequest);
return ResponseEntity.created(URI.create("/levellogs/" + response.getId())).build();
}
@AllArgsConstructor
public class AuthMemberPrincipalArgumentResolver implements HandlerMethodArgumentResolver {
private final JwtTokenProvider jwtTokenProvider;
private final MemberAuthorityCache memberAuthorityCache;
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(AuthMemberPrincipal.class);
}
@Override
public LoginMember resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
// 1
String credentials = AuthorizationExtractor
.extract(webRequest.getNativeRequest(HttpServletRequest.class));
// 2
if (credentials == null || credentials.isEmpty()) {
memberAuthorityCache.setAuthority(Authority.ANONYMOUS);
return new LoginMember(Authority.ANONYMOUS);
}
// 3
try {
Long id = Long.parseLong(jwtTokenProvider.extractSubject(credentials));
memberAuthorityCache.setAuthority(Authority.MEMBER);
return new LoginMember(id, Authority.MEMBER);
} catch (NumberFormatException e) {
throw new TokenNotValidException();
}
}
}
- HttpServletRequest 의 Authorization 헤더 필드에서 토큰을 추출합니다.
- Authrization 헤더 필드에 토큰이 존재한다면 credentials 변수에 할당됩니다.
- 토큰이 존재하지 않는다면 null 이 할당 됩니다.
- 비회원 사용자를 걸러냅니다.
- credentials 가 null 혹은 Empty 면 비회원 사용자입니다.
- memberAuthorityCache의 Authority 가 ANONYMOUS 로 설정됩니다.
- LoginMember 객체를 ANONYMOUS 권한으로 생성해 반환합니다.
- 회원인 사용자에 대한 검증입니다.
- 토큰을 검증하면서 회원의 id 값을 받습니다.
- 이 때, 토큰이 유효하지 않다면 예외가 발생합니다.
- memberAuthorityCache의 권한을 MEMBER로 설정합니다.
- LoginMember 객체를 MEMBER 권한으로 생성해 반환합니다.
- 토큰을 검증하면서 회원의 id 값을 받습니다.
@Component
@RequestScope
public class MemberAuthorityCache {
private Authority authority;
public Authority getAuthority() {
return authority;
}
public void setAuthority(Authority authority) {
this.authority = authority;
}
}
- 해당 요청을 한 멤버의 권한을 잠시 저장해놓는 객체입니다. (Spring Bean)
-
@Reqeust
가 선언되어 있는데, 이는 스프링 Bean 의 생명주기가를 현재 들어온 요청으로 제한하는 것입니다.(디폴트는 싱글톤) - AuthMemberPrincipalArgumentResolver 를 통해 MemberAuthorityCache 의 Authority를 설정하고, MemberOnly AOP 과정에서 이를 이용해 권한을 검증합니다.
@Aspect
@Component
@RequiredArgsConstructor
public class LoginMemberVerifier {
private final MemberAuthorityCache memberAuthorityCache;
//1
@Before("@annotation(wooteco.prolog.login.aop.MemberOnly)")
public void checkLoginMember() {
//2
final Authority authority = memberAuthorityCache.getAuthority();
if (!authority.equals(Authority.MEMBER)) {
throw new MemberNotAllowedException();
}
}
}
- Spring AOP를 통해 멤버 권한 체크를 진행합니다.
- MemberOnly 어노테이션이 존재하는 메서드의 실행전에 checkLoginMember 메서드를 실행합니다.
- AuthMemberPrincipalArgumentResolver 를 통해 설정해둔 MemberAuthorityCache 의 Authority 로 권한 체크를 합니다.
- MEMBER 권한이 아니면 예외를 발생합니다.