Add authentication
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
package top.fatweb.api.util
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.servlet.mvc.condition.RequestCondition
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
|
||||
import top.fatweb.api.annotation.ApiVersion
|
||||
import java.lang.reflect.Method
|
||||
|
||||
class ApiResponseMappingHandlerMapping : RequestMappingHandlerMapping() {
|
||||
private val versionFlag = "{apiVersion}"
|
||||
|
||||
private fun createCondition(clazz: Class<*>): RequestCondition<ApiVersionCondition>? {
|
||||
val classRequestMapping = clazz.getAnnotation(RequestMapping::class.java)
|
||||
classRequestMapping ?: let { return null }
|
||||
val mappingUrlBuilder = StringBuilder()
|
||||
if (classRequestMapping.value.isNotEmpty()) {
|
||||
mappingUrlBuilder.append(classRequestMapping.value[0])
|
||||
}
|
||||
val mappingUrl = mappingUrlBuilder.toString()
|
||||
if (!mappingUrl.contains(versionFlag)) {
|
||||
return null
|
||||
}
|
||||
val apiVersion = clazz.getAnnotation(ApiVersion::class.java)
|
||||
|
||||
return if (apiVersion == null) ApiVersionCondition(1) else ApiVersionCondition(apiVersion.version)
|
||||
}
|
||||
|
||||
override fun getCustomMethodCondition(method: Method): RequestCondition<*>? = createCondition(method.javaClass)
|
||||
|
||||
override fun getCustomTypeCondition(handlerType: Class<*>): RequestCondition<*>? = createCondition(handlerType)
|
||||
}
|
||||
26
src/main/kotlin/top/fatweb/api/util/ApiVersionCondition.kt
Normal file
26
src/main/kotlin/top/fatweb/api/util/ApiVersionCondition.kt
Normal file
@@ -0,0 +1,26 @@
|
||||
package top.fatweb.api.util
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import org.springframework.web.servlet.mvc.condition.RequestCondition
|
||||
import java.util.regex.Pattern
|
||||
|
||||
class ApiVersionCondition(private val apiVersion: Int) : RequestCondition<ApiVersionCondition> {
|
||||
private val versionPrefixPattern: Pattern = Pattern.compile(".*v(\\d+).*")
|
||||
|
||||
override fun combine(other: ApiVersionCondition): ApiVersionCondition = ApiVersionCondition(other.apiVersion)
|
||||
|
||||
override fun getMatchingCondition(request: HttpServletRequest): ApiVersionCondition? {
|
||||
val matcher = versionPrefixPattern.matcher(request.requestURI)
|
||||
if (matcher.find()) {
|
||||
val version = matcher.group(1).toInt()
|
||||
if (version >= this.apiVersion) {
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
override fun compareTo(other: ApiVersionCondition, request: HttpServletRequest): Int =
|
||||
other.apiVersion - this.apiVersion
|
||||
}
|
||||
67
src/main/kotlin/top/fatweb/api/util/JwtUtil.kt
Normal file
67
src/main/kotlin/top/fatweb/api/util/JwtUtil.kt
Normal file
@@ -0,0 +1,67 @@
|
||||
package top.fatweb.api.util
|
||||
|
||||
import com.auth0.jwt.JWT
|
||||
import com.auth0.jwt.algorithms.Algorithm
|
||||
import com.auth0.jwt.interfaces.DecodedJWT
|
||||
import top.fatweb.api.constant.SecurityConstants
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
|
||||
object JwtUtil {
|
||||
private fun getUUID() = UUID.randomUUID().toString().replace("-", "")
|
||||
|
||||
/**
|
||||
* 生成加密后的秘钥 secretKey
|
||||
*
|
||||
* @return 密钥
|
||||
*/
|
||||
private fun generalKey(): SecretKeySpec {
|
||||
val encodeKey = Base64.getDecoder().decode(SecurityConstants.jwtKey)
|
||||
return SecretKeySpec(encodeKey, 0, encodeKey.size, "AES")
|
||||
}
|
||||
|
||||
private fun algorithm(): Algorithm = Algorithm.HMAC256(generalKey().toString())
|
||||
|
||||
/**
|
||||
* 创建 token
|
||||
*
|
||||
* @param subject token 中存放的数据(json格式)
|
||||
* @param ttl token 生存时间
|
||||
* @param timeUnit ttl 时间单位
|
||||
* @param uuid 唯一 ID
|
||||
* @return jwt 串
|
||||
*/
|
||||
fun createJwt(
|
||||
subject: String,
|
||||
ttl: Long = SecurityConstants.jwtTtl,
|
||||
timeUnit: TimeUnit = SecurityConstants.jwtTtlUnit,
|
||||
uuid: String = getUUID()
|
||||
): String? {
|
||||
val nowMillis = System.currentTimeMillis()
|
||||
val nowDate = Date(nowMillis)
|
||||
val unitTtl = (ttl * when (timeUnit) {
|
||||
TimeUnit.DAYS -> 24 * 60 * 60 * 1000
|
||||
TimeUnit.HOURS -> 60 * 60 * 1000
|
||||
TimeUnit.MINUTES -> 60 * 1000
|
||||
TimeUnit.SECONDS -> 1000
|
||||
TimeUnit.MILLISECONDS -> 1
|
||||
TimeUnit.NANOSECONDS -> 1 / 1000
|
||||
TimeUnit.MICROSECONDS -> 1 / 1000 / 1000
|
||||
})
|
||||
val expMillis = nowMillis + unitTtl
|
||||
val expDate = Date(expMillis)
|
||||
|
||||
return JWT.create().withJWTId(uuid).withSubject(subject).withIssuer(SecurityConstants.jwtIssuer)
|
||||
.withIssuedAt(nowDate).withExpiresAt(expDate).sign(algorithm())
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 jwt
|
||||
*
|
||||
* @param jwt jwt 串
|
||||
* @return 解析内容
|
||||
*/
|
||||
fun parseJwt(jwt: String): DecodedJWT =
|
||||
JWT.require(algorithm()).build().verify(jwt)
|
||||
}
|
||||
183
src/main/kotlin/top/fatweb/api/util/RedisUtil.kt
Normal file
183
src/main/kotlin/top/fatweb/api/util/RedisUtil.kt
Normal file
@@ -0,0 +1,183 @@
|
||||
package top.fatweb.api.util
|
||||
|
||||
import org.springframework.data.redis.core.BoundSetOperations
|
||||
import org.springframework.data.redis.core.RedisTemplate
|
||||
import org.springframework.stereotype.Component
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@Component
|
||||
class RedisUtil(private val redisTemplate: RedisTemplate<String, Any>) {
|
||||
/**
|
||||
* 设置有效时间
|
||||
*
|
||||
* @param key 缓存的键
|
||||
* @param timeout 超时时间
|
||||
* @param timeUnit 时间颗粒度
|
||||
* @return true=设置成功;false=设置失败
|
||||
*/
|
||||
fun setExpire(key: String, timeout: Long, timeUnit: TimeUnit = TimeUnit.SECONDS) =
|
||||
redisTemplate.expire(key, timeout, timeUnit)
|
||||
|
||||
/**
|
||||
* 获取有效时间
|
||||
*
|
||||
* @param key 缓存的键
|
||||
* @return 有效时间
|
||||
*/
|
||||
fun getExpire(key: String, timeUnit: TimeUnit = TimeUnit.SECONDS) = redisTemplate.getExpire(key, timeUnit)
|
||||
|
||||
/**
|
||||
* 判断 key 是否存在
|
||||
*
|
||||
* @param key 缓存的键
|
||||
* @return true=存在; false=不存在
|
||||
*/
|
||||
fun hasKey(key: String) = redisTemplate.hasKey(key)
|
||||
|
||||
/**
|
||||
* 获得缓存的基本对象列表
|
||||
*
|
||||
* @param pattern 字符串前缀
|
||||
* @return 对象列表
|
||||
*/
|
||||
fun keys(pattern: String): Set<String> = redisTemplate.keys(pattern)
|
||||
|
||||
/**
|
||||
* 缓存基本的对象,Integer、String、实体类等
|
||||
*
|
||||
* @param key 缓存的键
|
||||
* @param value 缓存的值
|
||||
*/
|
||||
fun setObject(key: String, value: Any) = redisTemplate.opsForValue().set(key, value)
|
||||
|
||||
/**
|
||||
* 缓存基本的对象,Integer、String、实体类等
|
||||
*
|
||||
* @param key 缓存的键
|
||||
* @param value 缓存的值
|
||||
* @param timeout 超时时间
|
||||
* @param timeUnit 时间颗粒度
|
||||
*/
|
||||
fun setObject(key: String, value: Any, timeout: Long, timeUnit: TimeUnit = TimeUnit.SECONDS) =
|
||||
redisTemplate.opsForValue().set(key, value, timeout, timeUnit)
|
||||
|
||||
|
||||
/**
|
||||
* 获得缓存的基本对象
|
||||
*
|
||||
* @param key 缓存的键
|
||||
* @return 缓存的值
|
||||
*/
|
||||
fun <T> getObject(key: String) = redisTemplate.opsForValue().get(key) as? T
|
||||
|
||||
/**
|
||||
* 删除单个对象
|
||||
*
|
||||
* @param key 缓存的键
|
||||
* @return true=删除成功;false=删除失败
|
||||
*/
|
||||
fun delObject(key: String) = redisTemplate.delete(key)
|
||||
|
||||
/**
|
||||
* 删除对象集合
|
||||
*
|
||||
* @param collection 键集合
|
||||
* @return 删除个数
|
||||
*/
|
||||
fun delObject(collection: Collection<String>) = redisTemplate.delete(collection)
|
||||
|
||||
/**
|
||||
* 缓存 List 数据
|
||||
*
|
||||
* @param key 缓存的键
|
||||
* @param dataList 缓存的 List 数据
|
||||
* @return 缓存的个数
|
||||
*/
|
||||
fun setList(key: String, dataList: List<Any>) = redisTemplate.opsForList().rightPushAll(key, dataList)
|
||||
|
||||
/**
|
||||
* 获得缓存的 List 数据
|
||||
*
|
||||
* @param key 缓存的键
|
||||
* @return 缓存的键对应的 List 数据
|
||||
*/
|
||||
fun <T> getList(key: String): List<T>? = redisTemplate.opsForList().range(key, 0, -1) as? List<T>
|
||||
|
||||
/**
|
||||
* 缓存 Set 数据
|
||||
*
|
||||
* @param key 缓存的键
|
||||
* @param dataSet 缓存的 Set 数据
|
||||
* @return 缓存数据的对象
|
||||
*/
|
||||
fun setSet(key: String, dataSet: Set<Any>): BoundSetOperations<String, Any> {
|
||||
val boundSetOps: BoundSetOperations<String, Any> = redisTemplate.boundSetOps(key)
|
||||
for (data in dataSet) {
|
||||
boundSetOps.add(data)
|
||||
}
|
||||
return boundSetOps
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的 Set 数据
|
||||
*
|
||||
* @param key 缓存的键
|
||||
* @return 缓存的键对应的 Set 数据
|
||||
*/
|
||||
fun <T> getSet(key: String): Set<T>? = redisTemplate.opsForSet().members(key) as? Set<T>
|
||||
|
||||
/**
|
||||
* 缓存 Map 数据
|
||||
*
|
||||
* @param key 缓存的键
|
||||
* @param dataMap 缓存的 Map 数据
|
||||
*/
|
||||
fun setMap(key: String, dataMap: Map<String, Any>) = redisTemplate.opsForHash<String, Any>().putAll(key, dataMap)
|
||||
|
||||
/**
|
||||
* 获得缓存的 Map 数据
|
||||
*
|
||||
* @param key 缓存的键
|
||||
* @return 缓存的键对应的 Map 数据
|
||||
*/
|
||||
fun <T> getMap(key: String): Map<String, T>? =
|
||||
redisTemplate.opsForHash<String, Any>().entries(key) as? Map<String, T>
|
||||
|
||||
/**
|
||||
* 往 Hash 中存入数据
|
||||
*
|
||||
* @param key Redis 键
|
||||
* @param hKey Hash 键
|
||||
* @param value 值
|
||||
*/
|
||||
fun setMapValue(key: String, hKey: String, value: Any) =
|
||||
redisTemplate.opsForHash<String, Any>().put(key, hKey, value)
|
||||
|
||||
/**
|
||||
* 获取 Hash 中的数据
|
||||
*
|
||||
* @param key Redis 键
|
||||
* @param hKey Hash 键
|
||||
* @return Hash 中的对象
|
||||
*/
|
||||
fun <T> getMapValue(key: String, hKey: String) = redisTemplate.opsForHash<String, T>().get(key, hKey)
|
||||
|
||||
/**
|
||||
* 删除 Hash 中的数据
|
||||
*
|
||||
* @param key Redis 键
|
||||
* @param hKey Hash 键
|
||||
*/
|
||||
fun delMapValue(key: String, hKey: String) = redisTemplate.opsForHash<String, Any>().delete(key, hKey)
|
||||
|
||||
/**
|
||||
* 获取多个 Hash 中的数据
|
||||
*
|
||||
* @param key Redis 键
|
||||
* @param hKeys Hash 键集合
|
||||
* @return Hash 对象集合
|
||||
*/
|
||||
fun <T> getMultiMapValue(key: String, hKeys: Collection<String>): List<T> =
|
||||
redisTemplate.opsForHash<String, T>().multiGet(key, hKeys)
|
||||
}
|
||||
10
src/main/kotlin/top/fatweb/api/util/WebUtil.kt
Normal file
10
src/main/kotlin/top/fatweb/api/util/WebUtil.kt
Normal file
@@ -0,0 +1,10 @@
|
||||
package top.fatweb.api.util
|
||||
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
import top.fatweb.api.entity.permission.LoginUser
|
||||
|
||||
object WebUtil {
|
||||
fun getLoginUser() = SecurityContextHolder.getContext().authentication.principal as LoginUser
|
||||
|
||||
fun getLoginUserId() = getLoginUser().user.id
|
||||
}
|
||||
Reference in New Issue
Block a user