Adds JWT-based auth with refresh tokens
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
package net.halfbinary.scavengerhuntapi.service
|
||||
|
||||
import net.halfbinary.scavengerhuntapi.repository.HunterRepository
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority
|
||||
import org.springframework.security.core.userdetails.User
|
||||
import org.springframework.security.core.userdetails.UserDetails
|
||||
import org.springframework.security.core.userdetails.UserDetailsService
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException
|
||||
import org.springframework.stereotype.Service
|
||||
import java.util.Collections
|
||||
|
||||
|
||||
@Service
|
||||
class HunterDetailsService(private val hunterRepository: HunterRepository): UserDetailsService {
|
||||
override fun loadUserByUsername(username: String): UserDetails {
|
||||
hunterRepository.findByEmail(username)
|
||||
?.let { hunter ->
|
||||
val hunterAuthorities =
|
||||
if (hunter.isAdmin) {
|
||||
SimpleGrantedAuthority("ROLE_ADMIN")
|
||||
} else {
|
||||
SimpleGrantedAuthority("ROLE_USER")
|
||||
}
|
||||
return User(
|
||||
hunter.email,
|
||||
hunter.password,
|
||||
Collections.singleton(hunterAuthorities)
|
||||
)
|
||||
}
|
||||
throw UsernameNotFoundException("User Not Found with username: $username")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package net.halfbinary.scavengerhuntapi.service
|
||||
|
||||
import net.halfbinary.scavengerhuntapi.config.JwtUtil
|
||||
import net.halfbinary.scavengerhuntapi.error.exception.ExpiredRefreshTokenException
|
||||
import net.halfbinary.scavengerhuntapi.error.exception.InvalidRefreshTokenException
|
||||
import net.halfbinary.scavengerhuntapi.model.RefreshId
|
||||
import net.halfbinary.scavengerhuntapi.model.record.RefreshTokenRecord
|
||||
import net.halfbinary.scavengerhuntapi.repository.RefreshTokenRepository
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
import org.springframework.stereotype.Service
|
||||
import java.time.LocalDateTime
|
||||
import java.time.temporal.ChronoUnit
|
||||
|
||||
@Service
|
||||
class RefreshTokenService(private val refreshTokenRepository: RefreshTokenRepository, private val jwtUtil: JwtUtil) {
|
||||
|
||||
companion object {
|
||||
private val log = LoggerFactory.getLogger(RefreshTokenService::class.java)
|
||||
}
|
||||
|
||||
fun getAccessToken(tokenId: RefreshId): String {
|
||||
return getToken(tokenId)?.let { refreshToken ->
|
||||
if (isTokenExpired(refreshToken)) {
|
||||
removeToken(tokenId)
|
||||
throw ExpiredRefreshTokenException(tokenId)
|
||||
} else {
|
||||
jwtUtil.generateToken(refreshToken.email)
|
||||
}
|
||||
}?: throw InvalidRefreshTokenException(tokenId)
|
||||
}
|
||||
|
||||
fun generateRefreshToken(email: String): RefreshId {
|
||||
return refreshTokenRepository.save(RefreshTokenRecord(RefreshId.randomUUID(), email, LocalDateTime.now().plus(1, ChronoUnit.MONTHS))).token
|
||||
}
|
||||
|
||||
fun isTokenExpired(token: RefreshTokenRecord): Boolean {
|
||||
return token.expiryDateTime.isBefore(LocalDateTime.now())
|
||||
}
|
||||
|
||||
fun getToken(token: RefreshId): RefreshTokenRecord? {
|
||||
return refreshTokenRepository.findByIdOrNull(token)
|
||||
}
|
||||
|
||||
fun removeToken(token: RefreshId) {
|
||||
log.debug("Removing refresh token: $token")
|
||||
refreshTokenRepository.deleteById(token)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user