add di and refactoring
This commit is contained in:
parent
0114e330ed
commit
fbe07fd569
@ -20,6 +20,8 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
// Koin for Ktor
|
||||||
|
implementation("io.insert-koin:koin-ktor3:4.1.0-Beta5")
|
||||||
implementation(libs.ktor.server.content.negotiation)
|
implementation(libs.ktor.server.content.negotiation)
|
||||||
implementation(libs.ktor.server.core)
|
implementation(libs.ktor.server.core)
|
||||||
implementation(libs.ktor.serialization.kotlinx.json)
|
implementation(libs.ktor.serialization.kotlinx.json)
|
||||||
|
@ -1,12 +1,19 @@
|
|||||||
package com.example
|
package com.example
|
||||||
|
|
||||||
|
import com.example.config.JwtConfig
|
||||||
|
import com.example.di.configureDependencyInjection
|
||||||
|
import com.example.security.JwtManager
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.*
|
||||||
|
import org.koin.ktor.plugin.Koin
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
io.ktor.server.netty.EngineMain.main(args)
|
io.ktor.server.netty.EngineMain.main(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Application.module() {
|
fun Application.module() {
|
||||||
|
install(Koin){
|
||||||
|
modules(configureDependencyInjection(this@module))
|
||||||
|
}
|
||||||
configureSecurity()
|
configureSecurity()
|
||||||
configureSerialization()
|
configureSerialization()
|
||||||
configureRouting()
|
configureRouting()
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package com.example
|
package com.example
|
||||||
|
|
||||||
import com.auth0.jwt.JWT
|
import com.example.security.JwtManager
|
||||||
import com.auth0.jwt.algorithms.Algorithm
|
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
import io.ktor.resources.*
|
import io.ktor.resources.*
|
||||||
import io.ktor.serialization.kotlinx.json.*
|
import io.ktor.serialization.kotlinx.json.*
|
||||||
@ -12,27 +11,14 @@ import io.ktor.server.plugins.contentnegotiation.*
|
|||||||
import io.ktor.server.resources.*
|
import io.ktor.server.resources.*
|
||||||
import io.ktor.server.response.*
|
import io.ktor.server.response.*
|
||||||
import io.ktor.server.routing.*
|
import io.ktor.server.routing.*
|
||||||
import kotlinx.serialization.Serializable
|
import org.koin.ktor.ext.inject
|
||||||
|
|
||||||
fun Application.configureSecurity() {
|
fun Application.configureSecurity() {
|
||||||
val jwtAudience = environment.config.property("jwt.audience").getString()
|
val jwtManager: JwtManager by inject()
|
||||||
val jwtIssue = environment.config.property("jwt.issue").getString()
|
|
||||||
val jwtRealm = environment.config.property("jwt.realm").getString()
|
|
||||||
val jwtSecret = environment.config.property("jwt.secret").getString()
|
|
||||||
install(Authentication)
|
install(Authentication)
|
||||||
authentication {
|
authentication {
|
||||||
jwt("auth-jwt") {
|
jwt {
|
||||||
realm = jwtRealm
|
verifier(jwtManager.verifyJwt())
|
||||||
verifier(
|
|
||||||
JWT
|
|
||||||
.require(Algorithm.HMAC256(jwtSecret))
|
|
||||||
.withAudience(jwtAudience)
|
|
||||||
.withIssuer(jwtIssue)
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
validate { credential ->
|
|
||||||
if (credential.payload.audience.contains(jwtAudience)) JWTPrincipal(credential.payload) else null
|
|
||||||
}
|
|
||||||
challenge { defaultScheme, realm ->
|
challenge { defaultScheme, realm ->
|
||||||
call.respond(HttpStatusCode.Unauthorized, "Token is not valid or has expire")
|
call.respond(HttpStatusCode.Unauthorized, "Token is not valid or has expire")
|
||||||
}
|
}
|
||||||
|
5
src/main/kotlin/command/auth/GetAuthByEmailCommand.kt
Normal file
5
src/main/kotlin/command/auth/GetAuthByEmailCommand.kt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package com.example.command.request
|
||||||
|
|
||||||
|
data class GetAuthByEmailCommand(
|
||||||
|
val email: String
|
||||||
|
)
|
7
src/main/kotlin/command/auth/InsertAuthCommand.kt
Normal file
7
src/main/kotlin/command/auth/InsertAuthCommand.kt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package com.example.command.request
|
||||||
|
|
||||||
|
data class InsertAuthCommand(
|
||||||
|
val email: String,
|
||||||
|
val password: String,
|
||||||
|
val userName: String
|
||||||
|
)
|
7
src/main/kotlin/command/auth/UpdateAuthByEmailCommand.kt
Normal file
7
src/main/kotlin/command/auth/UpdateAuthByEmailCommand.kt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package com.example.command.request
|
||||||
|
|
||||||
|
data class UpdateAuthByEmailCommand(
|
||||||
|
val email: String,
|
||||||
|
val password: String?,
|
||||||
|
val userName: String?
|
||||||
|
)
|
6
src/main/kotlin/common/Either.kt
Normal file
6
src/main/kotlin/common/Either.kt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package com.example.common
|
||||||
|
|
||||||
|
sealed class Either<out A, out B> {
|
||||||
|
class Left<A>(val data: A): Either<A, Nothing>()
|
||||||
|
class Right<B>(val data: B): Either<Nothing, B>()
|
||||||
|
}
|
7
src/main/kotlin/config/JwtConfig.kt
Normal file
7
src/main/kotlin/config/JwtConfig.kt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package com.example.config
|
||||||
|
|
||||||
|
data class JwtConfig(
|
||||||
|
val jwtAudience: String,
|
||||||
|
val jwtIssue: String,
|
||||||
|
val jwtSecret: String
|
||||||
|
)
|
27
src/main/kotlin/di/appModule.kt
Normal file
27
src/main/kotlin/di/appModule.kt
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package com.example.di
|
||||||
|
|
||||||
|
import com.example.config.JwtConfig
|
||||||
|
import com.example.repository.AuthRepository
|
||||||
|
import com.example.repository.AuthRepositoryImpl
|
||||||
|
import com.example.security.JwtManager
|
||||||
|
import com.example.service.AuthServiceImpl
|
||||||
|
import io.ktor.server.application.*
|
||||||
|
import org.koin.core.module.Module
|
||||||
|
import org.koin.dsl.module
|
||||||
|
|
||||||
|
fun configureDependencyInjection(application: Application): Module{
|
||||||
|
return module {
|
||||||
|
single<JwtConfig> { provideJwtConfiguration(application.environment) }
|
||||||
|
single<JwtManager> { JwtManager(get()) }
|
||||||
|
single<AuthRepository> { AuthRepositoryImpl() }
|
||||||
|
single<AuthServiceImpl> { AuthServiceImpl(get(), get()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun provideJwtConfiguration(environment: ApplicationEnvironment): JwtConfig{
|
||||||
|
return JwtConfig(
|
||||||
|
jwtIssue = environment.config.property("jwt.issue").toString(),
|
||||||
|
jwtAudience = environment.config.property("jwt.audience").toString(),
|
||||||
|
jwtSecret = environment.config.property("jwt.secret").toString()
|
||||||
|
)
|
||||||
|
}
|
6
src/main/kotlin/dto/request/LoginRequest.kt
Normal file
6
src/main/kotlin/dto/request/LoginRequest.kt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package com.example.dto.request
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class LoginRequest(val email: String, val password: String)
|
6
src/main/kotlin/dto/response/LoginResponse.kt
Normal file
6
src/main/kotlin/dto/response/LoginResponse.kt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package com.example.dto.response
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class LoginResponse(val token: String)
|
20
src/main/kotlin/model/AuthEntity.kt
Normal file
20
src/main/kotlin/model/AuthEntity.kt
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package com.example.model
|
||||||
|
|
||||||
|
import com.example.command.request.UpdateAuthByEmailCommand
|
||||||
|
|
||||||
|
data class AuthEntity(
|
||||||
|
val userId: Int,
|
||||||
|
var userName: String,
|
||||||
|
val email: String,
|
||||||
|
var password: String
|
||||||
|
){
|
||||||
|
fun update(updateAuthByEmailCommand: UpdateAuthByEmailCommand): AuthEntity{
|
||||||
|
updateAuthByEmailCommand.password?.let {
|
||||||
|
this.password = it
|
||||||
|
}
|
||||||
|
updateAuthByEmailCommand.userName?.let {
|
||||||
|
this.userName = it
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
12
src/main/kotlin/repository/AuthRepository.kt
Normal file
12
src/main/kotlin/repository/AuthRepository.kt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package com.example.repository
|
||||||
|
|
||||||
|
import com.example.command.request.GetAuthByEmailCommand
|
||||||
|
import com.example.command.request.InsertAuthCommand
|
||||||
|
import com.example.command.request.UpdateAuthByEmailCommand
|
||||||
|
import com.example.model.AuthEntity
|
||||||
|
|
||||||
|
interface AuthRepository {
|
||||||
|
suspend fun getAuthByEmail(getAuthByEmailCommand: GetAuthByEmailCommand): AuthEntity?
|
||||||
|
suspend fun updateAuthByEmail(updateAuthByEmailCommand: UpdateAuthByEmailCommand): Boolean
|
||||||
|
suspend fun insertAuth(insertAuthCommand: InsertAuthCommand): AuthEntity
|
||||||
|
}
|
51
src/main/kotlin/repository/AuthRepositoryImpl.kt
Normal file
51
src/main/kotlin/repository/AuthRepositoryImpl.kt
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package com.example.repository
|
||||||
|
|
||||||
|
import com.example.command.request.GetAuthByEmailCommand
|
||||||
|
import com.example.command.request.InsertAuthCommand
|
||||||
|
import com.example.command.request.UpdateAuthByEmailCommand
|
||||||
|
import com.example.model.AuthEntity
|
||||||
|
|
||||||
|
class AuthRepositoryImpl: AuthRepository {
|
||||||
|
private val users = mutableListOf(
|
||||||
|
AuthEntity(
|
||||||
|
userId = 1,
|
||||||
|
userName = "user1",
|
||||||
|
email = "user1@mail.ru",
|
||||||
|
password = "123"
|
||||||
|
),
|
||||||
|
AuthEntity(
|
||||||
|
userId = 2,
|
||||||
|
userName = "user2",
|
||||||
|
email = "user2@mail.ru",
|
||||||
|
password = "123"
|
||||||
|
),
|
||||||
|
AuthEntity(
|
||||||
|
userId = 3,
|
||||||
|
userName = "user3",
|
||||||
|
email = "user3@mail.ru",
|
||||||
|
password = "123"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
override suspend fun getAuthByEmail(getAuthByEmailCommand: GetAuthByEmailCommand): AuthEntity? {
|
||||||
|
return users.find { it.email == getAuthByEmailCommand.email }
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun updateAuthByEmail(updateAuthByEmailCommand: UpdateAuthByEmailCommand): Boolean {
|
||||||
|
val user = users.find { it.email == updateAuthByEmailCommand.email }
|
||||||
|
if (user != null) {
|
||||||
|
user.update(updateAuthByEmailCommand)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun insertAuth(insertAuthCommand: InsertAuthCommand): AuthEntity {
|
||||||
|
val authEntity = AuthEntity(
|
||||||
|
userId = users.size + 1,
|
||||||
|
userName = insertAuthCommand.userName,
|
||||||
|
password = insertAuthCommand.password,
|
||||||
|
email = insertAuthCommand.email
|
||||||
|
)
|
||||||
|
return authEntity
|
||||||
|
}
|
||||||
|
}
|
@ -1,56 +1,42 @@
|
|||||||
package com.example.route
|
package com.example.route
|
||||||
|
|
||||||
import com.auth0.jwt.JWT
|
import com.example.common.Either
|
||||||
import com.auth0.jwt.algorithms.Algorithm
|
import com.example.config.JwtConfig
|
||||||
|
import com.example.dto.request.LoginRequest
|
||||||
|
import com.example.repository.AuthRepositoryImpl
|
||||||
|
import com.example.security.JwtManager
|
||||||
|
import com.example.service.AuthServiceImpl
|
||||||
|
import com.example.service.exception.ErrorService
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
import io.ktor.server.auth.*
|
|
||||||
import io.ktor.server.request.*
|
import io.ktor.server.request.*
|
||||||
import io.ktor.server.response.*
|
import io.ktor.server.response.*
|
||||||
import io.ktor.server.routing.*
|
import io.ktor.server.routing.*
|
||||||
import kotlinx.serialization.Serializable
|
import org.koin.ktor.ext.inject
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class User(val userId: Int,
|
|
||||||
val userName: String,
|
|
||||||
val email: String,
|
|
||||||
val password: String)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class CreateUserRequest(
|
|
||||||
val userName: String,
|
|
||||||
val email: String,
|
|
||||||
val password: String)
|
|
||||||
val userList = mutableListOf<User>()
|
|
||||||
fun Route.authRoute(){
|
fun Route.authRoute(){
|
||||||
post("login"){
|
|
||||||
|
|
||||||
}
|
val authServiceImpl: AuthServiceImpl by inject()
|
||||||
post("registration"){
|
|
||||||
val user = call.receive<CreateUserRequest>()
|
route("/auth"){
|
||||||
userList.add(User(
|
post("/login") {
|
||||||
userId = userList.size + 1,
|
val loginRequest = call.receive<LoginRequest>()
|
||||||
userName = user.userName,
|
val result = authServiceImpl.login(loginRequest)
|
||||||
password = user.password,
|
when(result){
|
||||||
email = user.email
|
is Either.Left -> {
|
||||||
))
|
when(result.data){
|
||||||
val jwtAudience = environment.config.property("jwt.audience").getString()
|
ErrorService.NOT_FOUND -> {
|
||||||
val jwtIssue = environment.config.property("jwt.issue").getString()
|
call.respond(HttpStatusCode.NotFound)
|
||||||
val jwtSecret = environment.config.property("jwt.secret").getString()
|
}
|
||||||
val token = JWT.create()
|
ErrorService.UNAUTHORIZED -> {
|
||||||
.withAudience(jwtAudience)
|
call.respond(HttpStatusCode.Unauthorized)
|
||||||
.withIssuer(jwtIssue)
|
}
|
||||||
.withClaim("user", user.userName)
|
}
|
||||||
.withExpiresAt(Date(System.currentTimeMillis() + 60000))
|
}
|
||||||
.sign(Algorithm.HMAC256(jwtSecret))
|
is Either.Right -> {
|
||||||
call.respond("Token" to token)
|
call.respond(HttpStatusCode.OK, result.data)
|
||||||
}
|
}
|
||||||
authenticate("auth-jwt") {
|
}
|
||||||
get("/profile/{userId}"){
|
|
||||||
val userId = call.pathParameters["userId"]?.toInt()
|
|
||||||
val findUser = userList.firstOrNull { it.userId == userId }
|
|
||||||
if(findUser != null) call.respond(findUser)
|
|
||||||
call.respond(HttpStatusCode.NotFound)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
25
src/main/kotlin/security/JwtManager.kt
Normal file
25
src/main/kotlin/security/JwtManager.kt
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package com.example.security
|
||||||
|
|
||||||
|
import com.auth0.jwt.JWT
|
||||||
|
import com.auth0.jwt.JWTVerifier
|
||||||
|
import com.auth0.jwt.algorithms.Algorithm
|
||||||
|
import com.example.config.JwtConfig
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class JwtManager(private val jwtConfig: JwtConfig) {
|
||||||
|
fun createJwt(): String{
|
||||||
|
return JWT.create()
|
||||||
|
.withAudience(jwtConfig.jwtAudience)
|
||||||
|
.withIssuer(jwtConfig.jwtIssue)
|
||||||
|
.withExpiresAt(Date(System.currentTimeMillis() + 7 * 24 * 60 * 60 * 1000))
|
||||||
|
.sign(Algorithm.HMAC256(jwtConfig.jwtSecret))
|
||||||
|
|
||||||
|
}
|
||||||
|
fun verifyJwt(): JWTVerifier{
|
||||||
|
return JWT
|
||||||
|
.require(Algorithm.HMAC256(jwtConfig.jwtSecret))
|
||||||
|
.withAudience(jwtConfig.jwtAudience)
|
||||||
|
.withIssuer(jwtConfig.jwtIssue)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
29
src/main/kotlin/service/AuthServiceImpl.kt
Normal file
29
src/main/kotlin/service/AuthServiceImpl.kt
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package com.example.service
|
||||||
|
|
||||||
|
import com.example.command.request.GetAuthByEmailCommand
|
||||||
|
import com.example.common.Either
|
||||||
|
import com.example.dto.request.LoginRequest
|
||||||
|
import com.example.dto.response.LoginResponse
|
||||||
|
import com.example.repository.AuthRepository
|
||||||
|
import com.example.security.JwtManager
|
||||||
|
import com.example.service.exception.ErrorService
|
||||||
|
|
||||||
|
class AuthServiceImpl(
|
||||||
|
private val authRepository: AuthRepository,
|
||||||
|
private val jwtManager: JwtManager
|
||||||
|
) {
|
||||||
|
suspend fun login(loginRequest: LoginRequest): Either<ErrorService, LoginResponse>{
|
||||||
|
val getAuthByEmailCommand = GetAuthByEmailCommand(loginRequest.email)
|
||||||
|
val user = authRepository.getAuthByEmail(getAuthByEmailCommand) ?: return Either.Left(ErrorService.NOT_FOUND)
|
||||||
|
if(user.password == loginRequest.password){
|
||||||
|
val token = jwtManager.createJwt()
|
||||||
|
val response = LoginResponse(token = token)
|
||||||
|
return Either.Right(response)
|
||||||
|
}
|
||||||
|
return Either.Left(ErrorService.UNAUTHORIZED)
|
||||||
|
}
|
||||||
|
suspend fun registration(){
|
||||||
|
}
|
||||||
|
suspend fun resetPassword(){
|
||||||
|
}
|
||||||
|
}
|
6
src/main/kotlin/service/exception/ErrorService.kt
Normal file
6
src/main/kotlin/service/exception/ErrorService.kt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package com.example.service.exception
|
||||||
|
|
||||||
|
enum class ErrorService {
|
||||||
|
NOT_FOUND,
|
||||||
|
UNAUTHORIZED
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user