diff --git a/src/main/kotlin/org/meogo/domain/user/domain/User.kt b/src/main/kotlin/org/meogo/domain/user/domain/User.kt new file mode 100644 index 0000000..389e9ee --- /dev/null +++ b/src/main/kotlin/org/meogo/domain/user/domain/User.kt @@ -0,0 +1,29 @@ +package org.meogo.domain.user.domain + +import org.meogo.global.base.BaseUUIDEntity +import java.util.UUID +import javax.persistence.Column +import javax.persistence.Entity +import javax.persistence.EnumType +import javax.persistence.Enumerated + +@Entity +class User( + id: UUID? = null, + + @Column(nullable = false, length = 4) + val name: String, + + @Column(name = "account_id", nullable = false, length = 15, unique = true) + val accountId: String, + + val password: String, + + @Column(name = "enrolled_school", nullable = true) + val enrolledSchool: Int? = 0, + + val profile: String? = null, + + @Enumerated(EnumType.STRING) + val role: UserRole +) : BaseUUIDEntity(id) diff --git a/src/main/kotlin/org/meogo/domain/user/domain/UserRole.kt b/src/main/kotlin/org/meogo/domain/user/domain/UserRole.kt new file mode 100644 index 0000000..e918796 --- /dev/null +++ b/src/main/kotlin/org/meogo/domain/user/domain/UserRole.kt @@ -0,0 +1,7 @@ +package org.meogo.domain.user.domain + +enum class UserRole { + MANAGER, + USER, + ADMIN +} diff --git a/src/main/kotlin/org/meogo/domain/user/exception/UserNotFoundException.kt b/src/main/kotlin/org/meogo/domain/user/exception/UserNotFoundException.kt new file mode 100644 index 0000000..d82df77 --- /dev/null +++ b/src/main/kotlin/org/meogo/domain/user/exception/UserNotFoundException.kt @@ -0,0 +1,8 @@ +package org.meogo.domain.user.exception + +import org.meogo.global.error.exception.ErrorCode +import org.meogo.global.error.exception.MeogoException + +object UserNotFoundException : MeogoException( + ErrorCode.USER_NOT_FOUND +) diff --git a/src/main/kotlin/org/meogo/domain/user/facade/UserFacade.kt b/src/main/kotlin/org/meogo/domain/user/facade/UserFacade.kt new file mode 100644 index 0000000..55340e2 --- /dev/null +++ b/src/main/kotlin/org/meogo/domain/user/facade/UserFacade.kt @@ -0,0 +1,22 @@ +package org.meogo.domain.user.facade + +import org.meogo.domain.user.domain.User +import org.meogo.domain.user.exception.UserNotFoundException +import org.meogo.domain.user.repository.UserRepository +import org.springframework.security.core.context.SecurityContextHolder +import org.springframework.stereotype.Component + +@Component +class UserFacade( + private val userRepository: UserRepository +) { + + fun currentUser(): User? { + val authentication = SecurityContextHolder.getContext().authentication + val accountId = authentication?.name + return accountId?.let { getUserByAccountId(it) } + } + + fun getUserByAccountId(accountId: String): User = + userRepository.findByAccountId(accountId) ?: throw UserNotFoundException +} diff --git a/src/main/kotlin/org/meogo/domain/user/repository/UserRepository.kt b/src/main/kotlin/org/meogo/domain/user/repository/UserRepository.kt new file mode 100644 index 0000000..77972e1 --- /dev/null +++ b/src/main/kotlin/org/meogo/domain/user/repository/UserRepository.kt @@ -0,0 +1,13 @@ +package org.meogo.domain.user.repository + +import org.meogo.domain.user.domain.User +import org.springframework.data.repository.Repository +import java.util.UUID + +interface UserRepository : Repository { + fun save(entity: User): User + + fun findByAccountId(accountId: String): User? + + fun existsByAccountId(accountId: String): Boolean +} diff --git a/src/main/kotlin/org/meogo/global/error/exception/ErrorCode.kt b/src/main/kotlin/org/meogo/global/error/exception/ErrorCode.kt index 24e843b..8885fdb 100644 --- a/src/main/kotlin/org/meogo/global/error/exception/ErrorCode.kt +++ b/src/main/kotlin/org/meogo/global/error/exception/ErrorCode.kt @@ -7,6 +7,8 @@ enum class ErrorCode( INVALID_TOKEN(401, "Invalid Token"), EXPIRED_TOKEN(401, "Expired Token"), + USER_NOT_FOUND(404, "User not found"), + // Internal Server Error INTERNAL_SERVER_ERROR(500, "Internal Server Error") } diff --git a/src/main/kotlin/org/meogo/global/jwt/JwtTokenProvider.kt b/src/main/kotlin/org/meogo/global/jwt/JwtTokenProvider.kt index 4ab1fa4..d8b82db 100644 --- a/src/main/kotlin/org/meogo/global/jwt/JwtTokenProvider.kt +++ b/src/main/kotlin/org/meogo/global/jwt/JwtTokenProvider.kt @@ -12,7 +12,6 @@ import org.meogo.global.jwt.entity.repository.RefreshTokenRepository import org.meogo.global.jwt.exception.ExpiredTokenException import org.meogo.global.jwt.exception.InvalidJwtException import org.springframework.security.authentication.UsernamePasswordAuthenticationToken -import org.springframework.security.core.userdetails.UserDetails import org.springframework.stereotype.Component import java.util.Date import javax.servlet.http.HttpServletRequest @@ -29,16 +28,17 @@ class JwtTokenProvider( } fun getToken(name: String): TokenResponse { - val accessToken: String = generateAccessToken(name, ACCESS_KEY, jwtProperties.accessExp) - val refreshToken: String = generateRefreshToken(REFRESH_KEY, jwtProperties.refreshExp) + val accessToken = generateAccessToken(name, ACCESS_KEY, jwtProperties.accessExp) + val refreshToken = generateRefreshToken(REFRESH_KEY, jwtProperties.refreshExp) refreshTokenRepository.save( RefreshToken(name, refreshToken, jwtProperties.refreshExp) ) - return TokenResponse(accessToken = accessToken, refreshToken = refreshToken) + return TokenResponse(accessToken, refreshToken) } private fun generateAccessToken(name: String, type: String, expiration: Long): String { - return Jwts.builder().signWith(SignatureAlgorithm.HS256, jwtProperties.secretKey) + return Jwts.builder() + .signWith(SignatureAlgorithm.HS256, jwtProperties.secretKey) .setSubject(name) .setHeaderParam("type", type) .setIssuedAt(Date()) @@ -47,7 +47,8 @@ class JwtTokenProvider( } private fun generateRefreshToken(type: String, ttl: Long): String { - return Jwts.builder().signWith(SignatureAlgorithm.HS256, jwtProperties.secretKey) + return Jwts.builder() + .signWith(SignatureAlgorithm.HS256, jwtProperties.secretKey) .setHeaderParam("type", type) .setIssuedAt(Date()) .setExpiration(Date(System.currentTimeMillis() + ttl * 1000)) @@ -55,40 +56,36 @@ class JwtTokenProvider( } fun resolveToken(request: HttpServletRequest): String? { - val bearer: String? = request.getHeader("Authorization") - + val bearer = request.getHeader("Authorization") return parseToken(bearer) } fun parseToken(bearerToken: String?): String? { return if (bearerToken != null && bearerToken.startsWith("Bearer ")) { - return bearerToken.replace("Bearer ", "") + bearerToken.removePrefix("Bearer ") } else { null } } fun authorization(token: String): UsernamePasswordAuthenticationToken { - return token.let { - val userDetails: UserDetails = authDetailsService.loadUserByUsername(getTokenSubject(token)) - return UsernamePasswordAuthenticationToken(userDetails, "", userDetails.authorities) - } + val userDetails = authDetailsService.loadUserByUsername(getTokenSubject(token)) + return UsernamePasswordAuthenticationToken(userDetails, "", userDetails.authorities) } - private fun getTokenSubject(subject: String): String { - return getTokenBody(subject).subject + private fun getTokenSubject(token: String): String { + return getTokenBody(token).subject } private fun getTokenBody(token: String?): Claims { return try { - Jwts.parser().setSigningKey(jwtProperties.secretKey) - .parseClaimsJws(token).body + Jwts.parser().setSigningKey(jwtProperties.secretKey).parseClaimsJws(token).body + } catch (e: ExpiredJwtException) { + throw ExpiredTokenException + } catch (e: InvalidClaimException) { + throw InvalidJwtException } catch (e: Exception) { - when (e) { - is ExpiredJwtException -> throw ExpiredTokenException - is InvalidClaimException -> throw InvalidJwtException - else -> throw InvalidJwtException - } + throw InvalidJwtException } } } diff --git a/src/test/kotlin/org/meogo/MeogoBackendApplicationTests.kt b/src/test/kotlin/org/meogo/MeogoBackendApplicationTests.kt deleted file mode 100644 index 5bc0b2d..0000000 --- a/src/test/kotlin/org/meogo/MeogoBackendApplicationTests.kt +++ /dev/null @@ -1,12 +0,0 @@ -package org.meogo - -import org.junit.jupiter.api.Test -import org.springframework.boot.test.context.SpringBootTest - -@SpringBootTest -class MeogoBackendApplicationTests { - - @Test - fun contextLoads() { - } -}