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

Feature: (BRD-74) 액세스토큰 인증 기능 추가 #53

Merged
merged 14 commits into from
Nov 17, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.ttasjwi.board.system.auth.domain.external.spring.security

import com.ttasjwi.board.system.auth.domain.external.spring.security.exception.InvalidAuthorizationHeaderFormatException
import jakarta.servlet.http.HttpServletRequest
import org.springframework.http.HttpHeaders

class BearerTokenResolver {

private val bearerTokenHeaderName = HttpHeaders.AUTHORIZATION

fun resolve(request: HttpServletRequest): String? {
val authorizationHeader = request.getHeader(this.bearerTokenHeaderName) ?: return null

if (!authorizationHeader.startsWith("Bearer ", ignoreCase = true)) {
throw InvalidAuthorizationHeaderFormatException()
}
return authorizationHeader.substring(7)
}
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • BearerTokenResolver 는 AuthorizationHeader 에서 "Bearere " 뒤의 문자열을 추출합니다.
  • 이 때 "Bearer "로 시작하지 않으면 예외가 발생합니다.
  • AuthorizationHeader 가 없으면 null 을 반환합니다.


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.ttasjwi.board.system.auth.domain.external.spring.security.exception

import com.ttasjwi.board.system.core.exception.CustomException
import com.ttasjwi.board.system.core.exception.ErrorStatus

class InvalidAuthorizationHeaderFormatException : CustomException(
status = ErrorStatus.UNAUTHENTICATED,
code = "Error.InvalidAuthorizationHeaderFormat",
args = emptyList(),
source = "authorizationHeader",
debugMessage = "잘못된 Authorization 헤더 형식입니다. 토큰값을 Authorization 헤더에 'Bearer [토큰값]' 형식으로 보내주세요."
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.ttasjwi.board.system.auth.domain.external.spring.security

import com.ttasjwi.board.system.auth.domain.external.spring.security.exception.InvalidAuthorizationHeaderFormatException
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import jakarta.servlet.http.HttpServletRequest
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.springframework.http.HttpHeaders

@DisplayName("BearerTokenResolver: Authorization 헤더의 Bearer 뒤에 위치한 토큰값을 분리한다.")
class BearerTokenResolverTest {
private lateinit var bearerTokenResolver: BearerTokenResolver

@BeforeEach
fun setup() {
bearerTokenResolver = BearerTokenResolver()
}

@Test
@DisplayName("헤더값이 유효하다면, 토큰값이 성공적으로 분리된다.")
fun testSuccess() {
// given
val request = mockk<HttpServletRequest>()
every { request.getHeader(HttpHeaders.AUTHORIZATION) } returns "Bearer validToken123"


// when
val token = bearerTokenResolver.resolve(request)

// then
assertThat(token).isEqualTo("validToken123")
verify { request.getHeader(HttpHeaders.AUTHORIZATION) }
}

@Test
@DisplayName("Authorization 헤더값이 없을 경우 null 이 반환된다.")
fun authorizationHeaderNull() {
// given
val request = mockk<HttpServletRequest>()
every { request.getHeader(HttpHeaders.AUTHORIZATION) } returns null

// when
val token = bearerTokenResolver.resolve(request)

// then
assertThat(token).isNull()
}

@Test
@DisplayName("Authorization 헤더값이 Bearer 로 시작하지 않으면 예외가 발생한다.")
fun testBadAuthorizationHeader() {
// given
val request = mockk<HttpServletRequest>()
every { request.getHeader(HttpHeaders.AUTHORIZATION) } returns "Basic abc123"

// when
// then
assertThrows<InvalidAuthorizationHeaderFormatException> { bearerTokenResolver.resolve(request) }
verify { request.getHeader(HttpHeaders.AUTHORIZATION) }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.ttasjwi.board.system.auth.domain.external.spring.security.exception

import com.ttasjwi.board.system.core.exception.ErrorStatus
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test

@DisplayName("InvalidAuthorizationHeaderFormatException: Authorization 헤더값 포맷이 잘못된 형식일 때 발생하는 예외")
class InvalidAuthorizationHeaderFormatExceptionTest {

@Test
@DisplayName("예외 기본값 테스트")
fun test() {
val exception = InvalidAuthorizationHeaderFormatException()

assertThat(exception.status).isEqualTo(ErrorStatus.UNAUTHENTICATED)
assertThat(exception.code).isEqualTo("Error.InvalidAuthorizationHeaderFormat")
assertThat(exception.source).isEqualTo("authorizationHeader")
assertThat(exception.args).isEmpty()
assertThat(exception.message).isEqualTo(exception.debugMessage)
assertThat(exception.cause).isNull()
assertThat(exception.debugMessage).isEqualTo("잘못된 Authorization 헤더 형식입니다. 토큰값을 Authorization 헤더에 'Bearer [토큰값]' 형식으로 보내주세요.")
}
}
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ subprojects {

implementation(Dependencies.KOTLIN_REFLECT.fullName)
testImplementation(Dependencies.SPRING_BOOT_TEST.fullName)
testImplementation(Dependencies.MOCKK.fullName)
}

tasks.getByName("bootJar") {
Expand Down
4 changes: 3 additions & 1 deletion buildSrc/src/main/kotlin/Dependencies.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ enum class Dependencies(
YAML_RESOURCE_BUNDLE(groupId = "dev.akkinoc.util", artifactId = "yaml-resource-bundle", version = "2.13.0"),

// email-format-check
COMMONS_VALIDATOR(groupId="commons-validator", artifactId ="commons-validator" , version="1.9.0");
COMMONS_VALIDATOR(groupId="commons-validator", artifactId ="commons-validator" , version="1.9.0"),

// mockk
MOCKK(groupId="io.mockk", artifactId="mockk" , version="1.13.13");

val fullName: String
get() {
Expand Down