From b1b1be8a14c3c447e56907483e3f461590ac8a15 Mon Sep 17 00:00:00 2001 From: KP9lKk Date: Wed, 25 Dec 2024 14:35:14 +0300 Subject: [PATCH] add generate jwt token --- build.gradle.kts | 1 + src/main/kotlin/com/college/Application.kt | 21 ++++++++- .../com/college/controller/auth/AuthRouter.kt | 44 +++++++++++++++++++ .../controller/common/PasswordEncoder.kt | 13 ++++++ .../controller/request/UserLoginRequest.kt | 6 +++ .../request/UserRegistrationRequest.kt | 6 +++ .../controller/response/AuthResponse.kt | 7 +++ .../kotlin/com/college/data/DbSettings.kt | 12 ++++- .../data/repositorty/user/UserRepository.kt | 1 + .../repositorty/user/UserRepositoryImpl.kt | 10 ++++- src/main/kotlin/com/college/di/DI.kt | 13 ++++++ .../domain/request/user/UserCreateRequest.kt | 2 +- .../domain/request/user/UserFindRequest.kt | 3 ++ .../com/college/domain/usecase/UserUseCase.kt | 11 ++++- src/main/resources/application.yaml | 3 ++ 15 files changed, 147 insertions(+), 6 deletions(-) create mode 100644 src/main/kotlin/com/college/controller/auth/AuthRouter.kt create mode 100644 src/main/kotlin/com/college/controller/common/PasswordEncoder.kt create mode 100644 src/main/kotlin/com/college/controller/request/UserLoginRequest.kt create mode 100644 src/main/kotlin/com/college/controller/request/UserRegistrationRequest.kt create mode 100644 src/main/kotlin/com/college/controller/response/AuthResponse.kt create mode 100644 src/main/kotlin/com/college/di/DI.kt create mode 100644 src/main/kotlin/com/college/domain/request/user/UserFindRequest.kt diff --git a/build.gradle.kts b/build.gradle.kts index 8a019c3..6b15772 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -24,6 +24,7 @@ dependencies { implementation(libs.ktor.serialization.kotlinx.json) implementation(libs.ktor.server.content.negotiation) implementation(libs.postgresql) + implementation("org.springframework.security:spring-security-crypto:6.4.1") implementation("io.insert-koin:koin-ktor:4.0.0") implementation("org.jetbrains.exposed:exposed-java-time:0.57.0") implementation(libs.exposed.core) diff --git a/src/main/kotlin/com/college/Application.kt b/src/main/kotlin/com/college/Application.kt index 07f1d72..0243ce7 100644 --- a/src/main/kotlin/com/college/Application.kt +++ b/src/main/kotlin/com/college/Application.kt @@ -1,6 +1,14 @@ package com.college +import com.college.controller.auth.AuthRouter +import com.college.data.DbSettings +import com.college.di.myModule +import io.ktor.http.* +import io.ktor.serialization.kotlinx.json.* import io.ktor.server.application.* +import io.ktor.server.plugins.contentnegotiation.* +import io.ktor.server.plugins.cors.routing.* +import io.ktor.server.routing.* import org.koin.ktor.plugin.Koin fun main(args: Array) { @@ -8,6 +16,15 @@ fun main(args: Array) { } fun Application.module() { - install(Koin) - + val db = DbSettings.db + install(Koin){ + modules(myModule) + } + install(CORS){ + allowHeader(HttpHeaders.ContentType) + } + install(ContentNegotiation){ + json() + } + AuthRouter() } diff --git a/src/main/kotlin/com/college/controller/auth/AuthRouter.kt b/src/main/kotlin/com/college/controller/auth/AuthRouter.kt new file mode 100644 index 0000000..7b3cee0 --- /dev/null +++ b/src/main/kotlin/com/college/controller/auth/AuthRouter.kt @@ -0,0 +1,44 @@ +package com.college.controller.auth + +import com.auth0.jwt.JWT +import com.auth0.jwt.algorithms.Algorithm +import com.college.controller.request.UserRegistrationRequest +import com.college.controller.request.UserLoginRequest +import com.college.controller.response.AuthResponse +import com.college.domain.request.user.UserCreateRequest +import com.college.domain.request.user.UserFindRequest +import com.college.domain.usecase.UserUseCase +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.request.* +import io.ktor.server.response.* +import io.ktor.server.routing.* +import org.koin.ktor.ext.inject +import java.util.* + +fun Application.AuthRouter(){ + val userUseCase by inject() + routing { + route("auth"){ + val secret = environment.config.property("jwt.secret").getString() + val issuer = environment.config.property("jwt.issuer").getString() + post("login") { + val user = call.receive() + val findUser = userUseCase.getUserByLogin(userFindRequest = UserFindRequest( + login = user.login + )) + val token = JWT.create() + .withIssuer(issuer) + .withClaim("username", findUser.login) + .withExpiresAt(Date(System.currentTimeMillis() + 60000)) + .sign(Algorithm.HMAC256(secret)) + call.respond(HttpStatusCode.OK, AuthResponse(jwtToken = token)) + } + post("registration") { + val newUser = call.receive() + val userCreateRequest = UserCreateRequest(password = newUser.password, login = newUser.login, roleId = newUser.roleId) + userUseCase.register(userCreateRequest) + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/college/controller/common/PasswordEncoder.kt b/src/main/kotlin/com/college/controller/common/PasswordEncoder.kt new file mode 100644 index 0000000..2e56bfc --- /dev/null +++ b/src/main/kotlin/com/college/controller/common/PasswordEncoder.kt @@ -0,0 +1,13 @@ +package com.college.controller.common + +import org.springframework.security.crypto.argon2.Argon2PasswordEncoder + +fun encodePassword(password: String):String{ + val argon2PasswordEncoder = Argon2PasswordEncoder(16, 32, 1, 60000, 16) + return argon2PasswordEncoder.encode(password) +} + +fun matchPassword(password: String, hashedPassword: String): Boolean { + val argon2PasswordEncoder = Argon2PasswordEncoder(16, 32, 1, 60000, 16) + return argon2PasswordEncoder.matches(password, hashedPassword) +} \ No newline at end of file diff --git a/src/main/kotlin/com/college/controller/request/UserLoginRequest.kt b/src/main/kotlin/com/college/controller/request/UserLoginRequest.kt new file mode 100644 index 0000000..326f9ae --- /dev/null +++ b/src/main/kotlin/com/college/controller/request/UserLoginRequest.kt @@ -0,0 +1,6 @@ +package com.college.controller.request + +import kotlinx.serialization.Serializable + +@Serializable +data class UserLoginRequest(val login: String, val password: String) diff --git a/src/main/kotlin/com/college/controller/request/UserRegistrationRequest.kt b/src/main/kotlin/com/college/controller/request/UserRegistrationRequest.kt new file mode 100644 index 0000000..2133945 --- /dev/null +++ b/src/main/kotlin/com/college/controller/request/UserRegistrationRequest.kt @@ -0,0 +1,6 @@ +package com.college.controller.request + +import kotlinx.serialization.Serializable + +@Serializable +data class UserRegistrationRequest(val login: String, val password: String, val roleId: Int) diff --git a/src/main/kotlin/com/college/controller/response/AuthResponse.kt b/src/main/kotlin/com/college/controller/response/AuthResponse.kt new file mode 100644 index 0000000..d696560 --- /dev/null +++ b/src/main/kotlin/com/college/controller/response/AuthResponse.kt @@ -0,0 +1,7 @@ +package com.college.controller.response + +import com.auth0.jwt.JWT +import kotlinx.serialization.Serializable + +@Serializable +data class AuthResponse (val jwtToken: String) \ No newline at end of file diff --git a/src/main/kotlin/com/college/data/DbSettings.kt b/src/main/kotlin/com/college/data/DbSettings.kt index ccc3232..8ea298f 100644 --- a/src/main/kotlin/com/college/data/DbSettings.kt +++ b/src/main/kotlin/com/college/data/DbSettings.kt @@ -1,18 +1,28 @@ package com.college.data +import com.college.data.table.RoleIdTable +import com.college.data.table.UserUuidTable import org.jetbrains.exposed.sql.Database +import org.jetbrains.exposed.sql.SchemaUtils import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction +import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.sql.transactions.transactionManager object DbSettings { + val db by lazy { Database.connect( url = "jdbc:postgresql://localhost:5432/presence", user = "postgres", password = "123" ) + transaction { + SchemaUtils.create(RoleIdTable) + SchemaUtils.create(UserUuidTable) + } } - suspend fun query(block: () -> Unit): T = + suspend fun query(block: () -> T): T = newSuspendedTransaction { block() } } \ No newline at end of file diff --git a/src/main/kotlin/com/college/data/repositorty/user/UserRepository.kt b/src/main/kotlin/com/college/data/repositorty/user/UserRepository.kt index 4efd2f6..8e177ab 100644 --- a/src/main/kotlin/com/college/data/repositorty/user/UserRepository.kt +++ b/src/main/kotlin/com/college/data/repositorty/user/UserRepository.kt @@ -7,6 +7,7 @@ import java.util.UUID interface UserRepository { suspend fun getUserByUuid(userUuid: UUID): User? + suspend fun getUserByLogin(userLogin: String): User? suspend fun removeUserByUuid(userUuid: UUID): Boolean suspend fun addUser(userCreateRequest: UserCreateRequest): User suspend fun getAllUsers(): List diff --git a/src/main/kotlin/com/college/data/repositorty/user/UserRepositoryImpl.kt b/src/main/kotlin/com/college/data/repositorty/user/UserRepositoryImpl.kt index 6dbd360..442aed7 100644 --- a/src/main/kotlin/com/college/data/repositorty/user/UserRepositoryImpl.kt +++ b/src/main/kotlin/com/college/data/repositorty/user/UserRepositoryImpl.kt @@ -24,6 +24,14 @@ class UserRepositoryImpl(private val database: DbSettings): UserRepository { .firstOrNull() } + override suspend fun getUserByLogin(userLogin: String): User? = database.query { + (UserUuidTable innerJoin RoleIdTable).selectAll().where { + UserUuidTable.login eq userLogin + } + .map(::resultRowToUserWithJoinRole) + .firstOrNull() + } + override suspend fun removeUserByUuid(userUuid: UUID): Boolean = database.query{ val result = UserUuidTable.deleteWhere { UserUuidTable.id eq userUuid @@ -35,7 +43,7 @@ class UserRepositoryImpl(private val database: DbSettings): UserRepository { val result = UserUuidTable.insertReturning { it[password] = userCreateRequest.password it[login] = userCreateRequest.login - it[role] = userCreateRequest.role.id + it[role] = userCreateRequest.roleId } resultRowToUser(result.first()) } diff --git a/src/main/kotlin/com/college/di/DI.kt b/src/main/kotlin/com/college/di/DI.kt new file mode 100644 index 0000000..f9aaff8 --- /dev/null +++ b/src/main/kotlin/com/college/di/DI.kt @@ -0,0 +1,13 @@ +package com.college.di + +import com.college.data.DbSettings +import com.college.data.repositorty.user.UserRepository +import com.college.data.repositorty.user.UserRepositoryImpl +import com.college.domain.usecase.UserUseCase +import org.koin.dsl.module + +val myModule = module { + single { DbSettings } + single { UserRepositoryImpl(get()) } + single { UserUseCase(get()) } +} \ No newline at end of file diff --git a/src/main/kotlin/com/college/domain/request/user/UserCreateRequest.kt b/src/main/kotlin/com/college/domain/request/user/UserCreateRequest.kt index e1cba99..e9f3d58 100644 --- a/src/main/kotlin/com/college/domain/request/user/UserCreateRequest.kt +++ b/src/main/kotlin/com/college/domain/request/user/UserCreateRequest.kt @@ -5,5 +5,5 @@ import com.college.domain.model.Role data class UserCreateRequest( val login:String, val password:String, - val role: Role + val roleId: Int ) diff --git a/src/main/kotlin/com/college/domain/request/user/UserFindRequest.kt b/src/main/kotlin/com/college/domain/request/user/UserFindRequest.kt new file mode 100644 index 0000000..f01358b --- /dev/null +++ b/src/main/kotlin/com/college/domain/request/user/UserFindRequest.kt @@ -0,0 +1,3 @@ +package com.college.domain.request.user + +data class UserFindRequest(val login:String) \ No newline at end of file diff --git a/src/main/kotlin/com/college/domain/usecase/UserUseCase.kt b/src/main/kotlin/com/college/domain/usecase/UserUseCase.kt index 52628ea..a66a10d 100644 --- a/src/main/kotlin/com/college/domain/usecase/UserUseCase.kt +++ b/src/main/kotlin/com/college/domain/usecase/UserUseCase.kt @@ -1,7 +1,16 @@ package com.college.domain.usecase import com.college.data.repositorty.user.UserRepository +import com.college.domain.model.User +import com.college.domain.request.user.UserCreateRequest +import com.college.domain.request.user.UserFindRequest +import io.ktor.server.plugins.* class UserUseCase(private val userRepository: UserRepository) { - fun re + suspend fun register(userCreateRequest: UserCreateRequest){ + userRepository.addUser(userCreateRequest) + } + suspend fun getUserByLogin(userFindRequest: UserFindRequest):User{ + return userRepository.getUserByLogin(userFindRequest.login) ?: throw NotFoundException() + } } \ No newline at end of file diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 00b5634..54b4e9b 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -8,3 +8,6 @@ postgres: url: "jdbc:postgresql://localhost:5432/presence" user: "postgres" password: "123" +jwt: + secret: "test" + issuer: "http://0.0.0.0:8080/" \ No newline at end of file