添加jwt支持
This commit is contained in:
parent
3ee64a5f69
commit
e2b56a654c
@ -46,11 +46,14 @@ dependencies {
|
|||||||
implementation 'org.springframework.boot:spring-boot-starter-validation'
|
implementation 'org.springframework.boot:spring-boot-starter-validation'
|
||||||
implementation "org.noelware.charted.snowflake:snowflake:0.1-beta"
|
implementation "org.noelware.charted.snowflake:snowflake:0.1-beta"
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-security'
|
implementation 'org.springframework.boot:spring-boot-starter-security'
|
||||||
|
implementation 'io.jsonwebtoken:jjwt-api:0.12.6'
|
||||||
testImplementation 'org.springframework.security:spring-security-test'
|
testImplementation 'org.springframework.security:spring-security-test'
|
||||||
compileOnly 'org.projectlombok:lombok'
|
compileOnly 'org.projectlombok:lombok'
|
||||||
annotationProcessor 'org.projectlombok:lombok'
|
annotationProcessor 'org.projectlombok:lombok'
|
||||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||||
runtimeOnly 'org.postgresql:postgresql'
|
runtimeOnly 'org.postgresql:postgresql'
|
||||||
|
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.6'
|
||||||
|
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.6'
|
||||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,10 +2,15 @@ package dev.surl.surl
|
|||||||
|
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||||
import org.springframework.boot.runApplication
|
import org.springframework.boot.runApplication
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
open class SurlApplication
|
open class SurlApplication {
|
||||||
|
companion object {
|
||||||
|
lateinit var context: ConfigurableApplicationContext
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
runApplication<SurlApplication>(*args)
|
SurlApplication.context = runApplication<SurlApplication>(*args)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,14 @@
|
|||||||
package dev.surl.surl.cfg
|
package dev.surl.surl.cfg
|
||||||
|
|
||||||
|
import io.jsonwebtoken.security.Keys
|
||||||
import org.springframework.context.annotation.Configuration
|
import org.springframework.context.annotation.Configuration
|
||||||
|
import javax.crypto.SecretKey
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
open class BaseConfiguration(val site: String = "https://surl.org")
|
open class BaseConfiguration(
|
||||||
|
val site: String = "https://surl.org",
|
||||||
|
val expire: Long = 24 * 60 * 60 * 1000,
|
||||||
|
private val secret: String = "6244a108c0599980e7971845baeb3120",
|
||||||
|
val secretKey: SecretKey = Keys.hmacShaKeyFor(secret.toByteArray()),
|
||||||
|
val tokenHead: String = "token"
|
||||||
|
)
|
||||||
|
11
src/main/java/dev/surl/surl/cfg/Logging.kt
Normal file
11
src/main/java/dev/surl/surl/cfg/Logging.kt
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package dev.surl.surl.cfg
|
||||||
|
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
import org.springframework.stereotype.Component
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
@Component
|
||||||
|
open class Logging {
|
||||||
|
fun <T: Any> logger(clazz: KClass<T>): Logger = LoggerFactory.getLogger(clazz::class.java)
|
||||||
|
}
|
@ -1,27 +1,58 @@
|
|||||||
package dev.surl.surl.cfg.security
|
package dev.surl.surl.cfg.security
|
||||||
|
|
||||||
|
import dev.surl.surl.cfg.Logging
|
||||||
|
import jakarta.servlet.FilterChain
|
||||||
|
import jakarta.servlet.http.HttpServletRequest
|
||||||
|
import jakarta.servlet.http.HttpServletResponse
|
||||||
import org.springframework.context.annotation.Bean
|
import org.springframework.context.annotation.Bean
|
||||||
import org.springframework.context.annotation.Configuration
|
import org.springframework.context.annotation.Configuration
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||||
import org.springframework.security.web.SecurityFilterChain
|
import org.springframework.security.web.SecurityFilterChain
|
||||||
import org.springframework.security.config.annotation.web.invoke
|
import org.springframework.security.config.annotation.web.invoke
|
||||||
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
open class WebSecurityConfig {
|
open class WebSecurityConfig {
|
||||||
|
/**
|
||||||
|
* 配置过滤器链
|
||||||
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
|
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
|
||||||
|
|
||||||
println("loading")
|
|
||||||
http {
|
http {
|
||||||
|
csrf { disable() } // 关闭csrf
|
||||||
authorizeHttpRequests {
|
authorizeHttpRequests {
|
||||||
authorize(anyRequest, authenticated)
|
authorize(anyRequest, permitAll)
|
||||||
}
|
}
|
||||||
formLogin { }
|
headers {
|
||||||
httpBasic {
|
cacheControl { } // 禁用缓存
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return http.build()
|
return http.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 装载BCrypt密码编码器
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
open fun passwordEncoder(): BCryptPasswordEncoder {
|
||||||
|
return BCryptPasswordEncoder()
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Bean
|
||||||
|
// open fun authenticationTokenFilter(): OncePerRequestFilter {
|
||||||
|
// return object: OncePerRequestFilter() {
|
||||||
|
// override fun doFilterInternal(
|
||||||
|
// request: HttpServletRequest,
|
||||||
|
// response: HttpServletResponse,
|
||||||
|
// filterChain: FilterChain
|
||||||
|
// ) {
|
||||||
|
// filterChain.doFilter(request, response)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package dev.surl.surl.common
|
package dev.surl.surl.common
|
||||||
|
|
||||||
data class Msg(
|
data class Msg<T>(
|
||||||
val code: Int = 0,
|
val code: Int = 0, val msg: String? = null, val value: T? = null
|
||||||
val msg: String? = null,
|
|
||||||
val value: Any? = null
|
|
||||||
)
|
)
|
@ -0,0 +1,3 @@
|
|||||||
|
package dev.surl.surl.common.exception
|
||||||
|
|
||||||
|
class UserRegistException(message: String? = null, cause: Throwable? = null): Throwable(message, cause)
|
@ -10,14 +10,14 @@ import org.springframework.http.HttpStatus
|
|||||||
import org.springframework.http.ResponseEntity
|
import org.springframework.http.ResponseEntity
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||||
import org.springframework.web.bind.annotation.GetMapping
|
import org.springframework.web.bind.annotation.GetMapping
|
||||||
import org.springframework.web.bind.annotation.PostMapping
|
|
||||||
import org.springframework.web.bind.annotation.RequestBody
|
import org.springframework.web.bind.annotation.RequestBody
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping
|
||||||
import org.springframework.web.bind.annotation.RestController
|
import org.springframework.web.bind.annotation.RestController
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
class SurlAddController {
|
class SurlAddController {
|
||||||
@PostMapping("/surl/add")
|
@RequestMapping("/surl/add")
|
||||||
fun addSurl(
|
fun addSurl(
|
||||||
@Valid @RequestBody body: Surl, @Autowired service: SurlService, @Autowired cfg: BaseConfiguration
|
@Valid @RequestBody body: Surl, @Autowired service: SurlService, @Autowired cfg: BaseConfiguration
|
||||||
): Any {
|
): Any {
|
||||||
|
19
src/main/java/dev/surl/surl/controller/UserController.kt
Normal file
19
src/main/java/dev/surl/surl/controller/UserController.kt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package dev.surl.surl.controller
|
||||||
|
|
||||||
|
import dev.surl.surl.common.Msg
|
||||||
|
import dev.surl.surl.dto.UserDto
|
||||||
|
import dev.surl.surl.service.UserService
|
||||||
|
import jakarta.validation.Valid
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping
|
||||||
|
import org.springframework.web.bind.annotation.RequestMethod
|
||||||
|
import org.springframework.web.bind.annotation.RestController
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
class UserController {
|
||||||
|
@RequestMapping(method = [RequestMethod.POST], path = ["/reg"])
|
||||||
|
fun reg(
|
||||||
|
@Autowired service: UserService, @Valid @RequestBody(required = true) user: UserDto
|
||||||
|
) = service.addUser(user.username!!, user.password!!)
|
||||||
|
}
|
@ -8,5 +8,5 @@ import org.jetbrains.exposed.dao.id.EntityID
|
|||||||
class User(id: EntityID<Long>): LongEntity(id) {
|
class User(id: EntityID<Long>): LongEntity(id) {
|
||||||
companion object EntityClass: LongEntityClass<User>(Users)
|
companion object EntityClass: LongEntityClass<User>(Users)
|
||||||
var username by Users.username
|
var username by Users.username
|
||||||
var passwd by Users.passwd
|
var password by Users.password
|
||||||
}
|
}
|
@ -5,6 +5,6 @@ import org.jetbrains.exposed.dao.id.IdTable
|
|||||||
object Users: IdTable<Long>("users") {
|
object Users: IdTable<Long>("users") {
|
||||||
override val id = long("id").entityId()
|
override val id = long("id").entityId()
|
||||||
val username = varchar("username", 256).uniqueIndex()
|
val username = varchar("username", 256).uniqueIndex()
|
||||||
val passwd = varchar("passwd", 256)
|
val password = varchar("password", 256)
|
||||||
override val primaryKey = PrimaryKey(id, name = "PK_user_id")
|
override val primaryKey = PrimaryKey(id, name = "PK_user_id")
|
||||||
}
|
}
|
17
src/main/java/dev/surl/surl/dto/UserDto.kt
Normal file
17
src/main/java/dev/surl/surl/dto/UserDto.kt
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package dev.surl.surl.dto
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
|
import jakarta.validation.constraints.NotNull
|
||||||
|
import org.hibernate.validator.constraints.Length
|
||||||
|
|
||||||
|
class UserDto (
|
||||||
|
@JsonProperty("username")
|
||||||
|
@get:Length(max = 16, min = 4, message = "username length must be between 4 and 16")
|
||||||
|
@get:NotNull(message = "username cannot be null")
|
||||||
|
val username: String?,
|
||||||
|
|
||||||
|
@JsonProperty("password")
|
||||||
|
@get:Length(max = 16, min = 8, message = "password length must be between 8 and 16")
|
||||||
|
@get:NotNull(message = "password cannot be null")
|
||||||
|
val password: String?
|
||||||
|
)
|
@ -0,0 +1,36 @@
|
|||||||
|
package dev.surl.surl.filter
|
||||||
|
//
|
||||||
|
//import dev.surl.surl.cfg.BaseConfiguration
|
||||||
|
//import dev.surl.surl.util.JwtTokenUtil
|
||||||
|
//import jakarta.servlet.FilterChain
|
||||||
|
//import jakarta.servlet.http.HttpServletRequest
|
||||||
|
//import jakarta.servlet.http.HttpServletResponse
|
||||||
|
//import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
//import org.springframework.security.core.context.SecurityContextHolder
|
||||||
|
//import org.springframework.stereotype.Component
|
||||||
|
//import org.springframework.web.filter.OncePerRequestFilter
|
||||||
|
//
|
||||||
|
//@Component
|
||||||
|
//class JwtAuthenticationFilter: OncePerRequestFilter() {
|
||||||
|
// @Autowired
|
||||||
|
// lateinit var jwtTokenUtil: JwtTokenUtil
|
||||||
|
//
|
||||||
|
// @Autowired
|
||||||
|
// lateinit var cfg: BaseConfiguration
|
||||||
|
// override fun doFilterInternal(
|
||||||
|
// request: HttpServletRequest,
|
||||||
|
// response: HttpServletResponse,
|
||||||
|
// filterChain: FilterChain
|
||||||
|
// ) {
|
||||||
|
// val token: String? = request.getHeader(cfg.tokenHead)
|
||||||
|
// if(token.isNullOrEmpty()) {
|
||||||
|
// val claims = jwtTokenUtil.getTokenClaim(token)
|
||||||
|
// if(claims != null) {
|
||||||
|
// if(!jwtTokenUtil.isTokenExpired(token) && SecurityContextHolder.getContext().authentication == null) {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// filterChain.doFilter(request, response)
|
||||||
|
// }
|
||||||
|
//}
|
18
src/main/java/dev/surl/surl/handler/AccessHandler.kt
Normal file
18
src/main/java/dev/surl/surl/handler/AccessHandler.kt
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package dev.surl.surl.handler
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest
|
||||||
|
import jakarta.servlet.http.HttpServletResponse
|
||||||
|
import org.springframework.security.access.AccessDeniedException
|
||||||
|
import org.springframework.security.web.access.AccessDeniedHandler
|
||||||
|
import org.springframework.web.bind.annotation.ControllerAdvice
|
||||||
|
|
||||||
|
@ControllerAdvice
|
||||||
|
class AccessHandler: AccessDeniedHandler {
|
||||||
|
override fun handle(
|
||||||
|
request: HttpServletRequest?,
|
||||||
|
response: HttpServletResponse?,
|
||||||
|
accessDeniedException: AccessDeniedException?
|
||||||
|
) {
|
||||||
|
response?.sendRedirect("/login")
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,12 @@
|
|||||||
package dev.surl.surl.handler
|
package dev.surl.surl.handler
|
||||||
|
|
||||||
import dev.surl.surl.common.Msg
|
import dev.surl.surl.common.Msg
|
||||||
|
import dev.surl.surl.common.exception.UserRegistException
|
||||||
import org.springframework.http.HttpHeaders
|
import org.springframework.http.HttpHeaders
|
||||||
import org.springframework.http.HttpStatus
|
import org.springframework.http.HttpStatus
|
||||||
import org.springframework.http.HttpStatusCode
|
import org.springframework.http.HttpStatusCode
|
||||||
import org.springframework.http.ResponseEntity
|
import org.springframework.http.ResponseEntity
|
||||||
|
import org.springframework.http.converter.HttpMessageNotReadableException
|
||||||
import org.springframework.validation.method.MethodValidationException
|
import org.springframework.validation.method.MethodValidationException
|
||||||
import org.springframework.web.bind.MethodArgumentNotValidException
|
import org.springframework.web.bind.MethodArgumentNotValidException
|
||||||
import org.springframework.web.bind.annotation.ControllerAdvice
|
import org.springframework.web.bind.annotation.ControllerAdvice
|
||||||
@ -17,23 +19,35 @@ class DefaultExceptionHandler : ResponseEntityExceptionHandler() {
|
|||||||
override fun handleMethodValidationException(
|
override fun handleMethodValidationException(
|
||||||
ex: MethodValidationException, headers: HttpHeaders, status: HttpStatus, request: WebRequest
|
ex: MethodValidationException, headers: HttpHeaders, status: HttpStatus, request: WebRequest
|
||||||
): ResponseEntity<Any> {
|
): ResponseEntity<Any> {
|
||||||
return ResponseEntity(Msg(code = -1, msg = ex.allValidationResults.joinToString(";")), status)
|
return ResponseEntity(Msg<String>(code = -1, msg = ex.allValidationResults.joinToString(";")), status)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleMethodArgumentNotValid(
|
override fun handleMethodArgumentNotValid(
|
||||||
ex: MethodArgumentNotValidException, headers: HttpHeaders, status: HttpStatusCode, request: WebRequest
|
ex: MethodArgumentNotValidException, headers: HttpHeaders, status: HttpStatusCode, request: WebRequest
|
||||||
): ResponseEntity<Any> {
|
): ResponseEntity<Any> {
|
||||||
return ResponseEntity(
|
return ResponseEntity(
|
||||||
Msg(code = -1, msg = ex.allErrors.joinToString(";") {
|
Msg<String>(code = -1, msg = ex.allErrors.joinToString(";") {
|
||||||
it.defaultMessage?.toString() ?: "unknown invalid method argument"
|
it.defaultMessage?.toString() ?: "unknown invalid method argument"
|
||||||
}), status
|
}), status
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun handleHttpMessageNotReadable(
|
||||||
|
ex: HttpMessageNotReadableException, headers: HttpHeaders, status: HttpStatusCode, request: WebRequest
|
||||||
|
): ResponseEntity<Any> {
|
||||||
|
return ResponseEntity(Msg<String>(code = -1, msg = ex.message ?: "unknown error"), status)
|
||||||
|
}
|
||||||
|
|
||||||
@ExceptionHandler(value = [Exception::class])
|
@ExceptionHandler(value = [Exception::class])
|
||||||
fun handleException(
|
fun handleException(
|
||||||
ex: Exception, headers: HttpHeaders, status: HttpStatusCode, request: WebRequest
|
ex: Exception
|
||||||
): ResponseEntity<Msg> {
|
): ResponseEntity<Msg<String>> {
|
||||||
return ResponseEntity(Msg(code = -1, msg = ex.message ?: "unknown error"), status)
|
return ResponseEntity(Msg(code = -1, msg = ex.message ?: "unknown error"), HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(value = [UserRegistException::class])
|
||||||
|
fun handleUserRegistException(ex: Exception, headers: HttpHeaders, status: HttpStatusCode, request: WebRequest
|
||||||
|
): ResponseEntity<Msg<String>>{
|
||||||
|
return ResponseEntity(Msg(code = -1, msg = ex.message ?: "unknown regist error"), status)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -11,10 +11,11 @@ import org.springframework.stereotype.Service
|
|||||||
class SurlService {
|
class SurlService {
|
||||||
fun addSurl(baseurl: String): String = runBlocking {
|
fun addSurl(baseurl: String): String = runBlocking {
|
||||||
val id = genSnowflakeUID()
|
val id = genSnowflakeUID()
|
||||||
Surl.new {
|
transaction {
|
||||||
this.id._value = id
|
Surl.new(id) {
|
||||||
url = baseurl
|
url = baseurl
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return@runBlocking numberToKey(id)
|
return@runBlocking numberToKey(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,43 @@
|
|||||||
package dev.surl.surl.service
|
package dev.surl.surl.service
|
||||||
|
|
||||||
class UserService
|
import dev.surl.surl.SurlApplication
|
||||||
|
import dev.surl.surl.common.Msg
|
||||||
|
import dev.surl.surl.common.exception.UserRegistException
|
||||||
|
import dev.surl.surl.dao.User
|
||||||
|
import dev.surl.surl.dsl.Users
|
||||||
|
import dev.surl.surl.util.genSnowflakeUID
|
||||||
|
import dev.surl.surl.util.numberToKey
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
|
@Service
|
||||||
|
class UserService(@Autowired private val passwordEncoder: BCryptPasswordEncoder) {
|
||||||
|
fun addUser(username: String, password: String): Msg<Any> {
|
||||||
|
// if (passwordEncoder == null) throw Exception("password encoder is null")
|
||||||
|
// val passwordEncoder = SurlApplication.context.getBean("bcryptor") as PasswordEncoder
|
||||||
|
val id = runBlocking {
|
||||||
|
genSnowflakeUID()
|
||||||
|
}
|
||||||
|
val encryptedPassword = passwordEncoder.encode(password)
|
||||||
|
transaction {
|
||||||
|
if (isUserExist(username)) {
|
||||||
|
throw UserRegistException("user is existed")
|
||||||
|
}
|
||||||
|
User.new(id) {
|
||||||
|
this.username = username
|
||||||
|
this.password = encryptedPassword
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Suppress("unused") return Msg(value = object {
|
||||||
|
val id = numberToKey(id)
|
||||||
|
val username = username
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isUserExist(username: String) = User.find {
|
||||||
|
Users.username eq username
|
||||||
|
}.toList().isNotEmpty()
|
||||||
|
}
|
75
src/main/java/dev/surl/surl/util/JwtTokenUtil.kt
Normal file
75
src/main/java/dev/surl/surl/util/JwtTokenUtil.kt
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package dev.surl.surl.util
|
||||||
|
|
||||||
|
import dev.surl.surl.cfg.BaseConfiguration
|
||||||
|
import dev.surl.surl.cfg.Logging
|
||||||
|
import io.jsonwebtoken.Claims
|
||||||
|
import io.jsonwebtoken.Jwts
|
||||||
|
import org.hibernate.validator.internal.engine.DefaultClockProvider
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties
|
||||||
|
import org.springframework.stereotype.Component
|
||||||
|
import java.time.Clock
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@ConfigurationProperties(prefix = "jwt")
|
||||||
|
class JwtTokenUtil {
|
||||||
|
@Autowired
|
||||||
|
private lateinit var cfg: BaseConfiguration
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private lateinit var logging: Logging
|
||||||
|
|
||||||
|
private val clock: Clock = DefaultClockProvider.INSTANCE.clock
|
||||||
|
|
||||||
|
fun getToken(identityId: String, authorizes: List<String>): Map<String, Any> {
|
||||||
|
val now = Date()
|
||||||
|
val expireAt = now.time + cfg.expire
|
||||||
|
val expireDate = Date(expireAt)
|
||||||
|
val token = Jwts.builder().run {
|
||||||
|
subject(identityId)
|
||||||
|
issuedAt(now)
|
||||||
|
expiration(expireDate)
|
||||||
|
signWith(cfg.secretKey)
|
||||||
|
claim("roleAuthorizes", authorizes)
|
||||||
|
compact()
|
||||||
|
}
|
||||||
|
return mapOf(
|
||||||
|
"expireAt" to expireAt,
|
||||||
|
"token" to token
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getTokenClaim(token: String?): Claims? {
|
||||||
|
if(token == null) return null
|
||||||
|
try {
|
||||||
|
return Jwts.parser().verifyWith(cfg.secretKey).build().parseSignedClaims(token).payload
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logging.logger(JwtTokenUtil::class).error("get token claim error", e)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getExpireDateFromToken(token: String): Date? {
|
||||||
|
return getClaimFromToken(token) {
|
||||||
|
it?.expiration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isTokenExpired(token: String?): Boolean {
|
||||||
|
if(token == null) return true
|
||||||
|
val expireDate = getExpireDateFromToken(token)
|
||||||
|
return if(expireDate == null) true else expireDate.time < clock.millis()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getUsernameFromToken(token: String): String? {
|
||||||
|
return getClaimFromToken(token) {
|
||||||
|
it?.subject
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <T> getClaimFromToken(token: String, resolver: (Claims?) -> T): T {
|
||||||
|
val claims = getTokenClaim(token)
|
||||||
|
return resolver(claims)
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
server:
|
server:
|
||||||
port: 18888
|
port: 18888
|
||||||
|
servlet:
|
||||||
|
context-path: /api/v1
|
||||||
spring:
|
spring:
|
||||||
profiles:
|
profiles:
|
||||||
active: default
|
active: default
|
||||||
@ -27,10 +29,6 @@ spring:
|
|||||||
exposed:
|
exposed:
|
||||||
show-sql: false
|
show-sql: false
|
||||||
generate-ddl: true
|
generate-ddl: true
|
||||||
security:
|
|
||||||
user:
|
|
||||||
name: admin
|
|
||||||
password: 123
|
|
||||||
logging:
|
logging:
|
||||||
level:
|
level:
|
||||||
root: info
|
root: info
|
||||||
|
Loading…
Reference in New Issue
Block a user