Compare commits
No commits in common. "b7c087d53c66e57701dcae0e7ce8f8b4d1c566fa" and "d537ec1f76cb1f654350743859015cc95fd3093f" have entirely different histories.
b7c087d53c
...
d537ec1f76
@ -11,13 +11,12 @@ object JwtConfig {
|
|||||||
val jwtDomain = "com.ray650128"
|
val jwtDomain = "com.ray650128"
|
||||||
val jwtRealm = "pc re:dive rank table"
|
val jwtRealm = "pc re:dive rank table"
|
||||||
val jwtSecret = "secret"
|
val jwtSecret = "secret"
|
||||||
private val validityInMs = 36_000_00 * 24 // 1 day
|
//private val validityInMs = 36_000_00 * 24 // 1 day
|
||||||
//private const val validityInMs = 300000 // 5 min
|
private const val validityInMs = 300000 // 5 min
|
||||||
private val algorithm = Algorithm.HMAC512(jwtSecret)
|
private val algorithm = Algorithm.HMAC512(jwtSecret)
|
||||||
|
|
||||||
val verifier: JWTVerifier = JWT
|
val verifier: JWTVerifier = JWT
|
||||||
.require(algorithm)
|
.require(algorithm)
|
||||||
.withAudience(jwtAudience)
|
|
||||||
.withIssuer(jwtDomain)
|
.withIssuer(jwtDomain)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
@ -25,10 +24,9 @@ object JwtConfig {
|
|||||||
* Produce a token for this combination of name and password
|
* Produce a token for this combination of name and password
|
||||||
*/
|
*/
|
||||||
fun generateToken(user: User): String = JWT.create()
|
fun generateToken(user: User): String = JWT.create()
|
||||||
.withAudience(jwtAudience)
|
.withSubject("Authentication")
|
||||||
.withIssuer(jwtDomain)
|
.withIssuer(jwtDomain)
|
||||||
.withClaim("account", user.account)
|
.withClaim("account", user.account)
|
||||||
.withClaim("password", user.password)
|
|
||||||
.withExpiresAt(getExpiration()) // optional
|
.withExpiresAt(getExpiration()) // optional
|
||||||
.sign(algorithm)
|
.sign(algorithm)
|
||||||
|
|
||||||
|
|||||||
@ -1,36 +0,0 @@
|
|||||||
package com.ray650128.model.dto
|
|
||||||
|
|
||||||
import com.ray650128.model.pojo.GameCharacter
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class CharacterDto(
|
|
||||||
val _id: String? = null,
|
|
||||||
val name: String,
|
|
||||||
val imgSrc: String,
|
|
||||||
val position: Int,
|
|
||||||
val standIndex: Int,
|
|
||||||
var createAt: Long? = null,
|
|
||||||
var updatedAt: Long? = null
|
|
||||||
)
|
|
||||||
|
|
||||||
fun GameCharacter.toDto(baseUrl: String? = null): CharacterDto =
|
|
||||||
CharacterDto(
|
|
||||||
_id = this._id.toString(),
|
|
||||||
name = this.name,
|
|
||||||
imgSrc = if (baseUrl.isNullOrEmpty()) this.imgSrc else "$baseUrl${this.imgSrc}",
|
|
||||||
position = this.position,
|
|
||||||
standIndex = this.standIndex,
|
|
||||||
createAt = this.createAt,
|
|
||||||
updatedAt = this.updatedAt
|
|
||||||
)
|
|
||||||
|
|
||||||
fun CharacterDto.toGameCharacter(): GameCharacter =
|
|
||||||
GameCharacter(
|
|
||||||
name = this.name,
|
|
||||||
imgSrc = this.imgSrc,
|
|
||||||
position = this.position,
|
|
||||||
standIndex = this.standIndex,
|
|
||||||
createAt = this.createAt,
|
|
||||||
updatedAt = this.updatedAt
|
|
||||||
)
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
package com.ray650128.model.pojo
|
|
||||||
|
|
||||||
import kotlinx.serialization.Contextual
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import org.litote.kmongo.Id
|
|
||||||
import org.litote.kmongo.newId
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class GameCharacter(
|
|
||||||
@Contextual val _id: Id<GameCharacter>? = newId(),
|
|
||||||
val name: String,
|
|
||||||
val imgSrc: String,
|
|
||||||
val position: Int,
|
|
||||||
val standIndex: Int,
|
|
||||||
var createAt: Long? = null,
|
|
||||||
var updatedAt: Long? = null
|
|
||||||
)
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
package com.ray650128.model.pojo
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class NewCharacter(
|
|
||||||
val name: String,
|
|
||||||
val position: Int,
|
|
||||||
val standIndex: Int
|
|
||||||
)
|
|
||||||
@ -1,116 +1,28 @@
|
|||||||
package com.ray650128.plugins
|
package com.ray650128.plugins
|
||||||
|
|
||||||
import com.google.gson.Gson
|
import io.ktor.serialization.gson.*
|
||||||
import com.ray650128.extensions.sendBadRequest
|
import io.ktor.server.plugins.contentnegotiation.*
|
||||||
import com.ray650128.extensions.sendNotFound
|
|
||||||
import com.ray650128.extensions.sendSuccess
|
|
||||||
import com.ray650128.extensions.sendUnauthorized
|
|
||||||
import com.ray650128.model.ErrorResponse
|
|
||||||
import com.ray650128.model.User
|
|
||||||
import com.ray650128.model.dto.toDto
|
|
||||||
import com.ray650128.model.pojo.GameCharacter
|
|
||||||
import com.ray650128.model.pojo.NewCharacter
|
|
||||||
import com.ray650128.service.CharacterService
|
|
||||||
import io.ktor.http.content.*
|
|
||||||
import io.ktor.server.response.*
|
import io.ktor.server.response.*
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.*
|
||||||
import io.ktor.server.auth.*
|
import io.ktor.server.auth.*
|
||||||
import io.ktor.server.request.*
|
|
||||||
import io.ktor.server.routing.*
|
import io.ktor.server.routing.*
|
||||||
import io.ktor.server.util.*
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
fun Application.configureCharacter() {
|
fun Application.configureCharacter() {
|
||||||
routing {
|
routing {
|
||||||
route("/upload") {
|
|
||||||
get("/{name}") {
|
|
||||||
val fileName = call.parameters["name"] ?: run {
|
|
||||||
call.sendNotFound()
|
|
||||||
return@get
|
|
||||||
}
|
|
||||||
val file = File("./upload/$fileName")
|
|
||||||
if(!file.exists()) {
|
|
||||||
call.sendNotFound()
|
|
||||||
return@get
|
|
||||||
}
|
|
||||||
call.respondFile(file)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
route("/api") {
|
route("/api") {
|
||||||
route("/v1") {
|
route("/v1") {
|
||||||
get("/characters") {
|
get("/characters") {
|
||||||
val gameCharacterList = CharacterService.findAll().map(GameCharacter::toDto)
|
call.respond(mapOf("hello" to "world"))
|
||||||
call.sendSuccess(gameCharacterList)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
route("/character") {
|
route("/character") {
|
||||||
get("/{id}") {
|
get("/{id}") {
|
||||||
val id = call.parameters["id"].toString()
|
call.respond(mapOf("hello" to "world"))
|
||||||
val character = CharacterService.findById(id)?.toDto() ?: run {
|
|
||||||
call.sendNotFound()
|
|
||||||
return@get
|
|
||||||
}
|
|
||||||
call.sendSuccess(character)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
authenticate {
|
authenticate {
|
||||||
post {
|
post {
|
||||||
call.authentication.principal<User>() ?: run {
|
|
||||||
call.sendUnauthorized()
|
|
||||||
return@post
|
|
||||||
}
|
|
||||||
var characterId: String? = null
|
|
||||||
// retrieve all multipart data (suspending)
|
|
||||||
val multipart = call.receiveMultipart()
|
|
||||||
var params: NewCharacter? = null
|
|
||||||
multipart.forEachPart { part ->
|
|
||||||
// Check part type
|
|
||||||
when (part) {
|
|
||||||
is PartData.FormItem -> {
|
|
||||||
params = Gson().fromJson(part.value, NewCharacter::class.java)
|
|
||||||
println(part.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
is PartData.FileItem -> {
|
|
||||||
val extensionName = part.contentType?.contentSubtype
|
|
||||||
val name = "${System.currentTimeMillis()}.$extensionName"
|
|
||||||
val directory = File("./upload/")
|
|
||||||
if (!directory.exists()) {
|
|
||||||
directory.mkdir()
|
|
||||||
}
|
|
||||||
val file = File("${directory.path}/$name")
|
|
||||||
|
|
||||||
// use InputStream from part to save file
|
|
||||||
part.streamProvider().use { its ->
|
|
||||||
// copy the stream to the file with buffering
|
|
||||||
file.outputStream().buffered().use {
|
|
||||||
// note that this is blocking
|
|
||||||
its.copyTo(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val tmpCharacter = GameCharacter(
|
|
||||||
name = params!!.name,
|
|
||||||
imgSrc = "/upload/$name",
|
|
||||||
position = params!!.position,
|
|
||||||
standIndex = params!!.standIndex,
|
|
||||||
createAt = System.currentTimeMillis()
|
|
||||||
)
|
|
||||||
characterId = CharacterService.create(tmpCharacter).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {}
|
|
||||||
}
|
|
||||||
// make sure to dispose of the part after use to prevent leaks
|
|
||||||
part.dispose()
|
|
||||||
}
|
|
||||||
if (characterId != null) {
|
|
||||||
val data = CharacterService.findById(characterId!!)?.toDto()
|
|
||||||
call.sendSuccess(data)
|
|
||||||
} else {
|
|
||||||
call.sendBadRequest(ErrorResponse("Add material fail."))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
put {
|
put {
|
||||||
@ -118,14 +30,7 @@ fun Application.configureCharacter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
delete("/{id}") {
|
delete("/{id}") {
|
||||||
call.authentication.principal<User>() ?: run {
|
|
||||||
call.sendUnauthorized()
|
|
||||||
return@delete
|
|
||||||
}
|
|
||||||
val id = call.parameters["id"].toString()
|
|
||||||
CharacterService.deleteById(id)
|
|
||||||
val gameCharacterList = CharacterService.findAll().map(GameCharacter::toDto)
|
|
||||||
call.sendSuccess(gameCharacterList)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,6 @@ package com.ray650128.plugins
|
|||||||
import io.ktor.server.auth.*
|
import io.ktor.server.auth.*
|
||||||
import io.ktor.server.auth.jwt.*
|
import io.ktor.server.auth.jwt.*
|
||||||
import com.ray650128.JwtConfig
|
import com.ray650128.JwtConfig
|
||||||
import com.ray650128.model.User
|
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
import io.ktor.serialization.gson.*
|
import io.ktor.serialization.gson.*
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.*
|
||||||
@ -17,10 +16,8 @@ fun Application.configureModules() {
|
|||||||
realm = JwtConfig.jwtRealm
|
realm = JwtConfig.jwtRealm
|
||||||
verifier(JwtConfig.verifier)
|
verifier(JwtConfig.verifier)
|
||||||
validate { credential ->
|
validate { credential ->
|
||||||
val account = credential.payload.getClaim("account").asString()
|
if (credential.payload.audience.contains(JwtConfig.jwtAudience)) {
|
||||||
val password = credential.payload.getClaim("password").asString()
|
JWTPrincipal(credential.payload)
|
||||||
if (account != "" && password != "") {
|
|
||||||
User(account = account, password = password)
|
|
||||||
} else null
|
} else null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,8 +43,8 @@ fun Application.configureUser() {
|
|||||||
val password = md5encode(request.password)
|
val password = md5encode(request.password)
|
||||||
val user = UserService.findByLoginInfo(request.account, password)
|
val user = UserService.findByLoginInfo(request.account, password)
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
val token = JwtConfig.generateToken(user)
|
val token = JwtConfig.generateToken(request)
|
||||||
call.sendSuccess(LoginResult(user.account, token))
|
call.sendSuccess(LoginResult(request.account, token))
|
||||||
} else {
|
} else {
|
||||||
call.sendUnauthorized()
|
call.sendUnauthorized()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,45 +0,0 @@
|
|||||||
package com.ray650128.service
|
|
||||||
|
|
||||||
import com.ray650128.model.pojo.GameCharacter
|
|
||||||
import org.bson.types.ObjectId
|
|
||||||
import org.litote.kmongo.*
|
|
||||||
import org.litote.kmongo.id.toId
|
|
||||||
|
|
||||||
object CharacterService {
|
|
||||||
private val client = KMongo.createClient("mongodb://ray650128:Zx650128!@www.ray650128.com:27017")
|
|
||||||
private val database = client.getDatabase("test_system")
|
|
||||||
private val characterCollection = database.getCollection<GameCharacter>()
|
|
||||||
|
|
||||||
fun create(character: GameCharacter): Id<GameCharacter>? {
|
|
||||||
characterCollection.insertOne(character)
|
|
||||||
return character._id
|
|
||||||
}
|
|
||||||
|
|
||||||
fun findAll(): List<GameCharacter> = characterCollection.find().toList()
|
|
||||||
|
|
||||||
fun findById(id: String): GameCharacter? {
|
|
||||||
val bsonId: Id<GameCharacter> = ObjectId(id).toId()
|
|
||||||
return characterCollection.findOne(GameCharacter::_id eq bsonId)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun findByName(name: String): List<GameCharacter> {
|
|
||||||
val caseSensitiveTypeSafeFilter = GameCharacter::name regex name
|
|
||||||
return characterCollection.find(caseSensitiveTypeSafeFilter).toList()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateById(id: String, request: GameCharacter): Boolean =
|
|
||||||
findById(id)?.let { character ->
|
|
||||||
val updateResult = characterCollection.replaceOne(
|
|
||||||
character.copy(
|
|
||||||
name = request.name,
|
|
||||||
updatedAt = request.updatedAt
|
|
||||||
)
|
|
||||||
)
|
|
||||||
updateResult.modifiedCount == 1L
|
|
||||||
} ?: false
|
|
||||||
|
|
||||||
fun deleteById(id: String): Boolean {
|
|
||||||
val deleteResult = characterCollection.deleteOneById(ObjectId(id))
|
|
||||||
return deleteResult.deletedCount == 1L
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user