728x90
Controller
@GetMapping("/me") //pathVariable 로 Id를 받게 되면, 헤커가 다른 유저 정보도 알수 있게된다(보안에 취약)
suspend fun get(
@AuthToken token: String,
): MeResponse {
return MeResponse(userService.getByToken(token))
}
MeResponse
data class MeResponse(
val id: Long,
val profileUrl: String?,
val username: String,
val email: String,
val createdAt: LocalDateTime?,
val updatedAt: LocalDateTime?,
) {
companion object {
operator fun invoke(user: User) = with(user) {
MeResponse(
id = id!!,
profileUrl = if (profileUrl.isNullOrEmpty()) null else "http://localhost:9090/images/$profileUrl",
username = username,
email = email,
createdAt = createdAt,
updatedAt = updatedAt,
)
}
}
}
- PathVariable을 통해 userId 값을 받을 수도 있지만, 보안에 취약해지며, 헤커가 악의적인 방법으로 다른 사람을 user정보를 해킹할 수 있다.
- MeResponse에서는 동반 객체와 리플렉션을 이용하여, 생성자처럼 객체를 생성할 수 있다.
Service
suspend fun getByToken(token: String): User {
//캐시 조회(없으면 복호화된 값 반환)
val cacheUser = cacheManager.awaitGetOrPut(key = token, ttl = CACHE_TTL) {
//캐시가 유효하지 않은 경우 동작
val decodedJWT = JWTUtils.decode(token, jwtProperties.secret, jwtProperties.issuer)
val userId = decodedJWT.claims["userId"]?.asLong() ?: throw InvalidJwtTokenException()
get(userId)
}
return cacheUser
}
suspend fun get(userId: Long):User {
return userRepository.findById(userId) ?: throw UserNotFoundException()
}
cacheManager.awaitGetOrPut()
suspend fun awaitGetOrPut(
key: String,
ttl: Duration? = Duration.ofMinutes(5),
supplier: suspend () -> T
): T {
val now = Instant.now()
val cacheWrapper = localCache[key]
val cached = if (cacheWrapper == null) {
CacheWrapper(cached = supplier(), ttl = now.plusMillis(ttl!!.toMillis())).also {
localCache[key] = it
}
} else if (now.isAfter(cacheWrapper.ttl)) {//캐시 ttl이 지난 경우
localCache.remove(key)
CacheWrapper(
cached = supplier(),
ttl = now.plusMillis(ttl!!.toMillis())
).also { localCache[key] }
} else {
cacheWrapper
}
checkNotNull(cached.cached)
return cached.cached
}
- awaitGetOrPut 함수의 3번째 인자를 람다식으로 받아 cache 존재할 때, 람다식을 실행시키지 않는다.
- 캐시에 값이 있을경우는(else) decode를 할 필요 없이 캐시 값만 가지고 오면 된다.
- cacheWrapper 가 null일 경우
- cache에 새로 넣어주어야 한다.
- cache되어 있던 데이터의 ttl 값보다, 현재 시간이 초과되었을 경우(캐시 시간 초과)
- 기존 캐시되어 있던 데이터를 지우고, cache에 다시 넣어준다.
- cache 존재 && ttl 값보다 초과되지 않았을 경우
- 현재 cache에 있는 값을 그대로 사용한다.
- checkNotNull 함수를 통해 cache값을 잘 가지고 왔는지 확인한 뒤, 이를 반환한다(null처리를 해주었기 때문에 해당 함수 이후는 컴파일러가 반드시 값이 있는지를 알 수 있다)
728x90
'실무 프로젝트로 배우는 Kotlin & Spring > 회원 인증 서비스 개발하기' 카테고리의 다른 글
| 서비스 연동 & 프론트 연동 (0) | 2022.12.16 |
|---|---|
| 리포트 조회 / 내정보 수정 (0) | 2022.12.16 |
| 로그인과 로그아웃 (0) | 2022.12.15 |
| 회원가입 (0) | 2022.12.14 |
| JWT 기반 인증 구현 (0) | 2022.12.13 |