나만의 라이브러리를 만들어서 배포해봅시다!
Bearer 토큰 추출을 조금 더 쉽게 할 수 없을까
로그인, 인증/인가 과정은 어느 프로젝트를 하더라도 추가하게 되기 마련인데요,
이 과정에서 Authorization Header에 담긴 Bearer 토큰을 추출해내는 코드를
매번 프로젝트에 복사 붙여넣기로 추가하는 과정이 너무 번거롭게 느껴졌습니다.
저만 느끼는 감정이 아닐 것이기에 분명 이미 만들어진 무언가가 있으리라 생각했는데,
Spring Security OAuth쪽 패키지에 DefaultBearerTokenResolver가 있는 것을 확인했습니다.
그러나 이 클래스는 특정 의존성 이 제공하는 클래스 중 하나의 구성요소여서
다른 의존성도 함께 추가할 수밖에 없다는 점과,
일부 내부 구현이 저의 사용 의도와 약간 맞지 않는 점이 있어서 아쉬움이 있었습니다.
그래서, 나만의 BearerTokenExtractor 를 만들어서,
이를 라이브러리화 하여 배포한뒤,
필요할 때 이를 의존성 추가하여 사용할 수 있으면 좋겠다고 생각하게 되었습니다.
jitpack, github를 이용한 라이브러리 배포
maven 리포지토리에 배포하는 것도 잠시 알아봤으나 절차가 상당히 복잡했습니다.
왜 그러한 절차가 필요한지에 대해선 충분히 납득되지만,
간단히 만들어서 혼자 사용하기에 편리해야한다는 관점에서는
좋은 선택지는 아니었습니다.
그래서 jitpack과 github를 이용한 배포를 선택하게 됐습니다.
jitpack을 이용한다면, 자신의 리포지토리에 라이브러리를 만들어두고
이를 간단히 배포하고, 또 가져다가 사용할 수 있습니다.
이 링크는 제가 만든 BearerExtractor 라이브러리 리포지토리입니다.
BearerExtractor 구현
private static final String AUTHORIZATION = "Authorization";
private static final Pattern VALID_TOKEN_PATTERN =
Pattern.compile("^Bearer (?<token>[a-zA-Z0-9-._~+/]+=*)$", Pattern.CASE_INSENSITIVE);
public static String resolve(final HttpServletRequest request) {
String authorization = request.getHeader(AUTHORIZATION);
if (Objects.isNull(authorization) || doesNotStartsWithBearer(authorization)) {
throw new BearerTokenNotFoundException();
}
Matcher matcher = VALID_TOKEN_PATTERN.matcher(authorization);
if (!matcher.matches()) {
throw new BearerTokenMalformedException();
}
return matcher.group("token");
}
private static boolean doesNotStartsWithBearer(final String authorization) {
return !authorization.toLowerCase().startsWith("bearer ");
}
DefaultBearerTokenResolver의 코드를 수정하여 완성하였습니다.
HttpServletRequest를 매개변수로 받아, String으로 token을 반환하는 static method를 제공합니다.
Header에 bearer 토큰이 존재하는지 검증하고,
존재한다면 유효한 형식인지 검증하며, 이 과정에서 예외를 던지기도 합니다.
유효하다면 문자열을 반환합니다.
build.gradle
apply plugin: 'java'
apply plugin: 'maven-publish'
group = 'com.github.HJ-Rich'
version = '0.1.0'
sourceCompatibility = 11
targetCompatibility = 11
repositories {
mavenCentral()
}
dependencies {
implementation 'org.apache.tomcat.embed:tomcat-embed-core:9.0.65'
testImplementation 'org.springframework.boot:spring-boot-starter-test:2.7.3'
}
java {
withSourcesJar()
withJavadocJar()
}
publishing {
publications {
maven(MavenPublication) {
from components.java
}
}
}
wrapper {
gradleVersion = "7.5"
distributionType = Wrapper.DistributionType.ALL
}
tasks.named('test') {
useJUnitPlatform()
}
jitpack의 예제를 참고하여 일부 변형하여 만들었습니다.
처음엔 의존성으로 spring-boot-starter-web을 가지고 있었는데,
사용하는 부분이 간단한 정적 메서드 두 가지만 있어서 이를 제거하고
코드로 옮기면서 의존성을 tomcat-embed-core로 줄일 수 있었습니다.
HttpServletRequest는 코드에서 사용되기 때문에 더이상 제거할 순 없었습니다.
테스트 코드 의존성도 더 줄이고 싶은 마음이 있었지만,
MockHttpServletRequest를 테스트코드에서 사용하고 있어서
이를 그대로 사용하는 것이 비용에 비해 효용이 크다 판단하여 그대로 두었습니다.
jitpack.yml
jdk: openjdk11
프로젝트 루트 경로에 jitpack.yml 이라는 파일을 만들고,
파일 내부에 위와 같은 내용을 입력해야 jdk11 버전으로 build가 수행됩니다.
jitpack은 기본적으로 빌드를 jdk 1.8로 수행하기 때문에
예외가 발생하여 배포가 정상적으로 이루어지지 않기 때문이 위 선언이 필요합니다.
관련하여 이슈 링크를 참조하실 수 있습니다.
github release
github 에서 릴리즈를 수행해야 합니다.
여기까지 완료하셨다면, 모든 준비가 끝났습니다.
jitpack.io 방문
jitpack.io 에 방문해서, github 리포지토리 주소를 입력하고 Look up을 누릅니다.
Release에 배포했던 버전이 나옵니다.
정상적으로 빌드가 수행됐다면 Status에 Get it 버튼이 초록색으로 나타나고,
그렇지 않을 경우 Log 아래 버튼이 빨간색으로, Status 가 Report로 나타납니다.
(빌드 실패 예제 로그가 보고 싶으시다면 여기를 눌러주세요)
초록색 Get it을 누르면 하단에 build.gradle에 입력해야할 내용이 나타납니다.
의존성 추가해보기
build.gradle 내 repositories 선언을 일부 수정해야했습니다.
그리고 배포했던 라이브러리를 정상적으로 가져오는데 성공했습니다.
External Libraries에도 추가가 되었고,
import도 정상적으로 수행되고 static method도 잘 동작하는 모습입니다.
후기
반복되는 패턴에 대해 개인적인 라이브러리를 만들어 배포하고, 가져다 사용하는 경험을 해봤습니다.
앞으로 개인 라이브러리를 많이 만들게 될 것 같습니다.
반복되는 내용에 대해서는 잘게 쪼개서 라이브러리화해서 사용해볼 수 있을 것 같아요!
'Java & Spring' 카테고리의 다른 글
🙌 쓰레드풀을 이용해 두 비동기 작업 처리 완료 후 후속 처리하기 (0) | 2022.09.29 |
---|---|
🥄 쓰레드풀 한 스푼 (2) | 2022.09.29 |
📦 DTO는 택배상자 (Bean Validation 검증은 누가 하나?) (3) | 2022.07.25 |
의존이 복잡하게 얽힌 Bean들은 어떻게 생성될까? (4) | 2022.07.05 |
🌱 Spring에 Handler가 등록되는 과정 (0) | 2022.06.21 |