Implement user creation endpoint + persistance and hash to db

This commit is contained in:
Hubert Van De Walle 2020-04-12 02:33:48 +02:00
parent 542eaa21cc
commit 14aa195bb3
3 changed files with 67 additions and 8 deletions

View File

@ -17,6 +17,7 @@
<kodein_version>6.5.4</kodein_version> <kodein_version>6.5.4</kodein_version>
<flyway_version>6.3.3</flyway_version> <flyway_version>6.3.3</flyway_version>
<javajwt_version>3.10.2</javajwt_version> <javajwt_version>3.10.2</javajwt_version>
<jbcrypt_version>0.4</jbcrypt_version>
<kotlin.code.style>official</kotlin.code.style> <kotlin.code.style>official</kotlin.code.style>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@ -127,6 +128,11 @@
<artifactId>flyway-core</artifactId> <artifactId>flyway-core</artifactId>
<version>${flyway_version}</version> <version>${flyway_version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.mindrot</groupId>
<artifactId>jbcrypt</artifactId>
<version>${jbcrypt_version}</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
<sourceDirectory>${project.basedir}/src</sourceDirectory> <sourceDirectory>${project.basedir}/src</sourceDirectory>

View File

@ -16,6 +16,7 @@ import io.ktor.features.ContentNegotiation
import io.ktor.jackson.jackson import io.ktor.jackson.jackson
import io.ktor.locations.Locations import io.ktor.locations.Locations
import io.ktor.routing.routing import io.ktor.routing.routing
import me.liuwj.ktorm.database.Database
import org.kodein.di.Kodein import org.kodein.di.Kodein
import org.kodein.di.description import org.kodein.di.description
import org.kodein.di.generic.bind import org.kodein.di.generic.bind
@ -35,12 +36,14 @@ fun Application.module() {
import(configurationModule) import(configurationModule)
bind<Feature>() with singleton { Migration(this.kodein) } bind<Feature>() with singleton { Migration(this.kodein) }
bind<Database>() with singleton { Database.Companion.connect(this.instance<DataSource>()) }
} }
features() features()
log.debug(kodein.container.tree.bindings.description()) log.debug(kodein.container.tree.bindings.description())
// TODO, clean this (migration)
val feature: Feature by kodein.instance() val feature: Feature by kodein.instance()
feature.execute() feature.execute()

View File

@ -2,7 +2,9 @@ package be.vandewalleh.controllers
import be.vandewalleh.auth.SimpleJWT import be.vandewalleh.auth.SimpleJWT
import be.vandewalleh.auth.UsernamePasswordCredential import be.vandewalleh.auth.UsernamePasswordCredential
import be.vandewalleh.entities.User
import be.vandewalleh.errors.ApiError import be.vandewalleh.errors.ApiError
import be.vandewalleh.tables.Users
import io.ktor.application.call import io.ktor.application.call
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.locations.Location import io.ktor.locations.Location
@ -10,26 +12,74 @@ import io.ktor.locations.post
import io.ktor.request.receive import io.ktor.request.receive
import io.ktor.response.respond import io.ktor.response.respond
import io.ktor.routing.Routing import io.ktor.routing.Routing
import me.liuwj.ktorm.database.Database
import me.liuwj.ktorm.dsl.eq
import me.liuwj.ktorm.dsl.from
import me.liuwj.ktorm.dsl.select
import me.liuwj.ktorm.dsl.where
import me.liuwj.ktorm.entity.add
import me.liuwj.ktorm.entity.sequenceOf
import org.kodein.di.Kodein import org.kodein.di.Kodein
import org.kodein.di.generic.instance import org.kodein.di.generic.instance
import org.mindrot.jbcrypt.BCrypt
import java.time.LocalDateTime
class UserController(kodein: Kodein) : KodeinController(kodein) { class UserController(kodein: Kodein) : KodeinController(kodein) {
private val simpleJwt by instance<SimpleJWT>() private val simpleJwt by instance<SimpleJWT>()
private val db by instance<Database>()
override fun Routing.registerRoutes() { override fun Routing.registerRoutes() {
post<Routes.Auth> { post<Routes.SignIn> {
val post = call.receive<UsernamePasswordCredential>() data class Response(val token: String)
// TODO check db val credential = call.receive<UsernamePasswordCredential>()
if (post.username != "test" || post.password != "test")
val (email, password) = db.from(Users)
.select(Users.email, Users.password)
.where { Users.username eq credential.username }
.map { row -> row[Users.email]!! to row[Users.password]!! }
.firstOrNull()
?: return@post call.respond(HttpStatusCode.BadRequest, ApiError.InvalidCredentialError())
if (!BCrypt.checkpw(credential.password, password)) {
return@post call.respond(HttpStatusCode.BadRequest, ApiError.InvalidCredentialError()) return@post call.respond(HttpStatusCode.BadRequest, ApiError.InvalidCredentialError())
}
return@post call.respond(mapOf("token" to simpleJwt.sign("test@test.be"))) return@post call.respond(Response(simpleJwt.sign(email)))
}
post<Routes.SignUp> {
data class Response(val message: String)
val user = call.receive<SignUpInfo>()
// TODO check if user does not already exists
// db won't let you insert it anyway
val hashedPassword = BCrypt.hashpw(user.password, BCrypt.gensalt())
val newUser = User {
this.username = user.username
this.email = user.email
this.password = hashedPassword
this.createdAt = LocalDateTime.now()
}
db.sequenceOf(Users).add(newUser)
call.respond(HttpStatusCode.Created, Response("User created successfully"))
} }
} }
object Routes { object Routes {
@Location("/auth") @Location("/signin")
class Auth class SignIn
@Location("/signup")
class SignUp
} }
} }
data class SignUpInfo(val username: String, val email: String, val password: String)