3주차 미션시 필요한 사전 지식 정리

3주차 미션을 진행하면서 인증관련 내용이 추가가 되었는데 처음 접하는 내용이라 많이 어려웠다. 스프링 시큐리티를 이용하게 되면 미션 난이도가 많이 올라가게 되어서 비록 스프링 시큐리티를 온전히 사용하지는 않았지만 그래도 어느정도 관련성은 있으므로 정리를 해두려고 한다.

1. 로그인 요청

프론트 단에서 이메일과 패스워드를 입력하여 로그인 요청을 보내면 서버에서는 이 로그인 요청을 /login/token의 경로로 보낸다.

2. AuthConfig

AuthConfig인증과 관련된 설정을 하는 곳으로 위 사진의 빨간색 부분에 의하여 /login/token으로 요청이 오면 TokenAuthenticationInterceptor를 실행시킨다.

3. TokenAuthenticationInterceptor

1) convert

로그인 요청에는 이메일과 비밀번호에 대한 정보가 들어있는데 JSON형태로 들어있다.
따라서 JSON 형태의 정보를 JAVA에 맞게 다시 재가공해야하는데 이 역할을 하는 메소드가 바로 convert이다.

위 사진의 빨간색 부분이 JSON 형식의 정보를 JAVA에 맞게 재가공해주는 코드이며,
TokenRequest 객체와 AuthenticationToken 객체는 다음과 같다.

public class TokenRequest {
    private String email;
    private String password;

    public TokenRequest(String email, String password) {
        this.email = email;
        this.password = password;
    }
}

public class AuthenticationToken {
    private String principal;
    private String credentials;

    public AuthenticationToken(String principal, String credentials) {
        this.principal = principal;
        this.credentials = credentials;
    }
}    

2) authenticate

principal은 로그인 요청 정보의 EMAIL이다.
빨간색 부분을 보면 DB에서 해당 EMAIL을 가진 회원 정보를 가져온 뒤 로그인 요청 정보의 패스워드와 회원 정보의 패스워드가 일치하는지 검증하는 코드이다.

만약 검증을 통과하였다면 DB에서 가져온 회원 정보를 Authentication 객체에 담는다.
Authentication 객체는 다음과 같다.

public class Authentication {
    private Object principal;

    public Authentication(Object principal) {
        this.principal = principal;
    }
}

정리하면 DB에서 가져온 회원 정보를 Authenticationprincipal이 가지고 있는 것이다.

3) preHandle

파란색 부분을 집중해서 보길 바란다.

  • authentication.getPrincipal()에는 회원정보가 들어있는데 이를 payload라는 변수에 담는다.

  • 그리고 JWT 라이브러리를 이용해 이 payload로 토큰을 만든다.

  • 그 다음 tokenResponse객체에 그 토큰을 담는다.

주황색 부분은 응답 Response를 보내는 부분이다.
주황색 코드로 인하여 응답으로 다음과 같은 JSON이 나가게 된다.

{accessToken : 해당 토큰 값}

여기까지가 로그인 요청을 보내고 로그인이 되는 과정이다.
로그인이 성공적으로 되면 accessToken이라는 토큰 값을 응답 받게 된다.

또한 여기까지의 과정을 인증(Authentication)의 과정이라 부른다.
즉 유저가 누구인지 확인하는 과정이라고 생각하면 되겠다.


4. 내 회원 정보 조회 요청

로그인에 성공하였다면 accessToken을 받았을 것이다.

내 회원 정보 조회 요청을 하려면 당연히 로그인이 되어있어야 한다.
따라서 내 회원 정보 조회 요청에 대한 url인 /members/me로 요청을 보내기 전에 위 사진의 빨간색 부분의 과정이 필요하다.

즉 내 회원 정보 조회 요청을 보낸 클라이언트가 응답을 받을 권한이 있는지 판단을 할 수 있는 인증 정보(토큰)를 추가해주는 것이다. 이 부분이 빨간색 부분에 해당한다.

더 자세히 말하자면 빨간색 부분이 추가된다면 요청의 헤더에 Authorization: Bearer (accessToken값) 이 추가가 되고 헤더에 이 값이 있으면 서버에서는 권한을 판단하는 과정을 처리하게 되는 것이다.

또한 이 과정을 인가(Authorization)라고 부른다.
즉 요청을 실행할 수 있는 권한 여부를 확인하는 과정이라고 생각하면 되겠다.


5. AuthConfig

AuthConfig인가와 관련된 설정 또한 하는 곳으로 위 사진의 빨간색 부분에 의하여
어떤 요청에 대해서 토큰과 관련된 권한 여부를 확인할 때 TokenSecurityContextPersistenceInterceptor가 실행된다.

6. TokenSecurityContextPersistenceInterceptor

이 코드에 대한 분석을 하기 전에 미리 알아둬야 할 것에 대해 정리를 하겠다.

  1. SecurityContextHolderSecurityContext를 담고 있는 저장 공간이라고 생각하면 된다.

  2. SecurityContext에는 Authentication을 필드로 가지고 있는데 여기에 회원의 정보를 담는다.

파란색 부분부터 설명을 하고자 한다.
파란색 부분은 accessToken이 유효한 토큰인지 검증하는 과정이다.
만약 validateToken에서 false가 나온다면 즉 이미 유효기간이 지난 토큰이라면 SecurityContext에 회원정보를 담지 않고 그냥 통과시키게 한다.

주황색 부분은 만약 accessToken이 유효한 토큰이라면 회원 정보를 담고 있는 accessToken에서 회원 정보를 추출하여 SecurityContextauthentication에 회원정보를 담는 코드이다.

빨간색 부분은 만약 SecurityContext에 이미 회원정보가 담겨있다면 파란색부분과 주황색 부분은 필요가 없으므로 그냥 통과시키는 코드이다.

여기까지가 요청이 들어왔을 때 권한이 있는지 없는지 판단하는 과정이다.
다음은 권한이 있다고 판단이 되었을 때 요청을 수행하는 과정이다.

7. @AuthenticationPrincipal

이 어노테이션은 회원 정보에 대한 객체 즉 LoginMember 객체를 얻어올 때 쉽게 도와주는 어노테이션인데 일단 이게 있다는 것만 알아두고 넘어가자 (밑에 설명이 또 나온다!)

8. AuthenticationPrincipalArgumentResolver

주황색 부분은 각 컨트롤러 메소드의 인자에 @AuthenticationPrincipal가 붙어있는지 안붙어있는지 판단하는 코드이다.

빨간색 부분이 중요한데 만약 컨트롤러 메소드의 인자에 @AuthenticationPrincipal가 붙어있다면 회원 정보가 저장되어 있는 SecurityContextAuthentication을 반환하는 코드이다.

Resolever 덕분에 @AuthenticationPrincipal를 이용하면 회원 정보에 대한 객체 즉 LoginMember 객체를 쉽게 얻어올 수 있게 되는 것이다.

9. MemberController

이제 내 회원 정보 조회에 대한 요청에 대한 응답을 내보내어야 한다.
컨트롤러 메소드 findMemberOfMine의 인자에 @AuthenticationPrincipal가 붙어 있으므로 SecurityContext에 들어있는 회원정보를 LoginMember 객체가 받게 된다.
따라서 이 LoginMember 객체의 정보를 응답값으로 보내주면 된다.

좋은 웹페이지 즐겨찾기