feat: サンプルの値を使ってJWTでログイントークンを発行できるように

This commit is contained in:
usbharu 2023-04-30 17:05:10 +09:00
parent 19dc00236f
commit aad86a31a5
Signed by: usbharu
GPG Key ID: 6556747BF94EEBC8
5 changed files with 91 additions and 10 deletions

View File

@ -97,6 +97,7 @@ fun Application.parent() {
configureMonitoring()
configureSerialization()
register(inject<IUserService>().value)
configureSecurity(inject<IUserAuthService>().value)
configureRouting(
inject<HttpSignatureVerifyService>().value,
inject<ActivityPubService>().value,

View File

@ -0,0 +1,3 @@
package dev.usbharu.hideout.domain.model.hideout.form
data class UserLogin(val username: String, val password: String)

View File

@ -2,24 +2,86 @@
package dev.usbharu.hideout.plugins
import com.auth0.jwk.JwkProviderBuilder
import com.auth0.jwt.JWT
import com.auth0.jwt.algorithms.Algorithm
import dev.usbharu.hideout.domain.model.hideout.form.UserLogin
import dev.usbharu.hideout.property
import dev.usbharu.hideout.service.IUserAuthService
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.auth.*
import io.ktor.server.auth.jwt.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import java.security.KeyFactory
import java.security.interfaces.RSAPrivateKey
import java.security.interfaces.RSAPublicKey
import java.security.spec.PKCS8EncodedKeySpec
import java.util.*
import java.util.concurrent.TimeUnit
const val TOKEN_AUTH = "token-auth"
const val TOKEN_AUTH = "jwt-auth"
fun Application.configureSecurity(userAuthService: IUserAuthService) {
val privateKeyString = property("jwt.privateKey")
val issuer = property("jwt.issuer")
// val audience = property("jwt.audience")
val myRealm = property("jwt.realm")
val jwkProvider = JwkProviderBuilder(issuer)
.cached(10, 24, TimeUnit.HOURS)
.rateLimited(10, 1, TimeUnit.MINUTES)
.build()
install(Authentication) {
bearer(TOKEN_AUTH) {
authenticate { bearerTokenCredential ->
UserIdPrincipal(bearerTokenCredential.token)
jwt(TOKEN_AUTH) {
realm = myRealm
verifier(jwkProvider, issuer) {
acceptLeeway(3)
}
validate { jwtCredential ->
if (jwtCredential.payload.getClaim("username").asString().isNotEmpty()) {
JWTPrincipal(jwtCredential.payload)
} else {
null
}
}
skipWhen { true }
}
}
// install(Sessions) {
// cookie<UserSession>("MY_SESSION") {
// cookie.extensions["SameSite"] = "lax"
// }
// }
routing {
post("/login") {
val user = call.receive<UserLogin>()
val check = userAuthService.verifyAccount(user.username, user.password)
if (check.not()) {
return@post call.respond(HttpStatusCode.Unauthorized)
}
val publicKey = jwkProvider.get("6f8856ed-9189-488f-9011-0ff4b6c08edc").publicKey
val keySpecPKCS8 = PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyString))
val privateKey = KeyFactory.getInstance("RSA").generatePrivate(keySpecPKCS8)
val token = JWT.create()
// .withAudience(audience)
// .withIssuer(issuer)
.withClaim("username", user.username)
.withExpiresAt(Date(System.currentTimeMillis() + 60000))
.sign(Algorithm.RSA256(publicKey as RSAPublicKey, privateKey as RSAPrivateKey))
return@post call.respond(hashSetOf("token" to token))
}
get("/.well-known/jwks.json"){
//language=JSON
call.respondText(contentType = ContentType.Application.Json,text = """{
"keys": [
{
"kty": "RSA",
"e": "AQAB",
"kid": "6f8856ed-9189-488f-9011-0ff4b6c08edc",
"n":"tfJaLrzXILUg1U3N1KV8yJr92GHn5OtYZR7qWk1Mc4cy4JGjklYup7weMjBD9f3bBVoIsiUVX6xNcYIr0Ie0AQ"
}
]
}""")
}
}
}

View File

@ -0,0 +1,8 @@
package dev.usbharu.hideout.routing
import dev.usbharu.hideout.service.IUserAuthService
import io.ktor.server.routing.*
fun Routing.login(userAuthService: IUserAuthService){
}

View File

@ -20,3 +20,10 @@ hideout {
password = ""
}
}
jwt {
privateKey = "MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAtfJaLrzXILUg1U3N1KV8yJr92GHn5OtYZR7qWk1Mc4cy4JGjklYup7weMjBD9f3bBVoIsiUVX6xNcYIr0Ie0AQIDAQABAkEAg+FBquToDeYcAWBe1EaLVyC45HG60zwfG1S4S3IB+y4INz1FHuZppDjBh09jptQNd+kSMlG1LkAc/3znKTPJ7QIhANpyB0OfTK44lpH4ScJmCxjZV52mIrQcmnS3QzkxWQCDAiEA1Tn7qyoh+0rOO/9vJHP8U/beo51SiQMw0880a1UaiisCIQDNwY46EbhGeiLJR1cidr+JHl86rRwPDsolmeEF5AdzRQIgK3KXL3d0WSoS//K6iOkBX3KMRzaFXNnDl0U/XyeGMuUCIHaXv+n+Brz5BDnRbWS+2vkgIe9bUNlkiArpjWvX+2we"
issuer = "http://0.0.0.0:8080/"
audience = "http://0.0.0.0:8080/hello"
realm = "Access to 'hello'"
}