Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JWT Verificaiton 과정을 AspectJ로 구현하여 코드 중복 제거 #76

Open
woody35545 opened this issue Oct 4, 2023 · 0 comments

Comments

@woody35545
Copy link
Member

woody35545 commented Oct 4, 2023

기존의 JWT 인가 처리 방식

기존 JWT 처리 관련 클래스

classDiagram
    Controller ..> JwtAuthorizationManager : use

    FeedJwtAuthorizationManager ..> FeedRepository : use
    MemberJwtAuthorizationManager ..> MemberRepository : use

    MemberJwtAuthorizationManager ..> JwtManager : delegate
    FeedJwtAuthorizationManager ..> JwtManager: delegate
    
    JwtAuthorizationManager <-- MemberJwtAuthorizationManager : extends
    JwtAuthorizationManager <-- FeedJwtAuthorizationManager : extends
    

    JwtManager ..> com_auth0_jwt : Dependeny


class JwtAuthorizationManager{
    << abstract >>
    + authorize(headers : HttpHeaders , entityId : String) AuthorizationResult 
    + authorize(jwtToken : String, entityId : String)* AuthorizationResult;
}

class MemberJwtAuthorizationManager{
    + authorize(jwtToken : String, memberId : String) AuthorizationResult
}

class FeedJwtAuthorizationManager{
    + authorize(jwtToken : String, feedId : String) AuthorizationResult
}

class JwtManager{
    + verifyAccessToken(..) ServiceResult
}  

class com_auth0_jwt{ 

}
Loading

기존에는 아래와 같이 컨트롤러의 메서드 내에서 AuthorizationManager를 호출하여 처리

@GetMapping("/feeds/interactionFeeds")
public ResponseObject getInteractionFeedsByMemberId(@RequestParam("memberId") String memberId,
                                                            @RequestHeader HttpHeaders headers){

        AuthorizationResult authResult = memberAuthManager.authorize(headers, memberId);
        if(authResult.isFailed())
            return ResponseObject.UNAUTHORIZED(authResult.getMessage());

        ServiceResult result = feedService.getInteractionFeedsByMemberId(memberId);

        return result.isFailed() ? ResponseObject.BAD_REQUEST(result.getData())
                : ResponseObject.OK(result.getData());
    }

Spring Security가 자주 @deprecated 되거나 바뀌어서 이로 인한 수정이 잦아질수도 있겠다고 판단되어, 인가처리가 필요한 메서드에서 직접 memberAuthManager.authorize()를 호출하여 인가처리를 위임하고 결과에 따라 Response를 반환하도록 하는 방식으로 변경하였다.
하지만 인가처리가 필요한 메서드들마다 해당 과정을 코드에 추가하다보니 지져분해진다는 느낌이 들었고, Spring Security처럼 AOP를 사용하여 어노테이션 하나로 바꿀 수 있으면 좋겠다고 생각하였다.

변경될 방식

@JwtAuthorizationRequired
@GetMapping("/feeds/interactionFeeds")
public ResponseObject getInteractionFeedsByMemberId(@RequestParam("memberId") String memberId){

        ServiceResult result = feedService.getInteractionFeedsByMemberId(memberId);

        return result.isFailed() ? ResponseObject.BAD_REQUEST(result.getData())
                : ResponseObject.OK(result.getData());
    }

위와 같이 보안 처리하는 부분이 생략되면서 각 Controller가 해야할 로직에 중심을 두기를 기대하고 있다.

JWT 인증/인가 처리를 위해 추가될 항목들

  • JwtAuthorizationRequired: 인증/인가처리를 수행할 곳에 선언할 Annotation
  • JwtAuthorizationAspect: @JwtAuthorizationRequire이 선언된 곳에 인증/인가를 수행한다.
  • JwtAuthorizationFailException: 인증 실패 시 발생할 Exception
  • GlobalJwtAuhtorizationExceptionHandler: JWT 인증/인가 처리시 발생하는 예외에 따라 적절히 Response 하기 위한 전역 핸들러(@ControllerAdvice)
classDiagram
class Controller{
	<< Any Controllers >>
}
Controller ..> JwtAuthorizationRequired : use, when mehtod needs JWT Auth

class JwtAuthorizationFailException{
    + JwtAuthorizationFailException(customMessage : String) 
}
JwtAuthorizationFailException  ..|>	Exception : extends

class JwtAuthorizationAspect{	
	<< Aspect >>
	+ authorize() void
}
JwtAuthorizationAspect ..> JwtAuthorizationRequired : target pointcut
JwtAuthorizationAspect ..> JwtManager : delegate JWT verify process
JwtAuthorizationAspect ..> JwtAuthorizationFailException : throw
class JwtAuthorizationRequired{
	<< @interface >>
}

class GlobalJwtAuhtorizationExceptionHandler{
	<< @ControllerAdvice >>
	+ JwtAuthorizationFailExceptionHandler(e : Exception) ResponseObject
}
GlobalJwtAuhtorizationExceptionHandler ..> JwtAuthorizationFailException : find handle method for
Loading

추가될 AOP 기반 JWT Authorization 절차 시퀀스

sequenceDiagram
    participant Client
    participant C as Controller;
    participant J as JwtAuthorizationAspect;
    participant JwtManager
    participant E as GlobalJwtAuhtorizationExceptionHandler;
	

	Client ->> C : 1. 인증이 필요한 API 호출
		activate C
    C ->> J : 2. @JwtAuthorizationRequired가 선언된 메서드 실행
		activate J
        deactivate C
    J ->> JwtManager : 3. JWT 인증 요청
        activate JwtManager
    JwtManager ->> JwtManager : 4. 인증 절차 수행
    JwtManager -->> J : 5. 인증 결과 반환
        deactivate JwtManager

    alt is 6. 인증 실패
    J ->> E: 6-1. throw JwtAuthorizationFailException
		activate E
        deactivate J
    E ->> E: 6-2. JwtAuthorizationFailException에 대한 Handler 호출
    E -->> Client : 6-3 UNAUTHORIZED 반환      
        deactivate E        
    end		

    alt is 7. 인증 성공
        activate J
    J ->> C : 7-1. 클라이언트가 요청했던 Controller 로직 호출
        Activate C
        deactivate J
    C ->> C : 7-2. 클라이언트가 요청한 로직 수행
    C -->> Client : 7-3. 요청한 자원 반환
		
		deactivate C
		
	end
Loading
@woody35545 woody35545 self-assigned this Oct 4, 2023
@woody35545 woody35545 changed the title 인증/인가 처리를 AOP로 구현하여 코드 중복 제거 JWT Verificaiton 과정을 AspectJ로 구현하여 코드 중복 제거 Oct 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant