Finish sign api. Optimize code.
This commit is contained in:
@@ -75,7 +75,9 @@ class SecurityConfig(
|
||||
"/swagger-ui.html",
|
||||
"/favicon.ico",
|
||||
"/login",
|
||||
"/register"
|
||||
"/register",
|
||||
"/forget",
|
||||
"/retrieve"
|
||||
).anonymous()
|
||||
// Authentication required
|
||||
.anyRequest().authenticated()
|
||||
|
||||
@@ -9,9 +9,7 @@ import org.springframework.web.bind.annotation.RequestBody
|
||||
import top.fatweb.api.annotation.BaseController
|
||||
import top.fatweb.api.entity.common.ResponseCode
|
||||
import top.fatweb.api.entity.common.ResponseResult
|
||||
import top.fatweb.api.param.permission.LoginParam
|
||||
import top.fatweb.api.param.permission.RegisterParam
|
||||
import top.fatweb.api.param.permission.VerifyParam
|
||||
import top.fatweb.api.param.permission.*
|
||||
import top.fatweb.api.service.permission.IAuthenticationService
|
||||
import top.fatweb.api.util.WebUtil
|
||||
import top.fatweb.api.vo.permission.LoginVo
|
||||
@@ -49,7 +47,7 @@ class AuthenticationController(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Operation(summary = "发送验证邮箱")
|
||||
@Operation(summary = "发送验证邮件")
|
||||
@PostMapping("/resend")
|
||||
fun resend(): ResponseResult<Nothing> {
|
||||
authenticationService.resend()
|
||||
@@ -58,12 +56,12 @@ class AuthenticationController(
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify
|
||||
* Verify email
|
||||
*
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Operation(summary = "验证")
|
||||
@Operation(summary = "验证邮箱")
|
||||
@PostMapping("/verify")
|
||||
fun verify(@Valid @RequestBody verifyParam: VerifyParam): ResponseResult<Nothing> {
|
||||
authenticationService.verify(verifyParam)
|
||||
@@ -71,6 +69,34 @@ class AuthenticationController(
|
||||
return ResponseResult.success(ResponseCode.PERMISSION_VERIFY_SUCCESS)
|
||||
}
|
||||
|
||||
/**
|
||||
* Forget password
|
||||
*
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Operation(summary = "忘记密码")
|
||||
@PostMapping("/forget")
|
||||
fun forget(request: HttpServletRequest, @Valid @RequestBody forgetParam: ForgetParam): ResponseResult<Nothing> {
|
||||
authenticationService.forget(request, forgetParam)
|
||||
|
||||
return ResponseResult.success(ResponseCode.PERMISSION_FORGET_SUCCESS)
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve password
|
||||
*
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Operation(summary = "找回密码")
|
||||
@PostMapping("/retrieve")
|
||||
fun retrieve(request: HttpServletRequest, @Valid @RequestBody retrieveParam: RetrieveParam): ResponseResult<Nothing> {
|
||||
authenticationService.retrieve(request, retrieveParam)
|
||||
|
||||
return ResponseResult.success(ResponseCode.PERMISSION_RETRIEVE_SUCCESS)
|
||||
}
|
||||
|
||||
/**
|
||||
* Login
|
||||
*
|
||||
|
||||
@@ -21,6 +21,8 @@ enum class ResponseCode(val code: Int) {
|
||||
PERMISSION_REGISTER_SUCCESS(BusinessCode.PERMISSION, 4),
|
||||
PERMISSION_RESEND_SUCCESS(BusinessCode.PERMISSION, 5),
|
||||
PERMISSION_VERIFY_SUCCESS(BusinessCode.PERMISSION, 6),
|
||||
PERMISSION_FORGET_SUCCESS(BusinessCode.PERMISSION, 7),
|
||||
PERMISSION_RETRIEVE_SUCCESS(BusinessCode.PERMISSION, 8),
|
||||
|
||||
PERMISSION_UNAUTHORIZED(BusinessCode.PERMISSION, 50),
|
||||
PERMISSION_USERNAME_NOT_FOUND(BusinessCode.PERMISSION, 51),
|
||||
@@ -37,6 +39,9 @@ enum class ResponseCode(val code: Int) {
|
||||
PERMISSION_NO_VERIFICATION_REQUIRED(BusinessCode.PERMISSION, 62),
|
||||
PERMISSION_VERIFY_CODE_ERROR_OR_EXPIRED(BusinessCode.PERMISSION, 63),
|
||||
PERMISSION_ACCOUNT_NEED_INIT(BusinessCode.PERMISSION, 64),
|
||||
PERMISSION_USER_NOT_FOUND(BusinessCode.PERMISSION, 65),
|
||||
PERMISSION_RETRIEVE_CODE_ERROR_OR_EXPIRED(BusinessCode.PERMISSION, 66),
|
||||
PERMISSION_ACCOUNT_NEED_RESET_PASSWORD(BusinessCode.PERMISSION, 67),
|
||||
|
||||
DATABASE_SELECT_SUCCESS(BusinessCode.DATABASE, 0),
|
||||
DATABASE_SELECT_FAILED(BusinessCode.DATABASE, 5),
|
||||
|
||||
@@ -47,7 +47,7 @@ class User() : Serializable {
|
||||
var password: String? = null
|
||||
|
||||
/**
|
||||
* Verify
|
||||
* Verify email
|
||||
*
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
@@ -55,6 +55,15 @@ class User() : Serializable {
|
||||
@TableField("verify")
|
||||
var verify: String? = null
|
||||
|
||||
/**
|
||||
* Forget password
|
||||
*
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@TableField("forget")
|
||||
var forget: String? = null
|
||||
|
||||
/**
|
||||
* Locking
|
||||
*
|
||||
@@ -242,6 +251,6 @@ class User() : Serializable {
|
||||
var operations: List<Operation>? = null
|
||||
|
||||
override fun toString(): String {
|
||||
return "User(id=$id, username=$username, password=$password, locking=$locking, expiration=$expiration, credentialsExpiration=$credentialsExpiration, enable=$enable, currentLoginTime=$currentLoginTime, currentLoginIp=$currentLoginIp, lastLoginTime=$lastLoginTime, lastLoginIp=$lastLoginIp, createTime=$createTime, updateTime=$updateTime, deleted=$deleted, version=$version, userInfo=$userInfo, roles=$roles, groups=$groups, modules=$modules, menus=$menus, funcs=$funcs, operations=$operations)"
|
||||
return "User(id=$id, username=$username, password=$password, verify=$verify, forget=$forget, locking=$locking, expiration=$expiration, credentialsExpiration=$credentialsExpiration, enable=$enable, currentLoginTime=$currentLoginTime, currentLoginIp=$currentLoginIp, lastLoginTime=$lastLoginTime, lastLoginIp=$lastLoginIp, createTime=$createTime, updateTime=$updateTime, deleted=$deleted, version=$version, userInfo=$userInfo, roles=$roles, groups=$groups, modules=$modules, menus=$menus, funcs=$funcs, operations=$operations)"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package top.fatweb.api.exception
|
||||
|
||||
/**
|
||||
* Account need reset password exception
|
||||
*
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class AccountNeedResetPasswordException : RuntimeException("Account need reset password")
|
||||
@@ -0,0 +1,3 @@
|
||||
package top.fatweb.api.exception
|
||||
|
||||
class RetrieveCodeErrorOrExpiredException : RuntimeException("Retrieve code error or expired")
|
||||
@@ -0,0 +1,3 @@
|
||||
package top.fatweb.api.exception
|
||||
|
||||
class UserNotFoundException : RuntimeException("User not found")
|
||||
@@ -121,6 +121,11 @@ class ExceptionHandler {
|
||||
ResponseResult.fail(ResponseCode.PERMISSION_ACCESS_DENIED, "Access Denied", null)
|
||||
}
|
||||
|
||||
is UserNotFoundException -> {
|
||||
logger.debug(e.localizedMessage, e)
|
||||
ResponseResult.fail(ResponseCode.PERMISSION_USER_NOT_FOUND, e.localizedMessage, null)
|
||||
}
|
||||
|
||||
is NoVerificationRequiredException -> {
|
||||
logger.debug(e.localizedMessage, e)
|
||||
ResponseResult.fail(ResponseCode.PERMISSION_NO_VERIFICATION_REQUIRED, e.localizedMessage, null)
|
||||
@@ -136,6 +141,16 @@ class ExceptionHandler {
|
||||
ResponseResult.fail(ResponseCode.PERMISSION_ACCOUNT_NEED_INIT, e.localizedMessage, null)
|
||||
}
|
||||
|
||||
is RetrieveCodeErrorOrExpiredException -> {
|
||||
logger.debug(e.localizedMessage, e)
|
||||
ResponseResult.fail(ResponseCode.PERMISSION_RETRIEVE_CODE_ERROR_OR_EXPIRED, e.localizedMessage, null)
|
||||
}
|
||||
|
||||
is AccountNeedResetPasswordException -> {
|
||||
logger.debug(e.localizedMessage, e)
|
||||
ResponseResult.fail(ResponseCode.PERMISSION_ACCOUNT_NEED_RESET_PASSWORD, e.localizedMessage, null)
|
||||
}
|
||||
|
||||
|
||||
is BadSqlGrammarException -> {
|
||||
logger.debug(e.localizedMessage, e)
|
||||
|
||||
@@ -3,6 +3,7 @@ package top.fatweb.api.mapper.permission
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage
|
||||
import org.apache.ibatis.annotations.Mapper
|
||||
import org.apache.ibatis.annotations.Param
|
||||
import top.fatweb.api.entity.permission.Group
|
||||
|
||||
/**
|
||||
@@ -26,7 +27,11 @@ interface GroupMapper : BaseMapper<Group> {
|
||||
* @since 1.0.0
|
||||
* @see IPage
|
||||
*/
|
||||
fun selectPage(page: IPage<Long>, searchName: String?, searchRegex: Boolean): IPage<Long>
|
||||
fun selectPage(
|
||||
page: IPage<Long>,
|
||||
@Param("searchName") searchName: String?,
|
||||
@Param("searchRegex") searchRegex: Boolean
|
||||
): IPage<Long>
|
||||
|
||||
/**
|
||||
* Select group with role list by list of group IDs
|
||||
@@ -37,7 +42,7 @@ interface GroupMapper : BaseMapper<Group> {
|
||||
* @since 1.0.0
|
||||
* @see Group
|
||||
*/
|
||||
fun selectListWithRoleByIds(groupIds: List<Long>): List<Group>?
|
||||
fun selectListWithRoleByIds(@Param("groupIds") groupIds: List<Long>): List<Group>?
|
||||
|
||||
/**
|
||||
* Select one group by ID
|
||||
@@ -48,5 +53,5 @@ interface GroupMapper : BaseMapper<Group> {
|
||||
* @since 1.0.0
|
||||
* @see Group
|
||||
*/
|
||||
fun selectOneById(id: Long): Group?
|
||||
fun selectOneById(@Param("id") id: Long): Group?
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package top.fatweb.api.mapper.permission
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage
|
||||
import org.apache.ibatis.annotations.Mapper
|
||||
import org.apache.ibatis.annotations.Param
|
||||
import top.fatweb.api.entity.permission.Role
|
||||
|
||||
/**
|
||||
@@ -26,7 +27,11 @@ interface RoleMapper : BaseMapper<Role> {
|
||||
* @since 1.0.0
|
||||
* @see IPage
|
||||
*/
|
||||
fun selectPage(page: IPage<Long>, searchName: String?, searchRegex: Boolean): IPage<Long>
|
||||
fun selectPage(
|
||||
page: IPage<Long>,
|
||||
@Param("searchName") searchName: String?,
|
||||
@Param("searchRegex") searchRegex: Boolean
|
||||
): IPage<Long>
|
||||
|
||||
/**
|
||||
* Select role with power list by list of role IDs
|
||||
@@ -37,7 +42,7 @@ interface RoleMapper : BaseMapper<Role> {
|
||||
* @since 1.0.0
|
||||
* @see Role
|
||||
*/
|
||||
fun selectListWithPowerByIds(roleIds: List<Long>): List<Role>?
|
||||
fun selectListWithPowerByIds(@Param("roleIds") roleIds: List<Long>): List<Role>?
|
||||
|
||||
/**
|
||||
* Select one role by ID
|
||||
@@ -48,5 +53,5 @@ interface RoleMapper : BaseMapper<Role> {
|
||||
* @since 1.0.0
|
||||
* @see Role
|
||||
*/
|
||||
fun selectOneById(id: Long): Role?
|
||||
fun selectOneById(@Param("id") id: Long): Role?
|
||||
}
|
||||
|
||||
@@ -39,7 +39,12 @@ interface UserMapper : BaseMapper<User> {
|
||||
* @since 1.0.0
|
||||
* @see IPage
|
||||
*/
|
||||
fun selectPage(page: IPage<Long>, searchType: String, searchValue: String?, searchRegex: Boolean): IPage<Long>
|
||||
fun selectPage(
|
||||
page: IPage<Long>,
|
||||
@Param("searchType") searchType: String,
|
||||
@Param("searchValue") searchValue: String?,
|
||||
@Param("searchRegex") searchRegex: Boolean
|
||||
): IPage<Long>
|
||||
|
||||
/**
|
||||
* Select user with role and information list by list of user IDs
|
||||
@@ -50,7 +55,7 @@ interface UserMapper : BaseMapper<User> {
|
||||
* @since 1.0.0
|
||||
* @see User
|
||||
*/
|
||||
fun selectListWithRoleInfoByIds(userIds: List<Long>): List<User>
|
||||
fun selectListWithRoleInfoByIds(@Param("userIds") userIds: List<Long>): List<User>
|
||||
|
||||
/**
|
||||
* Select one user by ID
|
||||
@@ -61,7 +66,7 @@ interface UserMapper : BaseMapper<User> {
|
||||
* @since 1.0.0
|
||||
* @see User
|
||||
*/
|
||||
fun selectOneWithRoleInfoById(id: Long): User?
|
||||
fun selectOneWithRoleInfoById(@Param("id") id: Long): User?
|
||||
|
||||
/**
|
||||
* Select all user with information list
|
||||
@@ -81,7 +86,7 @@ interface UserMapper : BaseMapper<User> {
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
fun selectIdsWithRoleIds(roleIds: List<Long>): List<Long>
|
||||
fun selectIdsWithRoleIds(@Param("roleIds") roleIds: List<Long>): List<Long>
|
||||
|
||||
/**
|
||||
* Select user IDs list by list of group IDs
|
||||
@@ -91,5 +96,5 @@ interface UserMapper : BaseMapper<User> {
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
fun selectIdsWithGroupIds(groupIds: List<Long>): List<Long>
|
||||
fun selectIdsWithGroupIds(@Param("groupIds") groupIds: List<Long>): List<Long>
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package top.fatweb.api.mapper.system
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage
|
||||
import org.apache.ibatis.annotations.Mapper
|
||||
import org.apache.ibatis.annotations.Param
|
||||
import top.fatweb.api.entity.system.SysLog
|
||||
import java.time.LocalDateTime
|
||||
|
||||
@@ -34,10 +35,10 @@ interface SysLogMapper : BaseMapper<SysLog> {
|
||||
*/
|
||||
fun selectPage(
|
||||
page: IPage<SysLog>,
|
||||
logType: List<String>?,
|
||||
requestMethod: List<String>?,
|
||||
searchRequestUrl: String?,
|
||||
searchStartTime: LocalDateTime?,
|
||||
searchEndTime: LocalDateTime?
|
||||
@Param("logType") logType: List<String>?,
|
||||
@Param("requestMethod") requestMethod: List<String>?,
|
||||
@Param("searchRequestUrl") searchRequestUrl: String?,
|
||||
@Param("searchStartTime") searchStartTime: LocalDateTime?,
|
||||
@Param("searchEndTime") searchEndTime: LocalDateTime?
|
||||
): IPage<SysLog>
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ open class PageSortParam {
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "分页页码", example = "1", defaultValue = "1")
|
||||
@Schema(description = "分页页码", defaultValue = "1", example = "1")
|
||||
@field:Min(1, message = "Pagination page number must be a positive integer")
|
||||
var currentPage: Long = 1
|
||||
|
||||
@@ -26,7 +26,7 @@ open class PageSortParam {
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "分页大小", example = "20", defaultValue = "20")
|
||||
@Schema(description = "分页大小", defaultValue = "20", example = "20")
|
||||
@field:Min(1, message = "The number of data per page must be a positive integer")
|
||||
var pageSize: Long = 20
|
||||
|
||||
@@ -45,6 +45,6 @@ open class PageSortParam {
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "排序方式", example = "desc", allowableValues = ["desc", "asc"])
|
||||
@Schema(description = "排序方式", allowableValues = ["desc", "asc"], defaultValue = "desc", example = "desc")
|
||||
var sortOrder: String? = null
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package top.fatweb.api.param.permission
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema
|
||||
import jakarta.validation.constraints.NotBlank
|
||||
import jakarta.validation.constraints.Pattern
|
||||
|
||||
/**
|
||||
* Forget password parameters
|
||||
*
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "忘记密码请求参数")
|
||||
data class ForgetParam(
|
||||
/**
|
||||
* Email
|
||||
*
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "邮箱", required = true, example = "user@email.com")
|
||||
@field:NotBlank(message = "Email can not be blank")
|
||||
@field:Pattern(regexp = "^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*\$", message = "Illegal email address")
|
||||
val email: String?
|
||||
)
|
||||
@@ -17,7 +17,7 @@ data class LoginParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "账户", example = "test", required = true)
|
||||
@Schema(description = "账户", required = true, example = "test")
|
||||
@field:NotBlank(message = "Account can not be blank")
|
||||
val account: String?,
|
||||
|
||||
@@ -27,7 +27,7 @@ data class LoginParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "密码", example = "test123456", required = true)
|
||||
@Schema(description = "密码", required = true)
|
||||
@field:NotBlank(message = "Password can not be blank")
|
||||
val password: String?
|
||||
)
|
||||
@@ -19,7 +19,7 @@ data class RegisterParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "用户名", example = "abc", required = true)
|
||||
@Schema(description = "用户名", required = true, example = "abc")
|
||||
@field:NotBlank(message = "Username can not be blank")
|
||||
@field:Pattern(regexp = "[a-zA-Z-_][0-9a-zA-Z-_]{2,38}", message = "Illegal username")
|
||||
val username: String?,
|
||||
@@ -30,7 +30,7 @@ data class RegisterParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "邮箱", example = "guest@fatweb.top", required = true)
|
||||
@Schema(description = "邮箱", required = true, example = "user@email.com")
|
||||
@field:NotBlank(message = "Email can not be blank")
|
||||
@field:Pattern(regexp = "^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*\$", message = "Illegal email address")
|
||||
val email: String?,
|
||||
@@ -41,7 +41,7 @@ data class RegisterParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "密码", example = "test123456", required = true)
|
||||
@Schema(description = "密码", required = true)
|
||||
@field:NotBlank(message = "Password can not be blank")
|
||||
@field:Size(min = 10, max = 30)
|
||||
val password: String?
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package top.fatweb.api.param.permission
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema
|
||||
import jakarta.validation.constraints.NotBlank
|
||||
import jakarta.validation.constraints.Size
|
||||
|
||||
/**
|
||||
* Retrieve password parameters
|
||||
*
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "找回密码请求参数")
|
||||
data class RetrieveParam(
|
||||
/**
|
||||
* Code
|
||||
*
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "验证码", required = true)
|
||||
@field:NotBlank(message = "Code can not be blank")
|
||||
val code: String?,
|
||||
|
||||
/**
|
||||
* New password
|
||||
*
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "新密码")
|
||||
@field:NotBlank(message = "New password can not be blank")
|
||||
@field:Size(min = 10, max = 30)
|
||||
val password: String?
|
||||
)
|
||||
@@ -4,12 +4,12 @@ import io.swagger.v3.oas.annotations.media.Schema
|
||||
import jakarta.validation.constraints.NotBlank
|
||||
|
||||
/**
|
||||
* Verify parameters
|
||||
* Verify email parameters
|
||||
*
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "验证请求参数")
|
||||
@Schema(description = "验证邮箱请求参数")
|
||||
data class VerifyParam(
|
||||
/**
|
||||
* Code
|
||||
@@ -17,7 +17,7 @@ data class VerifyParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "验证码", example = "9c4b8199-1dbe-4f6f-96a5-fe1d75cc6a65", required = true)
|
||||
@Schema(description = "验证码", required = true)
|
||||
@field:NotBlank(message = "Code can not be blank")
|
||||
val code: String?,
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ data class GroupAddParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "用户组名称")
|
||||
@Schema(description = "用户组名称", required = true, example = "Group_1")
|
||||
@field:NotBlank(message = "Name can not be blank")
|
||||
val name: String?,
|
||||
|
||||
@@ -27,7 +27,7 @@ data class GroupAddParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "启用", allowableValues = ["true", "false"], defaultValue = "true")
|
||||
@Schema(description = "启用", allowableValues = ["true", "false"], defaultValue = "true", example = "true")
|
||||
val enable: Boolean = true,
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,6 @@ data class GroupDeleteParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "用户组 ID 列表")
|
||||
@Schema(description = "用户组 ID 列表", required = true)
|
||||
val ids: List<Long>
|
||||
)
|
||||
|
||||
@@ -18,7 +18,7 @@ data class GroupGetParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "查询用户组名称")
|
||||
@Schema(description = "查询用户组名称", example = "Group_1")
|
||||
val searchName: String?,
|
||||
|
||||
/**
|
||||
@@ -27,6 +27,11 @@ data class GroupGetParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "查询使用正则表达式", allowableValues = ["true", "false"], defaultValue = "false")
|
||||
@Schema(
|
||||
description = "查询使用正则表达式",
|
||||
allowableValues = ["true", "false"],
|
||||
defaultValue = "false",
|
||||
example = "false"
|
||||
)
|
||||
val searchRegex: Boolean = false,
|
||||
) : PageSortParam()
|
||||
|
||||
@@ -18,7 +18,7 @@ data class GroupUpdateParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "用户组 ID")
|
||||
@Schema(description = "用户组 ID", required = true)
|
||||
@field:NotNull(message = "ID can not be null")
|
||||
val id: Long?,
|
||||
|
||||
@@ -28,7 +28,7 @@ data class GroupUpdateParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "用户组名称")
|
||||
@Schema(description = "用户组名称", required = true, example = "Group_1")
|
||||
@field:NotBlank(message = "Name can not be blank")
|
||||
val name: String?,
|
||||
|
||||
@@ -38,7 +38,7 @@ data class GroupUpdateParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "启用", allowableValues = ["true", "false"], defaultValue = "true")
|
||||
@Schema(description = "启用", allowableValues = ["true", "false"], defaultValue = "true", example = "true")
|
||||
val enable: Boolean = true,
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,7 +17,7 @@ data class GroupUpdateStatusParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "用户组 ID")
|
||||
@Schema(description = "用户组 ID", required = true)
|
||||
@field:NotNull(message = "ID can not be null")
|
||||
val id: Long?,
|
||||
|
||||
@@ -27,6 +27,6 @@ data class GroupUpdateStatusParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "启用", allowableValues = ["true", "false"], defaultValue = "true")
|
||||
@Schema(description = "启用", allowableValues = ["true", "false"], defaultValue = "true", example = "true")
|
||||
val enable: Boolean = true
|
||||
)
|
||||
@@ -17,7 +17,7 @@ data class RoleAddParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "角色名称")
|
||||
@Schema(description = "角色名称", required = true, example = "Role_1")
|
||||
@field:NotBlank(message = "Name can not be blank")
|
||||
val name: String?,
|
||||
|
||||
@@ -27,7 +27,7 @@ data class RoleAddParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "启用", allowableValues = ["true", "false"], defaultValue = "true")
|
||||
@Schema(description = "启用", allowableValues = ["true", "false"], defaultValue = "true", example = "true")
|
||||
val enable: Boolean = true,
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,6 @@ data class RoleDeleteParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "角色 ID 列表")
|
||||
@Schema(description = "角色 ID 列表", required = true)
|
||||
val ids: List<Long>
|
||||
)
|
||||
|
||||
@@ -18,7 +18,7 @@ data class RoleGetParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "查询角色名称")
|
||||
@Schema(description = "查询角色名称", example = "Role_1")
|
||||
val searchName: String?,
|
||||
|
||||
/**
|
||||
@@ -27,6 +27,11 @@ data class RoleGetParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "查询使用正则表达式", allowableValues = ["true", "false"], defaultValue = "false")
|
||||
@Schema(
|
||||
description = "查询使用正则表达式",
|
||||
allowableValues = ["true", "false"],
|
||||
defaultValue = "false",
|
||||
example = "false"
|
||||
)
|
||||
val searchRegex: Boolean = false,
|
||||
) : PageSortParam()
|
||||
|
||||
@@ -18,7 +18,7 @@ data class RoleUpdateParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "角色 ID")
|
||||
@Schema(description = "角色 ID", required = true)
|
||||
@field:NotNull(message = "Role id can not be null")
|
||||
val id: Long?,
|
||||
|
||||
@@ -28,7 +28,7 @@ data class RoleUpdateParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "角色名称")
|
||||
@Schema(description = "角色名称", required = true, example = "Role_1")
|
||||
@field:NotBlank(message = "Name can not be blank")
|
||||
val name: String?,
|
||||
|
||||
@@ -38,7 +38,7 @@ data class RoleUpdateParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "启用", allowableValues = ["true", "false"], defaultValue = "true")
|
||||
@Schema(description = "启用", allowableValues = ["true", "false"], defaultValue = "true", example = "true")
|
||||
val enable: Boolean = true,
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,7 +17,7 @@ data class RoleUpdateStatusParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "角色 ID")
|
||||
@Schema(description = "角色 ID", required = true)
|
||||
@field:NotNull(message = "Role id can not be null")
|
||||
val id: Long?,
|
||||
|
||||
@@ -27,6 +27,6 @@ data class RoleUpdateStatusParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "启用", allowableValues = ["true", "false"], defaultValue = "true")
|
||||
@Schema(description = "启用", allowableValues = ["true", "false"], defaultValue = "true", example = "true")
|
||||
val enable: Boolean = true
|
||||
)
|
||||
@@ -19,7 +19,7 @@ data class UserAddParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "用户名")
|
||||
@Schema(description = "用户名", required = true, example = "User_1")
|
||||
@field:NotBlank(message = "Username can not be blank")
|
||||
val username: String?,
|
||||
|
||||
@@ -38,7 +38,7 @@ data class UserAddParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "是否已验证")
|
||||
@Schema(description = "是否已验证", allowableValues = ["true", "false"], defaultValue = "false", example = "false")
|
||||
val verified: Boolean = false,
|
||||
|
||||
/**
|
||||
@@ -47,7 +47,7 @@ data class UserAddParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "锁定", allowableValues = ["true", "false"], defaultValue = "false")
|
||||
@Schema(description = "锁定", allowableValues = ["true", "false"], defaultValue = "false", example = "false")
|
||||
val locking: Boolean = false,
|
||||
|
||||
/**
|
||||
@@ -57,7 +57,7 @@ data class UserAddParam(
|
||||
* @since 1.0.0
|
||||
* @see LocalDateTime
|
||||
*/
|
||||
@Schema(description = "过期时间")
|
||||
@Schema(description = "过期时间", example = "1900-01-01T00:00:00.000Z")
|
||||
val expiration: LocalDateTime?,
|
||||
|
||||
/**
|
||||
@@ -67,7 +67,7 @@ data class UserAddParam(
|
||||
* @since 1.0.0
|
||||
* @see LocalDateTime
|
||||
*/
|
||||
@Schema(description = "认证过期时间")
|
||||
@Schema(description = "认证过期时间", example = "1900-01-01T00:00:00.000Z")
|
||||
val credentialsExpiration: LocalDateTime?,
|
||||
|
||||
/**
|
||||
@@ -76,7 +76,7 @@ data class UserAddParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "启用", allowableValues = ["true", "false"], defaultValue = "true")
|
||||
@Schema(description = "启用", allowableValues = ["true", "false"], defaultValue = "true", example = "true")
|
||||
val enable: Boolean = true,
|
||||
|
||||
/**
|
||||
@@ -85,7 +85,7 @@ data class UserAddParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "昵称")
|
||||
@Schema(description = "昵称", required = true, example = "Nickname_1")
|
||||
@field:NotBlank(message = "Nickname can not be blank")
|
||||
val nickname: String?,
|
||||
|
||||
@@ -104,7 +104,8 @@ data class UserAddParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "邮箱")
|
||||
@Schema(description = "邮箱", required = true, example = "user@email.com")
|
||||
@NotBlank(message = "Email can not be blank")
|
||||
@Pattern(regexp = "^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*\$", message = "Illegal email address")
|
||||
val email: String?,
|
||||
|
||||
|
||||
@@ -16,6 +16,6 @@ data class UserDeleteParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "用户 ID 列表")
|
||||
@Schema(description = "用户 ID 列表", required = true)
|
||||
val ids: List<Long>
|
||||
)
|
||||
|
||||
@@ -18,7 +18,12 @@ data class UserGetParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "搜索类型", allowableValues = ["ALL", "ID", "USERNAME", "NICKNAME", "EMAIL"], defaultValue = "ALL")
|
||||
@Schema(
|
||||
description = "搜索类型",
|
||||
allowableValues = ["ALL", "ID", "USERNAME", "NICKNAME", "EMAIL"],
|
||||
defaultValue = "ALL",
|
||||
example = "ALL"
|
||||
)
|
||||
val searchType: String = "ALL",
|
||||
|
||||
/**
|
||||
@@ -27,7 +32,7 @@ data class UserGetParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "查询内容")
|
||||
@Schema(description = "查询内容", example = "User_1")
|
||||
val searchValue: String?,
|
||||
|
||||
/**
|
||||
@@ -36,6 +41,11 @@ data class UserGetParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "查询使用正则表达式", allowableValues = ["true", "false"], defaultValue = "false")
|
||||
@Schema(
|
||||
description = "查询使用正则表达式",
|
||||
allowableValues = ["true", "false"],
|
||||
defaultValue = "false",
|
||||
example = "false"
|
||||
)
|
||||
val searchRegex: Boolean = false,
|
||||
) : PageSortParam()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package top.fatweb.api.param.permission.user
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema
|
||||
import jakarta.validation.constraints.NotBlank
|
||||
import jakarta.validation.constraints.NotNull
|
||||
import jakarta.validation.constraints.Pattern
|
||||
import java.time.LocalDateTime
|
||||
@@ -19,7 +20,7 @@ data class UserUpdateParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "用户 ID")
|
||||
@Schema(description = "用户 ID", required = true)
|
||||
@field:NotNull(message = "ID can not be null")
|
||||
val id: Long?,
|
||||
|
||||
@@ -29,7 +30,8 @@ data class UserUpdateParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "用户名")
|
||||
@Schema(description = "用户名", required = true, example = "User_1")
|
||||
@field:NotBlank(message = "Username can not be blank")
|
||||
val username: String?,
|
||||
|
||||
/**
|
||||
@@ -38,7 +40,7 @@ data class UserUpdateParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "是否已验证")
|
||||
@Schema(description = "是否已验证", allowableValues = ["true", "false"], defaultValue = "false", example = "false")
|
||||
val verified: Boolean = false,
|
||||
|
||||
/**
|
||||
@@ -47,7 +49,7 @@ data class UserUpdateParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "锁定", allowableValues = ["true", "false"], defaultValue = "false")
|
||||
@Schema(description = "锁定", allowableValues = ["true", "false"], defaultValue = "false", example = "false")
|
||||
val locking: Boolean = false,
|
||||
|
||||
/**
|
||||
@@ -57,7 +59,7 @@ data class UserUpdateParam(
|
||||
* @since 1.0.0
|
||||
* @see LocalDateTime
|
||||
*/
|
||||
@Schema(description = "过期时间")
|
||||
@Schema(description = "过期时间", example = "1900-01-01T00:00:00.000Z")
|
||||
val expiration: LocalDateTime?,
|
||||
|
||||
/**
|
||||
@@ -67,7 +69,7 @@ data class UserUpdateParam(
|
||||
* @since 1.0.0
|
||||
* @see LocalDateTime
|
||||
*/
|
||||
@Schema(description = "认证过期时间")
|
||||
@Schema(description = "认证过期时间", example = "1900-01-01T00:00:00.000Z")
|
||||
val credentialsExpiration: LocalDateTime?,
|
||||
|
||||
/**
|
||||
@@ -76,7 +78,7 @@ data class UserUpdateParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "启用", allowableValues = ["true", "false"], defaultValue = "true")
|
||||
@Schema(description = "启用", allowableValues = ["true", "false"], defaultValue = "true", example = "true")
|
||||
val enable: Boolean = true,
|
||||
|
||||
/**
|
||||
@@ -85,7 +87,8 @@ data class UserUpdateParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "昵称")
|
||||
@Schema(description = "昵称", required = true, example = "Nickname_1")
|
||||
@field:NotBlank(message = "Nickname can not be blank")
|
||||
val nickname: String?,
|
||||
|
||||
/**
|
||||
@@ -103,7 +106,8 @@ data class UserUpdateParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "邮箱")
|
||||
@Schema(description = "邮箱", required = true, example = "user@email.com")
|
||||
@NotBlank(message = "Email can not be blank")
|
||||
@Pattern(regexp = "^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*\$", message = "Illegal email address")
|
||||
val email: String?,
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ data class UserUpdatePasswordParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "用户 ID")
|
||||
@Schema(description = "用户 ID", required = true)
|
||||
@field:NotNull(message = "ID can not be null")
|
||||
val id: Long?,
|
||||
|
||||
@@ -29,7 +29,7 @@ data class UserUpdatePasswordParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "新密码")
|
||||
@Schema(description = "新密码", required = true)
|
||||
@field:NotBlank(message = "Password can not be blank")
|
||||
val password: String?,
|
||||
|
||||
@@ -40,6 +40,6 @@ data class UserUpdatePasswordParam(
|
||||
* @since 1.0.0
|
||||
* @see LocalDateTime
|
||||
*/
|
||||
@Schema(description = "认证过期时间")
|
||||
@Schema(description = "认证过期时间", example = "1900-01-01T00:00:00.000Z")
|
||||
val credentialsExpiration: LocalDateTime?
|
||||
)
|
||||
|
||||
@@ -2,6 +2,7 @@ package top.fatweb.api.param.system
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.EnumValue
|
||||
import com.fasterxml.jackson.annotation.JsonValue
|
||||
import io.swagger.v3.oas.annotations.media.Schema
|
||||
|
||||
/**
|
||||
* Get active information parameters
|
||||
@@ -10,6 +11,18 @@ import com.fasterxml.jackson.annotation.JsonValue
|
||||
* @since 1.0.0
|
||||
*/
|
||||
data class ActiveInfoGetParam(
|
||||
/**
|
||||
* Scope
|
||||
*
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(
|
||||
description = "范围",
|
||||
allowableValues = ["WEAK", "MONTH", "QUARTER", "YEAR", "TWO_YEARS", "THREE_YEARS", "FIVE_YEARS", "ALL"],
|
||||
defaultValue = "WEAK",
|
||||
example = "WEAK"
|
||||
)
|
||||
val scope: Scope = Scope.WEAK
|
||||
) {
|
||||
enum class Scope(@field:EnumValue @field:JsonValue val code: String) {
|
||||
|
||||
@@ -17,7 +17,7 @@ data class MailSendParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "接收者")
|
||||
@Schema(description = "接收者", required = true, example = "user@email.com")
|
||||
@field:NotBlank
|
||||
val to: String?
|
||||
)
|
||||
|
||||
@@ -2,6 +2,7 @@ package top.fatweb.api.param.system
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.EnumValue
|
||||
import com.fasterxml.jackson.annotation.JsonValue
|
||||
import io.swagger.v3.oas.annotations.media.Schema
|
||||
|
||||
/**
|
||||
* Get online information parameters
|
||||
@@ -10,6 +11,18 @@ import com.fasterxml.jackson.annotation.JsonValue
|
||||
* @since 1.0.0
|
||||
*/
|
||||
data class OnlineInfoGetParam(
|
||||
/**
|
||||
* Scope
|
||||
*
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(
|
||||
description = "范围",
|
||||
allowableValues = ["WEAK", "MONTH", "QUARTER", "YEAR", "TWO_YEARS", "THREE_YEARS", "FIVE_YEARS", "ALL"],
|
||||
defaultValue = "WEAK",
|
||||
example = "WEAK"
|
||||
)
|
||||
val scope: Scope = Scope.WEAK
|
||||
) {
|
||||
enum class Scope(@field:EnumValue @field:JsonValue val code: String) {
|
||||
|
||||
@@ -20,7 +20,7 @@ data class SysLogGetParam(
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "类型过滤(多个使用逗号分隔)", example = "INFO", allowableValues = ["INFO", "ERROR"])
|
||||
@Schema(description = "类型过滤(多个使用逗号分隔)", allowableValues = ["INFO", "ERROR"], example = "INFO")
|
||||
val logType: String?,
|
||||
|
||||
/**
|
||||
@@ -31,8 +31,8 @@ data class SysLogGetParam(
|
||||
*/
|
||||
@Schema(
|
||||
description = "请求方式过滤(多个使用逗号分隔)",
|
||||
example = "GET,POST",
|
||||
allowableValues = ["GET", "POST", "PUT", "PATCH", "DELETE", "DELETE", "OPTIONS"]
|
||||
allowableValues = ["GET", "POST", "PUT", "PATCH", "DELETE", "DELETE", "OPTIONS"],
|
||||
example = "GET,POST"
|
||||
)
|
||||
val requestMethod: String?,
|
||||
|
||||
@@ -63,7 +63,7 @@ data class SysLogGetParam(
|
||||
* @since 1.0.0
|
||||
* @see LocalDateTime
|
||||
*/
|
||||
@Schema(description = "查询开始时间")
|
||||
@Schema(description = "查询开始时间", example = "1900-01-01T00:00:00.000Z")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
|
||||
val searchStartTime: LocalDateTime?,
|
||||
|
||||
@@ -74,7 +74,7 @@ data class SysLogGetParam(
|
||||
* @since 1.0.0
|
||||
* @see LocalDateTime
|
||||
*/
|
||||
@Schema(description = "查询结束时间")
|
||||
@Schema(description = "查询结束时间", example = "1900-01-01T00:00:00.000Z")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
|
||||
val searchEndTime: LocalDateTime?
|
||||
) : PageSortParam()
|
||||
@@ -2,9 +2,7 @@ package top.fatweb.api.service.permission
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import top.fatweb.api.entity.permission.User
|
||||
import top.fatweb.api.param.permission.LoginParam
|
||||
import top.fatweb.api.param.permission.RegisterParam
|
||||
import top.fatweb.api.param.permission.VerifyParam
|
||||
import top.fatweb.api.param.permission.*
|
||||
import top.fatweb.api.vo.permission.LoginVo
|
||||
import top.fatweb.api.vo.permission.RegisterVo
|
||||
import top.fatweb.api.vo.permission.TokenVo
|
||||
@@ -33,13 +31,29 @@ interface IAuthenticationService {
|
||||
fun resend()
|
||||
|
||||
/**
|
||||
* Verify
|
||||
* Verify email
|
||||
*
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
fun verify(verifyParam: VerifyParam)
|
||||
|
||||
/**
|
||||
* Forget password
|
||||
*
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
fun forget(request: HttpServletRequest, forgetParam: ForgetParam)
|
||||
|
||||
/**
|
||||
* Retrieve password
|
||||
*
|
||||
* @author FatttSnake, fatttsnake@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
fun retrieve(request: HttpServletRequest, retrieveParam: RetrieveParam)
|
||||
|
||||
/**
|
||||
* Login
|
||||
*
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package top.fatweb.api.service.permission.impl
|
||||
|
||||
import com.baomidou.mybatisplus.extension.kotlin.KtQueryWrapper
|
||||
import com.baomidou.mybatisplus.extension.kotlin.KtUpdateWrapper
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import org.apache.velocity.VelocityContext
|
||||
@@ -17,13 +18,8 @@ import top.fatweb.api.entity.permission.LoginUser
|
||||
import top.fatweb.api.entity.permission.User
|
||||
import top.fatweb.api.entity.permission.UserInfo
|
||||
import top.fatweb.api.entity.system.EventLog
|
||||
import top.fatweb.api.exception.AccountNeedInitException
|
||||
import top.fatweb.api.exception.NoVerificationRequiredException
|
||||
import top.fatweb.api.exception.TokenHasExpiredException
|
||||
import top.fatweb.api.exception.VerificationCodeErrorOrExpiredException
|
||||
import top.fatweb.api.param.permission.LoginParam
|
||||
import top.fatweb.api.param.permission.RegisterParam
|
||||
import top.fatweb.api.param.permission.VerifyParam
|
||||
import top.fatweb.api.exception.*
|
||||
import top.fatweb.api.param.permission.*
|
||||
import top.fatweb.api.properties.SecurityProperties
|
||||
import top.fatweb.api.service.api.v1.IAvatarService
|
||||
import top.fatweb.api.service.permission.IAuthenticationService
|
||||
@@ -71,7 +67,9 @@ class AuthenticationServiceImpl(
|
||||
username = registerParam.username
|
||||
password = passwordEncoder.encode(registerParam.password)
|
||||
verify =
|
||||
"${LocalDateTime.now(ZoneOffset.UTC).toInstant(ZoneOffset.UTC).toEpochMilli()}-${UUID.randomUUID()}-${UUID.randomUUID()}-${UUID.randomUUID()}"
|
||||
"${
|
||||
LocalDateTime.now(ZoneOffset.UTC).toInstant(ZoneOffset.UTC).toEpochMilli()
|
||||
}-${UUID.randomUUID()}-${UUID.randomUUID()}-${UUID.randomUUID()}"
|
||||
locking = 0
|
||||
enable = 1
|
||||
}
|
||||
@@ -83,7 +81,7 @@ class AuthenticationServiceImpl(
|
||||
email = registerParam.email
|
||||
})
|
||||
|
||||
sendVerifyMail(user.username!!, "http://localhost:5173/verify?code=${user.verify!!}", registerParam.email!!)
|
||||
sendVerifyMail(user.username!!, user.verify!!, registerParam.email!!)
|
||||
|
||||
return RegisterVo(userId = user.id)
|
||||
}
|
||||
@@ -95,21 +93,23 @@ class AuthenticationServiceImpl(
|
||||
user.verify ?: throw NoVerificationRequiredException()
|
||||
|
||||
user.verify =
|
||||
"${LocalDateTime.now(ZoneOffset.UTC).toInstant(ZoneOffset.UTC).toEpochMilli()}-${UUID.randomUUID()}-${UUID.randomUUID()}-${UUID.randomUUID()}"
|
||||
"${
|
||||
LocalDateTime.now(ZoneOffset.UTC).toInstant(ZoneOffset.UTC).toEpochMilli()
|
||||
}-${UUID.randomUUID()}-${UUID.randomUUID()}-${UUID.randomUUID()}"
|
||||
user.updateTime = LocalDateTime.now(ZoneOffset.UTC)
|
||||
userService.updateById(user)
|
||||
|
||||
WebUtil.getLoginUser()?.user?.userInfo?.email?.let {
|
||||
sendVerifyMail(user.username!!, "http://localhost:5173/verify?code=${user.verify!!}", it)
|
||||
sendVerifyMail(user.username!!, user.verify!!, it)
|
||||
} ?: throw AccessDeniedException("Access Denied")
|
||||
}
|
||||
|
||||
private fun sendVerifyMail(username: String, verifyUrl: String, email: String) {
|
||||
private fun sendVerifyMail(username: String, code: String, email: String) {
|
||||
val velocityContext = VelocityContext().apply {
|
||||
put("appName", "氮工具")
|
||||
put("appUrl", "http://localhost:5173/")
|
||||
put("username", username)
|
||||
put("verifyUrl", verifyUrl)
|
||||
put("verifyUrl", "http://localhost:5173/verify?code=${code}")
|
||||
}
|
||||
val template = velocityEngine.getTemplate("templates/email-verify-account-cn.vm")
|
||||
|
||||
@@ -147,6 +147,82 @@ class AuthenticationServiceImpl(
|
||||
)
|
||||
}
|
||||
|
||||
@Transactional
|
||||
override fun forget(request: HttpServletRequest, forgetParam: ForgetParam) {
|
||||
val user = userService.getUserWithPowerByAccount(forgetParam.email!!)
|
||||
user ?: let { throw UserNotFoundException() }
|
||||
val code = "${
|
||||
LocalDateTime.now(ZoneOffset.UTC).toInstant(ZoneOffset.UTC).toEpochMilli()
|
||||
}-${UUID.randomUUID()}-${UUID.randomUUID()}-${UUID.randomUUID()}"
|
||||
userService.update(KtUpdateWrapper(User()).eq(User::id, user.id).set(User::forget, code))
|
||||
sendRetrieveMail(user.username!!, request.remoteAddr, code, forgetParam.email)
|
||||
}
|
||||
|
||||
private fun sendRetrieveMail(username: String, ip: String, code: String, email: String) {
|
||||
val velocityContext = VelocityContext().apply {
|
||||
put("appName", "氮工具")
|
||||
put("appUrl", "http://localhost:5173/")
|
||||
put("username", username)
|
||||
put("ipAddress", ip)
|
||||
put("retrieveUrl", "http://localhost:5173/forget?code=${code}")
|
||||
}
|
||||
val template = velocityEngine.getTemplate("templates/email-retrieve-password-cn.vm")
|
||||
|
||||
val stringWriter = StringWriter()
|
||||
template.merge(velocityContext, stringWriter)
|
||||
|
||||
MailUtil.sendSimpleMail(
|
||||
"找回您的密码", stringWriter.toString(), true,
|
||||
email
|
||||
)
|
||||
}
|
||||
|
||||
@Transactional
|
||||
override fun retrieve(request: HttpServletRequest, retrieveParam: RetrieveParam) {
|
||||
val codeStrings = retrieveParam.code!!.split("-")
|
||||
if (codeStrings.size != 16) {
|
||||
throw RetrieveCodeErrorOrExpiredException()
|
||||
}
|
||||
try {
|
||||
if (LocalDateTime.ofInstant(Instant.ofEpochMilli(codeStrings.first().toLong()), ZoneOffset.UTC)
|
||||
.isBefore(LocalDateTime.now(ZoneOffset.UTC).minusHours(2))
|
||||
) {
|
||||
throw RetrieveCodeErrorOrExpiredException()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
throw RetrieveCodeErrorOrExpiredException()
|
||||
}
|
||||
|
||||
val user = userService.getOne(KtQueryWrapper(User()).eq(User::forget, retrieveParam.code))
|
||||
?: throw RetrieveCodeErrorOrExpiredException()
|
||||
val userInfo = userInfoService.getOne(KtQueryWrapper(UserInfo()).eq(UserInfo::userId, user.id))
|
||||
|
||||
userService.update(
|
||||
KtUpdateWrapper(User()).eq(User::id, user.id).set(User::forget, null)
|
||||
.set(User::password, passwordEncoder.encode(retrieveParam.password!!))
|
||||
)
|
||||
|
||||
sendPasswordChangedMail(user.username!!, request.remoteAddr, userInfo!!.email!!)
|
||||
}
|
||||
|
||||
private fun sendPasswordChangedMail(username: String, ip: String, email: String) {
|
||||
val velocityContext = VelocityContext().apply {
|
||||
put("appName", "氮工具")
|
||||
put("appUrl", "http://localhost:5173/")
|
||||
put("username", username)
|
||||
put("ipAddress", ip)
|
||||
}
|
||||
val template = velocityEngine.getTemplate("templates/email-password-changed-cn.vm")
|
||||
|
||||
val stringWriter = StringWriter()
|
||||
template.merge(velocityContext, stringWriter)
|
||||
|
||||
MailUtil.sendSimpleMail(
|
||||
"您的密码已更改", stringWriter.toString(), true,
|
||||
email
|
||||
)
|
||||
}
|
||||
|
||||
@EventLogRecord(EventLog.Event.LOGIN)
|
||||
override fun login(request: HttpServletRequest, loginParam: LoginParam): LoginVo {
|
||||
val usernamePasswordAuthenticationToken =
|
||||
|
||||
@@ -5,7 +5,8 @@ create table if not exists t_user
|
||||
id bigint not null primary key,
|
||||
username varchar(20) not null comment '用户名',
|
||||
password char(70) not null comment '密码',
|
||||
verify varchar(144) null comment '验证信息',
|
||||
verify varchar(144) null comment '验证邮箱',
|
||||
forget varchar(144) null comment '忘记密码',
|
||||
locking int not null comment '锁定',
|
||||
expiration datetime comment '过期时间',
|
||||
credentials_expiration datetime comment '认证过期时间',
|
||||
@@ -19,5 +20,6 @@ create table if not exists t_user
|
||||
deleted bigint not null default 0,
|
||||
version int not null default 0,
|
||||
constraint t_user_unique_username unique (username, deleted),
|
||||
constraint t_user_unique_verify unique (verify, deleted)
|
||||
constraint t_user_unique_verify unique (verify, deleted),
|
||||
constraint t_user_unique_forget unique (forget, deleted)
|
||||
) comment '用户表';
|
||||
78
src/main/resources/templates/email-password-changed-cn.vm
Normal file
78
src/main/resources/templates/email-password-changed-cn.vm
Normal file
@@ -0,0 +1,78 @@
|
||||
<!doctype html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport"
|
||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>您的密码已更改</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: #4D4D4D;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #4E47BB;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
background-color: #F1F2F7;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.view {
|
||||
display: flex;
|
||||
width: 800px;
|
||||
max-width: 100vw;
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
.card {
|
||||
margin: 20px;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
flex: 1;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-bottom: 10px;
|
||||
text-align: center;
|
||||
font-weight: bolder;
|
||||
font-size: 1.6em;
|
||||
color: #4E47BB;
|
||||
}
|
||||
|
||||
.retrieve-button a {
|
||||
padding: 20px 30px;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
font-size: 1.2em;
|
||||
background-color: #4E47BB;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.not-reply {
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="view">
|
||||
<div class="card">
|
||||
<div class="title">密 码 已 更 改</div>
|
||||
<div><strong>${username}</strong>,您好:</div>
|
||||
<div style="text-indent: 2em">您在 <a target="_blank" href=${appUrl}>${appName}(${appUrl})</a> 的密码已更改,操作
|
||||
IP 地址为 [${ipAddress}]。如果不是您自己的操作,请尽快检查您的账号!
|
||||
</div>
|
||||
<div class="not-reply">此邮件由系统自动发送,请勿回复!</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
90
src/main/resources/templates/email-retrieve-password-cn.vm
Normal file
90
src/main/resources/templates/email-retrieve-password-cn.vm
Normal file
@@ -0,0 +1,90 @@
|
||||
<!doctype html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport"
|
||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>找回您的密码</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: #4D4D4D;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #4E47BB;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
background-color: #F1F2F7;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.view {
|
||||
display: flex;
|
||||
width: 800px;
|
||||
max-width: 100vw;
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
.card {
|
||||
margin: 20px;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
flex: 1;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-bottom: 10px;
|
||||
text-align: center;
|
||||
font-weight: bolder;
|
||||
font-size: 1.6em;
|
||||
color: #4E47BB;
|
||||
}
|
||||
|
||||
.retrieve-button {
|
||||
display: flex;
|
||||
margin: 20px;
|
||||
padding-bottom: 60px;
|
||||
justify-content: center;
|
||||
|
||||
}
|
||||
|
||||
.retrieve-button a {
|
||||
padding: 20px 30px;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
font-size: 1.2em;
|
||||
background-color: #4E47BB;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.not-reply {
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="view">
|
||||
<div class="card">
|
||||
<div class="title">找 回 密 码</div>
|
||||
<div><strong>${username}</strong>,您好:</div>
|
||||
<div style="text-indent: 2em">您正在找回 <a target="_blank" href=${appUrl}>${appName}(${appUrl})</a> 的密码,操作
|
||||
IP 地址为 [${ipAddress}],如果是您自己的操作,请在 <u><i>两小时内</i></u> 点击下面的按钮找回您的密码:
|
||||
</div>
|
||||
<div class="retrieve-button"><a target="_blank" href=${retrieveUrl}>找回密码</a></div>
|
||||
<div>如果以上按钮无法点击,请复制此链接到浏览器地址栏中访问:<a target="_blank"
|
||||
href=${retrieveUrl}>${retrieveUrl}</a></div>
|
||||
<div>如果并非本人操作,请忽略该邮件</div>
|
||||
<div class="not-reply">此邮件由系统自动发送,请勿回复!</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -54,6 +54,7 @@
|
||||
justify-content: center;
|
||||
|
||||
}
|
||||
|
||||
.verify-button a {
|
||||
padding: 20px 30px;
|
||||
color: white;
|
||||
@@ -75,9 +76,12 @@
|
||||
<div class="card">
|
||||
<div class="title">账 号 激 活</div>
|
||||
<div><strong>${username}</strong>,您好:</div>
|
||||
<div style="text-indent: 2em">感谢注册 <a target="_blank" href=${appUrl}>${appName}(${appUrl})</a>,在继续使用之前,我们需要确定您的电子邮箱地址的有效性,请在 <u><i>两小时内</i></u> 点击下面的按钮帮助我们验证:</div>
|
||||
<div style="text-indent: 2em">感谢注册 <a target="_blank" href=${appUrl}>${appName}(${appUrl})</a>,在继续使用之前,我们需要确定您的电子邮箱地址的有效性,请在
|
||||
<u><i>两小时内</i></u> 点击下面的按钮帮助我们验证:
|
||||
</div>
|
||||
<div class="verify-button"><a target="_blank" href=${verifyUrl}>验证邮箱</a></div>
|
||||
<div>如果以上按钮无法点击,请复制此链接到浏览器地址栏中访问:<a target="_blank" href=${verifyUrl}>${verifyUrl}</a></div>
|
||||
<div>如果以上按钮无法点击,请复制此链接到浏览器地址栏中访问:<a target="_blank" href=${verifyUrl}>${verifyUrl}</a>
|
||||
</div>
|
||||
<div class="not-reply">此邮件由系统自动发送,请勿回复!</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user