Skip to content

Commit

Permalink
Merge pull request #133 from grida-diary/main
Browse files Browse the repository at this point in the history
prod
  • Loading branch information
wwan13 authored Aug 28, 2024
2 parents ee26a46 + e44c00a commit 833e8dc
Show file tree
Hide file tree
Showing 13 changed files with 156 additions and 30 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.grida.auth

interface AuthProcessor {
fun process(code: String): AuthToken
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.grida.auth

import org.grida.error.GridaException
import org.grida.error.NotSupportedLoginPlatform
import org.springframework.stereotype.Component

@Component
class AuthProcessorSelector(
private val authProcessors: Map<String, AuthProcessor>
) {

fun select(platform: String): AuthProcessor {
return authProcessors["${platform}AuthProcessor"]
?: throw GridaException(NotSupportedLoginPlatform)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.grida.auth

data class AuthToken(
val accessToken: String,
val refreshToken: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.grida.auth

import io.wwan13.wintersecurity.jwt.TokenGenerator
import org.grida.config.TokenPayload
import org.grida.domain.user.User
import org.springframework.stereotype.Component

@Component
class AuthTokenProvider(
private val tokenGenerator: TokenGenerator
) {

fun provide(
user: User
): AuthToken {
val tokenPayload = TokenPayload(user.id, user.role)
return AuthToken(
accessToken = tokenGenerator.accessToken(tokenPayload),
refreshToken = tokenGenerator.refreshToken(tokenPayload)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package org.grida.auth

import org.grida.domain.user.LoginOption
import org.grida.domain.user.LoginPlatform
import org.grida.domain.user.UserService
import org.grida.error.GridaException
import org.grida.error.NotSupportedLoginPlatform
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component

@Component
class InternalAuthProcessor(
@Value("\${spring.profiles.active}")
private val activeProfile: String,
private val userService: UserService,
private val authTokenProvider: AuthTokenProvider
) : AuthProcessor {

override fun process(code: String): AuthToken {
validateActiveProfile()
val loginOption = LoginOption(LoginPlatform.ADMIN, code)
val user = userService.read(loginOption.identifier.toLong())

return authTokenProvider.provide(user)
}

private fun validateActiveProfile() {
if (!enableProfiles.contains(activeProfile)) {
throw throw GridaException(NotSupportedLoginPlatform)
}
}

companion object {
val enableProfiles = listOf("dev", "stag")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.grida.auth

import org.grida.domain.user.LoginOption
import org.grida.domain.user.LoginPlatform
import org.grida.domain.user.UserService
import org.grida.user.KakaoUserClient
import org.springframework.stereotype.Component

@Component
class KakaoAuthProcessor(
private val kakaoAuthClient: KakaoAuthClient,
private val kakaoUserClient: KakaoUserClient,
private val userService: UserService,
private val authTokenProvider: AuthTokenProvider
) : AuthProcessor {

override fun process(code: String): AuthToken {
val kakaoToken = kakaoAuthClient.provideAuthToken(code)
val kakaoProfile = kakaoUserClient.readUserProfile(kakaoToken.accessToken)
val loginOption = LoginOption(LoginPlatform.KAKAO, kakaoProfile.id)

val user = userService.readUserByLoginOption(loginOption)
?: userService.appendAndReturnNormalUser(kakaoProfile.name, loginOption)
return authTokenProvider.provide(user)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ class CoreApiSecurityConfig(

override fun registerAuthPatterns(registry: AuthPatternsRegistry) {
registry.apply {
uriPatterns("/api/health")
.httpMethodGet()
.permitAll()

uriPatterns("/api/v1/auth/**")
.allHttpMethods()
.permitAll()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.grida.error

import org.grida.http.BAD_REQUEST

sealed interface CoreApiErrorType : ErrorType

data object NotSupportedLoginPlatform : CoreApiErrorType {
override val httpStatusCode: Int = BAD_REQUEST
override val errorCode: String = "AUTH_PLATFORM_400_1"
override val message: String = "지원하지 않는 로그인 플랫폼 입니다."
override val logLevel: LogLevel = INFO
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
package org.grida.presentation.v1.auth

import io.wwan13.wintersecurity.jwt.TokenGenerator
import org.grida.api.ApiResponse
import org.grida.auth.KakaoAuthClient
import org.grida.config.TokenPayload
import org.grida.domain.user.LoginOption
import org.grida.domain.user.LoginPlatform
import org.grida.domain.user.UserService
import org.grida.auth.AuthProcessorSelector
import org.grida.presentation.v1.auth.dto.LoginResponse
import org.grida.user.KakaoUserClient
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
Expand All @@ -17,28 +11,17 @@ import org.springframework.web.bind.annotation.RestController
@RestController
@RequestMapping("/api/v1/auth")
class AuthController(
private val userService: UserService,
private val tokenGenerator: TokenGenerator,
private val kakaoAuthClient: KakaoAuthClient,
private val kakaoUserClient: KakaoUserClient
private val authProcessorSelector: AuthProcessorSelector
) {

@GetMapping("/kakao")
fun kakaoLogin(
@RequestParam("code") kakaoAuthCode: String
@GetMapping
fun provideAuthToken(
@RequestParam("platform") platform: String,
@RequestParam("code") code: String
): ApiResponse<LoginResponse> {
val kakaoToken = kakaoAuthClient.provideAuthToken(kakaoAuthCode)
val kakaoProfile = kakaoUserClient.readUserProfile(kakaoToken.accessToken)

val loginOption = LoginOption(LoginPlatform.KAKAO, kakaoProfile.id)
val user = userService.readUserByLoginOption(loginOption)
?: userService.appendAndReturnNormalUser(kakaoProfile.name, loginOption)

val tokenPayload = TokenPayload(user.id, user.role)
val response = LoginResponse(
accessToken = tokenGenerator.accessToken(tokenPayload),
refreshToken = tokenGenerator.refreshToken(tokenPayload)
)
val authProcessor = authProcessorSelector.select(platform)
val authToken = authProcessor.process(code)
val response = LoginResponse.from(authToken)
return ApiResponse.success(response)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.grida.presentation.v1.auth.dto

data class LoginRequest(
val code: String
)
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
package org.grida.presentation.v1.auth.dto

import org.grida.auth.AuthToken

data class LoginResponse(
val accessToken: String,
val refreshToken: String,
)
) {
companion object {
fun from(authToken: AuthToken): LoginResponse {
return LoginResponse(authToken.accessToken, authToken.refreshToken)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import org.grida.domain.base.ValueEnum
enum class LoginPlatform(
override val value: String
) : ValueEnum<LoginPlatform> {
KAKAO("카카오"),
GOOGLE("구글"),
GITHUB("깃허브");
KAKAO("kakao"),
ADMIN("admin")
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ class UserService(
return userAppender.appendAndReturnUser(user)
}

fun read(id: Long): User {
return userReader.read(id)
}

fun readUserByLoginOption(
loginOption: LoginOption
): User? {
Expand Down

0 comments on commit 833e8dc

Please sign in to comment.