add generate jwt token

This commit is contained in:
KP9lKk 2024-12-25 14:35:14 +03:00
parent 9ca22827d5
commit b1b1be8a14
15 changed files with 147 additions and 6 deletions

View File

@ -24,6 +24,7 @@ dependencies {
implementation(libs.ktor.serialization.kotlinx.json) implementation(libs.ktor.serialization.kotlinx.json)
implementation(libs.ktor.server.content.negotiation) implementation(libs.ktor.server.content.negotiation)
implementation(libs.postgresql) implementation(libs.postgresql)
implementation("org.springframework.security:spring-security-crypto:6.4.1")
implementation("io.insert-koin:koin-ktor:4.0.0") implementation("io.insert-koin:koin-ktor:4.0.0")
implementation("org.jetbrains.exposed:exposed-java-time:0.57.0") implementation("org.jetbrains.exposed:exposed-java-time:0.57.0")
implementation(libs.exposed.core) implementation(libs.exposed.core)

View File

@ -1,6 +1,14 @@
package com.college 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.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 import org.koin.ktor.plugin.Koin
fun main(args: Array<String>) { fun main(args: Array<String>) {
@ -8,6 +16,15 @@ fun main(args: Array<String>) {
} }
fun Application.module() { fun Application.module() {
install(Koin) val db = DbSettings.db
install(Koin){
modules(myModule)
}
install(CORS){
allowHeader(HttpHeaders.ContentType)
}
install(ContentNegotiation){
json()
}
AuthRouter()
} }

View File

@ -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<UserUseCase>()
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<UserLoginRequest>()
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<UserRegistrationRequest>()
val userCreateRequest = UserCreateRequest(password = newUser.password, login = newUser.login, roleId = newUser.roleId)
userUseCase.register(userCreateRequest)
}
}
}
}

View File

@ -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)
}

View File

@ -0,0 +1,6 @@
package com.college.controller.request
import kotlinx.serialization.Serializable
@Serializable
data class UserLoginRequest(val login: String, val password: String)

View File

@ -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)

View File

@ -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)

View File

@ -1,18 +1,28 @@
package com.college.data 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.Database
import org.jetbrains.exposed.sql.SchemaUtils
import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.sql.transactions.transactionManager
object DbSettings { object DbSettings {
val db by lazy { val db by lazy {
Database.connect( Database.connect(
url = "jdbc:postgresql://localhost:5432/presence", url = "jdbc:postgresql://localhost:5432/presence",
user = "postgres", user = "postgres",
password = "123" password = "123"
) )
transaction {
SchemaUtils.create(RoleIdTable)
SchemaUtils.create(UserUuidTable)
}
} }
suspend fun <T> query(block: () -> Unit): T = suspend fun <T> query(block: () -> T): T =
newSuspendedTransaction { block() } newSuspendedTransaction { block() }
} }

View File

@ -7,6 +7,7 @@ import java.util.UUID
interface UserRepository { interface UserRepository {
suspend fun getUserByUuid(userUuid: UUID): User? suspend fun getUserByUuid(userUuid: UUID): User?
suspend fun getUserByLogin(userLogin: String): User?
suspend fun removeUserByUuid(userUuid: UUID): Boolean suspend fun removeUserByUuid(userUuid: UUID): Boolean
suspend fun addUser(userCreateRequest: UserCreateRequest): User suspend fun addUser(userCreateRequest: UserCreateRequest): User
suspend fun getAllUsers(): List<User> suspend fun getAllUsers(): List<User>

View File

@ -24,6 +24,14 @@ class UserRepositoryImpl(private val database: DbSettings): UserRepository {
.firstOrNull() .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{ override suspend fun removeUserByUuid(userUuid: UUID): Boolean = database.query{
val result = UserUuidTable.deleteWhere { val result = UserUuidTable.deleteWhere {
UserUuidTable.id eq userUuid UserUuidTable.id eq userUuid
@ -35,7 +43,7 @@ class UserRepositoryImpl(private val database: DbSettings): UserRepository {
val result = UserUuidTable.insertReturning { val result = UserUuidTable.insertReturning {
it[password] = userCreateRequest.password it[password] = userCreateRequest.password
it[login] = userCreateRequest.login it[login] = userCreateRequest.login
it[role] = userCreateRequest.role.id it[role] = userCreateRequest.roleId
} }
resultRowToUser(result.first()) resultRowToUser(result.first())
} }

View File

@ -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<UserRepository> { UserRepositoryImpl(get()) }
single { UserUseCase(get()) }
}

View File

@ -5,5 +5,5 @@ import com.college.domain.model.Role
data class UserCreateRequest( data class UserCreateRequest(
val login:String, val login:String,
val password:String, val password:String,
val role: Role val roleId: Int
) )

View File

@ -0,0 +1,3 @@
package com.college.domain.request.user
data class UserFindRequest(val login:String)

View File

@ -1,7 +1,16 @@
package com.college.domain.usecase package com.college.domain.usecase
import com.college.data.repositorty.user.UserRepository 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) { 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()
}
} }

View File

@ -8,3 +8,6 @@ postgres:
url: "jdbc:postgresql://localhost:5432/presence" url: "jdbc:postgresql://localhost:5432/presence"
user: "postgres" user: "postgres"
password: "123" password: "123"
jwt:
secret: "test"
issuer: "http://0.0.0.0:8080/"