Add login

This commit is contained in:
2023-10-06 01:53:25 +08:00
parent 8e5375ab30
commit 79e65f0785
12 changed files with 141 additions and 41 deletions

View File

@@ -18,14 +18,12 @@ fun main(args: Array<String>) {
runApplication<FatWebApiApplication>(*args)
} else {
logger.warn("File application.yml cannot be found in the running path. The configuration file template 'application.example.yml' has been created. Please change the configuration file content and rename it to 'application.yml', and then restart the server.")
FatWebApiApplication::class.java.getResource("/application-config-template.yml")?.readText()
?.let {
File("application-config.example.yml").writeText(
it.replace(
"\$uuid\$",
UUID.randomUUID().toString()
)
FatWebApiApplication::class.java.getResource("/application-config-template.yml")?.readText()?.let {
File("application-config.example.yml").writeText(
it.replace(
"\$uuid\$", UUID.randomUUID().toString().replace("-", "")
)
}
)
}
}
}

View File

@@ -2,13 +2,10 @@ package top.fatweb.api.annotation
import org.springframework.core.annotation.AliasFor
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class ApiVersion(
@get:AliasFor("version")
val value: Int = 1,
@get:AliasFor("version") val value: Int = 1,
@get:AliasFor("value")
val version: Int = 1
@get:AliasFor("value") val version: Int = 1
)

View File

