DB를 통한 토큰 발급 및 검증 2

이전 게시글이 너무 길어져서 아래에서 이어서 작성한다.

지금까지 공부한 지식을 활용해서 한번 마음대로 인증 로직을 작성할것이다. 인증 과정은 아래와 같다.

  1. 로그인 성공 시 응답으로 세션 토큰 발급
  2. 인증이 필요한 페이지에 요청 시 헤더에 담긴 세션 토큰 정보로 DB 에서 확인

 

2. 인증이 필요한 페이지에 요청 시 헤더에 담긴 세션 토큰 정보로 DB 에서 확인

ArgumentResolver 를 활용해 애노테이션 기반 인증 로직을 만든 것을 활용해보자.

애노테이션 기반 인증 로직 관련은 이 글을 참고하자.

이제 인증이 필요한 페이지에 애노테이션 @Login 을 달아서 구분하고 이 페이지에 접속 시 세션 토큰을 DB를 통해 검증한다.

 

AuthController

인증이 필요한 페이지에 애노테이션 @Login 을 달아서 구분하고 UserSession 객체에서 이름을 받아 응답값을 반환하는

컨트롤러를 만든다.

@GetMapping("/auth")
public String access(@Login UserSession session) {
    return session.getName() + " 님 안녕하세요";
}

 

AuthResolver

ArgumentResolver를 이용해 애노테이션 @Login으로 인증 로직을 실행할지 말지 구분하고 @Login이 달렸을 경우

Authorization 헤더에 담긴 세션 토큰 정보로 DB에서 사용자 확인작업을 수행한다.

올바른 요청일 시 UserSession 객체에 유저의 이름을 담아 컨트롤러에 보내준다.

@RequiredArgsConstructor
public class AuthResolver implements HandlerMethodArgumentResolver {

    private final SessionRepository sessionRepository;

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(Login.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        String accessToken = webRequest.getHeader("Authorization");
        if (accessToken == null || accessToken.isBlank()) {
            throw new UnauthorizedException();
        }
        Session session = sessionRepository.findByAccessToken(accessToken)
            .orElseThrow(() -> new UnauthorizedException());

        return new UserSession(session.getUser().getName());
    }
}

 

UserSession

@Getter
public class UserSession {

    private final String name;

    public UserSession(String name) {
        this.name = name;
    }
}

 


테스트

AuthControllerTest

data.sql 을 통해 초기 유저 데이터가 입력된걸 이용한다.

세션토큰으로 인증이 필요한 페이지에 요청 시 성공 및 실패 케이스를 작성한다.

사실 테스트에서 data.sql 이나 @Transactional 을 사용하는건 바람직하지 않지만 지금은 간단하게 테스트 해보자.

@DisplayName("검증된 세션 값으로 권한이 필요한 페이지에 요청시 접속에 성공한다.")
@Test
@Transactional
void access() throws Exception {
    // given
    User user = userRepository.findByEmailAndPassword("hyukkind@naver.com", "1234")
        .orElseThrow(() -> new InvalidSigninInformationException());
    Session session = user.addSession();

    // expected
    mockMvc.perform(
            get("/auth")
                .header("Authorization", session.getAccessToken())
                .contentType(APPLICATION_JSON)
        )
        .andDo(print())
        .andExpect(status().isOk());
}

@DisplayName("검증되지 않은 세션값으로 권한이 필요한 페이지에 요청시 실패한다.")
@Test
@Transactional
void access2() throws Exception {
    // given
    User user = userRepository.findByEmailAndPassword("hyukkind@naver.com", "1234")
        .orElseThrow(() -> new InvalidSigninInformationException());
    Session session = user.addSession();

    // expected
    mockMvc.perform(
            get("/auth")
                .header("Authorization", 1)
                .contentType(APPLICATION_JSON)
        )
        .andDo(print())
        .andExpect(status().isUnauthorized());
}

 

테스트를 수행하면 성공하며 인증 성공 시 UserSession 에 담긴 이름으로 응답이 오는걸 확인할 수 있다.

+ Recent posts