diff --git a/build.gradle.kts b/build.gradle.kts index 782b4e4..8842822 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -23,12 +23,11 @@ repositories { dependencies { implementation("io.ktor:ktor-server-core-jvm:$ktor_version") + implementation("io.ktor:ktor-server-cors:$ktor_version") implementation("io.ktor:ktor-server-auth-jvm:$ktor_version") implementation("io.ktor:ktor-server-auth-jwt-jvm:$ktor_version") - implementation("io.ktor:ktor-server-sessions-jvm:$ktor_version") implementation("io.ktor:ktor-server-content-negotiation-jvm:$ktor_version") implementation("io.ktor:ktor-serialization-gson-jvm:$ktor_version") - implementation("io.ktor:ktor-server-freemarker-jvm:$ktor_version") implementation("io.ktor:ktor-server-netty-jvm:$ktor_version") implementation("ch.qos.logback:logback-classic:$logback_version") testImplementation("io.ktor:ktor-server-tests-jvm:$ktor_version") diff --git a/src/main/kotlin/com/ray650128/Application.kt b/src/main/kotlin/com/ray650128/Application.kt index a926f88..b59444e 100644 --- a/src/main/kotlin/com/ray650128/Application.kt +++ b/src/main/kotlin/com/ray650128/Application.kt @@ -2,6 +2,8 @@ package com.ray650128 import io.ktor.server.application.* import com.ray650128.plugins.* +import java.security.MessageDigest +import java.security.NoSuchAlgorithmException fun main(args: Array): Unit = io.ktor.server.netty.EngineMain.main(args) @@ -10,6 +12,27 @@ fun main(args: Array): Unit = fun Application.module() { configureSecurity() configureSerialization() - configureTemplating() configureRouting() } + +fun md5encode(password: String): String { + try { + val instance: MessageDigest = MessageDigest.getInstance("MD5") // 獲取md5加密對象 + val digest:ByteArray = instance.digest(password.toByteArray()) // 對字串加密,返回字節數組 + val sb = StringBuffer() + for (b in digest) { + val i :Int = b.toInt() and 0xff // 獲取低八位有效值 + var hexString = Integer.toHexString(i) // 將整數轉化爲16進制 + if (hexString.length < 2) { + hexString = "0$hexString" // 如果是一位的話,補0 + } + sb.append(hexString) + } + return sb.toString() + + } catch (e: NoSuchAlgorithmException) { + e.printStackTrace() + } + + return "" +} diff --git a/src/main/kotlin/com/ray650128/JwtConfig.kt b/src/main/kotlin/com/ray650128/JwtConfig.kt index 63f7c95..1de625b 100644 --- a/src/main/kotlin/com/ray650128/JwtConfig.kt +++ b/src/main/kotlin/com/ray650128/JwtConfig.kt @@ -7,16 +7,17 @@ import com.ray650128.model.User import java.util.* object JwtConfig { - val secret = "my-secret" - val issuer = "com.ray650128" - val myRealm = "com.ray650128" + val jwtAudience = "jwt-audience" + val jwtDomain = "com.ray650128" + val jwtRealm = "pc re:dive rank table" + val jwtSecret = "secret" //private val validityInMs = 36_000_00 * 24 // 1 day - private val validityInMs = 300000 // 5 min - private val algorithm = Algorithm.HMAC512(secret) + private const val validityInMs = 300000 // 5 min + private val algorithm = Algorithm.HMAC512(jwtSecret) val verifier: JWTVerifier = JWT .require(algorithm) - .withIssuer(issuer) + .withIssuer(jwtDomain) .build() /** @@ -24,7 +25,7 @@ object JwtConfig { */ fun generateToken(user: User): String = JWT.create() .withSubject("Authentication") - .withIssuer(issuer) + .withIssuer(jwtDomain) .withClaim("account", user.account) .withExpiresAt(getExpiration()) // optional .sign(algorithm) diff --git a/src/main/kotlin/com/ray650128/plugins/Routing.kt b/src/main/kotlin/com/ray650128/plugins/Routing.kt index 3ca0c76..dfd1867 100644 --- a/src/main/kotlin/com/ray650128/plugins/Routing.kt +++ b/src/main/kotlin/com/ray650128/plugins/Routing.kt @@ -1,21 +1,38 @@ package com.ray650128.plugins import com.ray650128.JwtConfig -import com.ray650128.extensions.sendBadRequest -import com.ray650128.extensions.sendCreated -import com.ray650128.extensions.sendSuccess -import com.ray650128.extensions.sendUnauthorized +import com.ray650128.extensions.* +import com.ray650128.md5encode import com.ray650128.model.ErrorResponse import com.ray650128.model.LoginResult import com.ray650128.model.User import com.ray650128.service.UserService +import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.auth.* +import io.ktor.server.plugins.cors.routing.* import io.ktor.server.request.* +import io.ktor.server.response.* import io.ktor.server.routing.* +import java.io.File fun Application.configureRouting() { + install(CORS) { + allowHeader(HttpHeaders.AccessControlAllowOrigin) + allowHeader(HttpHeaders.Accept) + allowHeader(HttpHeaders.ContentType) + anyHost() + allowMethod(HttpMethod.Options) + allowMethod(HttpMethod.Get) + allowMethod(HttpMethod.Post) + allowMethod(HttpMethod.Put) + allowMethod(HttpMethod.Delete) + allowHeader(HttpHeaders.Authorization) + allowCredentials = true + allowNonSimpleContentTypes = true + } + routing { route("/api") { route("/v1") { @@ -26,9 +43,11 @@ fun Application.configureRouting() { return@post } val newToken = JwtConfig.generateToken(request) - val user = request.apply { + val user = User( + account = request.account, + password = md5encode(request.password), createAt = System.currentTimeMillis() - } + ) UserService.create(user)?.let { userId -> call.response.headers.append("My-User-Id-Header", userId.toString()) call.sendCreated(LoginResult(request.account, newToken)) @@ -37,12 +56,13 @@ fun Application.configureRouting() { post("/login") { val request = call.receive() - val user = UserService.findByLoginInfo(request.account, request.password) + val password = md5encode(request.password) + val user = UserService.findByLoginInfo(request.account, password) if (user != null) { val token = JwtConfig.generateToken(request) call.sendSuccess(LoginResult(request.account, token)) } else { - call.sendBadRequest(ErrorResponse("Account or Password wrong.")) + call.sendUnauthorized() } } diff --git a/src/main/kotlin/com/ray650128/plugins/Security.kt b/src/main/kotlin/com/ray650128/plugins/Security.kt index 7e22ae5..6210b69 100644 --- a/src/main/kotlin/com/ray650128/plugins/Security.kt +++ b/src/main/kotlin/com/ray650128/plugins/Security.kt @@ -4,6 +4,7 @@ import io.ktor.server.auth.* import io.ktor.server.auth.jwt.* import com.auth0.jwt.JWT import com.auth0.jwt.algorithms.Algorithm +import com.ray650128.JwtConfig import io.ktor.server.sessions.* import io.ktor.server.response.* import io.ktor.server.application.* @@ -11,37 +12,15 @@ import io.ktor.server.routing.* fun Application.configureSecurity() { - // Please read the jwt property from the config file if you are using EngineMain - val jwtAudience = "jwt-audience" - val jwtDomain = "https://jwt-provider-domain/" - val jwtRealm = "ktor sample app" - val jwtSecret = "secret" authentication { jwt { - realm = jwtRealm - verifier( - JWT - .require(Algorithm.HMAC256(jwtSecret)) - .withAudience(jwtAudience) - .withIssuer(jwtDomain) - .build() - ) + realm = JwtConfig.jwtRealm + verifier(JwtConfig.verifier) validate { credential -> - if (credential.payload.audience.contains(jwtAudience)) JWTPrincipal(credential.payload) else null + if (credential.payload.audience.contains(JwtConfig.jwtAudience)) { + JWTPrincipal(credential.payload) + } else null } } } - data class MySession(val count: Int = 0) - install(Sessions) { - cookie("MY_SESSION") { - cookie.extensions["SameSite"] = "lax" - } - } - routing { - get("/session/increment") { - val session = call.sessions.get() ?: MySession() - call.sessions.set(session.copy(count = session.count + 1)) - call.respondText("Counter is ${session.count}. Refresh to increment.") - } - } } diff --git a/src/main/kotlin/com/ray650128/plugins/Templating.kt b/src/main/kotlin/com/ray650128/plugins/Templating.kt deleted file mode 100644 index 8e1b0e3..0000000 --- a/src/main/kotlin/com/ray650128/plugins/Templating.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.ray650128.plugins - -import freemarker.cache.* -import io.ktor.server.freemarker.* -import io.ktor.server.response.* -import io.ktor.server.application.* -import io.ktor.server.routing.* - -fun Application.configureTemplating() { - install(FreeMarker) { - templateLoader = ClassTemplateLoader(this::class.java.classLoader, "templates") - } - routing { - get("/html-freemarker") { - call.respond(FreeMarkerContent("index.ftl", mapOf("data" to IndexData(listOf(1, 2, 3))), "")) - } - } -} - -data class IndexData(val items: List) diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index 9bb9b45..2b1035d 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -7,8 +7,3 @@ ktor { modules = [ com.ray650128.ApplicationKt.module ] } } -jwt { - domain = "https://jwt-provider-domain/" - audience = "jwt-audience" - realm = "ktor sample app" -} diff --git a/src/main/resources/templates/index.ftl b/src/main/resources/templates/index.ftl deleted file mode 100644 index 47236b7..0000000 --- a/src/main/resources/templates/index.ftl +++ /dev/null @@ -1,8 +0,0 @@ - - -

Items:

-<#list data.items as item> -

The item at index ${item?index} is ${item}

- - -