@@ -2,20 +2,30 @@ package top.fatweb.api.controller.permission
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import org.springframework.web.bind.annotation.*
import jakarta.validation.Valid
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import top.fatweb.api.annotation.ApiVersion
import top.fatweb.api.entity.common.ResponseCode
import top.fatweb.api.entity.common.ResponseResult
import top.fatweb.api.entity.permission.User
import top.fatweb.api.entity.converter.UserConverter
import top.fatweb.api.entity.param.LoginParam
import top.fatweb.api.service.permission.IAuthenticationService
@Tag(name = "身份认证", description = "身份认证相关接口")
@RestController
@Suppress("MVCPathVariableInspection")
@RequestMapping("/api/{apiVersion}")
@ApiVersion(2)
class AuthenticationController(val loginService: IAuthenticationService) {
@RestController
class AuthenticationController(val loginService: IAuthenticationService, val userConverter: UserConverter) {
@Operation(summary = "登录")
@PostMapping("/login")
fun login(@PathVariable apiVersion: String, @RequestBody user: User) =
ResponseResult.success(ResponseCode.SYSTEM_LOGIN_SUCCESS, "Login success", loginService.login(user))
fun login(@Valid @RequestBody loginParam: LoginParam) =
ResponseResult.success(
ResponseCode.SYSTEM_LOGIN_SUCCESS,
"Login success",
loginService.login(userConverter.loginParamToUser(loginParam))
)
}

View File

@@ -7,14 +7,16 @@ enum class ResponseCode(val code: Int) {
SYSTEM_LOGOUT_SUCCESS(BusinessCode.SYSTEM, 22),
SYSTEM_TOKEN_RENEW_SUCCESS(BusinessCode.SYSTEM, 23),
SYSTEM_UNAUTHORIZED(BusinessCode.SYSTEM, 30),
SYSTEM_ACCESS_DENIED(BusinessCode.SYSTEM, 31),
SYSTEM_USER_DISABLE(BusinessCode.SYSTEM, 32),
SYSTEM_LOGIN_USERNAME_PASSWORD_ERROR(BusinessCode.SYSTEM, 33),
SYSTEM_OLD_PASSWORD_NOT_MATCH(BusinessCode.SYSTEM, 34),
SYSTEM_LOGOUT_FAILED(BusinessCode.SYSTEM, 35),
SYSTEM_TOKEN_ILLEGAL(BusinessCode.SYSTEM, 36),
SYSTEM_TOKEN_HAS_EXPIRED(BusinessCode.SYSTEM, 37),
SYSTEM_USERNAME_NOT_FOUND(BusinessCode.SYSTEM, 31),
SYSTEM_ACCESS_DENIED(BusinessCode.SYSTEM, 32),
SYSTEM_USER_DISABLE(BusinessCode.SYSTEM, 33),
SYSTEM_LOGIN_USERNAME_PASSWORD_ERROR(BusinessCode.SYSTEM, 34),
SYSTEM_OLD_PASSWORD_NOT_MATCH(BusinessCode.SYSTEM, 35),
SYSTEM_LOGOUT_FAILED(BusinessCode.SYSTEM, 36),
SYSTEM_TOKEN_ILLEGAL(BusinessCode.SYSTEM, 37),
SYSTEM_TOKEN_HAS_EXPIRED(BusinessCode.SYSTEM, 38),
SYSTEM_REQUEST_ILLEGAL(BusinessCode.SYSTEM, 40),
SYSTEM_ARGUMENT_NOT_VALID(BusinessCode.SYSTEM, 41),
SYSTEM_ERROR(BusinessCode.SYSTEM, 50),
SYSTEM_TIMEOUT(BusinessCode.SYSTEM, 51);

View File

@@ -0,0 +1,14 @@
package top.fatweb.api.entity.converter
import org.mapstruct.Mapper
import org.mapstruct.Mapping
import org.mapstruct.Mappings
import top.fatweb.api.entity.param.LoginParam
import top.fatweb.api.entity.permission.User
@Mapper(componentModel = "spring")
interface UserConverter {
@Mappings(Mapping(source = "username", target = "username"), Mapping(source = "password", target = "password"))
fun loginParamToUser(loginParam: LoginParam): User
}

View File

@@ -0,0 +1,16 @@
package top.fatweb.api.entity.param
import io.swagger.v3.oas.annotations.media.Schema
import jakarta.validation.constraints.NotBlank
import java.io.Serializable
class LoginParam : Serializable {
@Schema(description = "用户名", example = "test", required = true)
@NotBlank(message = "Username can not be blank")
val username: String? = null
@Schema(description = "密码", example = "test123456", required = true)
@NotBlank(message = "Password can not be blank")
val password: String? = null
}

View File

@@ -12,7 +12,12 @@ import java.io.Serializable
* @since 2023-10-04
*/
@TableName("t_user")
class User : Serializable {
class User() : Serializable {
constructor(username: String, password: String, enable: Boolean = true) : this() {
this.username = username
this.password = password
this.enable = if (enable) 1 else 0
}
@TableId("id")
var id: Long? = null
@@ -44,13 +49,6 @@ class User : Serializable {
var version: Int? = null
override fun toString(): String {
return "User{" +
"id=" + id +
", username=" + username +
", password=" + password +
", enable=" + enable +
", deleted=" + deleted +
", version=" + version +
"}"
return "User{id=$id, username=$username, password=$password, enable=$enable, deleted=$deleted, version=$version}"
}
}

View File

@@ -3,7 +3,10 @@ package top.fatweb.api.handler
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.http.converter.HttpMessageNotReadableException
import org.springframework.security.authentication.BadCredentialsException
import org.springframework.security.authentication.InsufficientAuthenticationException
import org.springframework.security.authentication.InternalAuthenticationServiceException
import org.springframework.web.bind.MethodArgumentNotValidException
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.RestControllerAdvice
import top.fatweb.api.entity.common.ResponseCode
@@ -26,6 +29,22 @@ class ExceptionHandler {
ResponseResult.fail(ResponseCode.SYSTEM_REQUEST_ILLEGAL, e.localizedMessage.split(":")[0], null)
}
is MethodArgumentNotValidException -> {
log.debug(e.localizedMessage, e)
val errorMessage = e.allErrors.map { error -> error.defaultMessage }.joinToString(". ")
ResponseResult.fail(ResponseCode.SYSTEM_ARGUMENT_NOT_VALID, errorMessage, null)
}
is InternalAuthenticationServiceException -> {
log.debug(e.localizedMessage, e)
ResponseResult.fail(ResponseCode.SYSTEM_USERNAME_NOT_FOUND, e.localizedMessage, null)
}
is BadCredentialsException -> {
log.debug(e.localizedMessage, e)
ResponseResult.fail(ResponseCode.SYSTEM_LOGIN_USERNAME_PASSWORD_ERROR, e.localizedMessage, null)
}
else -> {
log.error(e.localizedMessage, e)
ResponseResult.fail(ResponseCode.SYSTEM_ERROR, data = null)

View File

@@ -0,0 +1,19 @@
package top.fatweb.api.service.permission.impl
import com.baomidou.mybatisplus.extension.kotlin.KtQueryWrapper
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.stereotype.Service
import top.fatweb.api.entity.permission.LoginUser
import top.fatweb.api.entity.permission.User
import top.fatweb.api.service.IUserService
@Service
class UserDetailsServiceImpl(val userService: IUserService) : UserDetailsService {
override fun loadUserByUsername(username: String?): UserDetails {
val user = userService.getOne(KtQueryWrapper(User()).eq(User::username, username))
user ?: let { throw Exception("Username not found") }
return LoginUser(user)
}
}

View File

@@ -4,7 +4,7 @@ app:
# token-prefix: "Bearer " # Token prefix
# jwt-ttl: 2 # The life of token
# jwt-ttl-unit: hours # Unit of life of token
jwt-key: $uuid$ # Key to generate token
jwt-key: $uuid$ # Key to generate token (Only numbers and letters allow)
# jwt-issuer: FatWeb # Token issuer
server:

View File

@@ -16,4 +16,15 @@ class FatWebApiApplicationTests {
fun removePrefixTest() {
assertEquals("12312", "Bearer 12312".removePrefix(SecurityConstants.tokenPrefix))
}
/*
@Test
fun addUser(@Autowired userService: IUserService, @Autowired passwordEncoder: PasswordEncoder) {
val username = "admin"
val rawPassword = "admin"
val encodedPassword = passwordEncoder.encode(rawPassword)
val user = User(username, encodedPassword)
userService.save(user)
}
*/
}