From e45769e52aa30f45da76e8cf233d2441581d9561 Mon Sep 17 00:00:00 2001 From: FatttSnake Date: Tue, 26 Dec 2023 18:17:03 +0800 Subject: [PATCH] Finish sign api. Optimize code. --- .../top/fatweb/api/config/SecurityConfig.kt | 4 +- .../permission/AuthenticationController.kt | 38 +++++-- .../fatweb/api/entity/common/ResponseCode.kt | 5 + .../top/fatweb/api/entity/permission/User.kt | 13 ++- .../AccountNeedResetPasswordException.kt | 9 ++ .../RetrieveCodeErrorOrExpiredException.kt | 3 + .../api/exception/UserNotFoundException.kt | 3 + .../fatweb/api/handler/ExceptionHandler.kt | 15 +++ .../api/mapper/permission/GroupMapper.kt | 11 +- .../api/mapper/permission/RoleMapper.kt | 11 +- .../api/mapper/permission/UserMapper.kt | 15 ++- .../fatweb/api/mapper/system/SysLogMapper.kt | 11 +- .../top/fatweb/api/param/PageSortParam.kt | 6 +- .../api/param/permission/ForgetParam.kt | 25 +++++ .../fatweb/api/param/permission/LoginParam.kt | 4 +- .../api/param/permission/RegisterParam.kt | 6 +- .../api/param/permission/RetrieveParam.kt | 35 ++++++ .../api/param/permission/VerifyParam.kt | 6 +- .../param/permission/group/GroupAddParam.kt | 4 +- .../permission/group/GroupDeleteParam.kt | 2 +- .../param/permission/group/GroupGetParam.kt | 9 +- .../permission/group/GroupUpdateParam.kt | 6 +- .../group/GroupUpdateStatusParam.kt | 4 +- .../api/param/permission/role/RoleAddParam.kt | 4 +- .../param/permission/role/RoleDeleteParam.kt | 2 +- .../api/param/permission/role/RoleGetParam.kt | 9 +- .../param/permission/role/RoleUpdateParam.kt | 6 +- .../permission/role/RoleUpdateStatusParam.kt | 4 +- .../api/param/permission/user/UserAddParam.kt | 17 +-- .../param/permission/user/UserDeleteParam.kt | 2 +- .../api/param/permission/user/UserGetParam.kt | 16 ++- .../param/permission/user/UserUpdateParam.kt | 22 ++-- .../user/UserUpdatePasswordParam.kt | 6 +- .../api/param/system/ActiveInfoGetParam.kt | 13 +++ .../fatweb/api/param/system/MailSendParam.kt | 2 +- .../api/param/system/OnlineInfoGetParam.kt | 13 +++ .../fatweb/api/param/system/SysLogGetParam.kt | 10 +- .../permission/IAuthenticationService.kt | 22 +++- .../impl/AuthenticationServiceImpl.kt | 102 +++++++++++++++--- .../V1_0_0_231019__Add_table_'t_user'.sql | 6 +- .../templates/email-password-changed-cn.vm | 78 ++++++++++++++ .../templates/email-retrieve-password-cn.vm | 90 ++++++++++++++++ .../templates/email-verify-account-cn.vm | 8 +- 43 files changed, 570 insertions(+), 107 deletions(-) create mode 100644 src/main/kotlin/top/fatweb/api/exception/AccountNeedResetPasswordException.kt create mode 100644 src/main/kotlin/top/fatweb/api/exception/RetrieveCodeErrorOrExpiredException.kt create mode 100644 src/main/kotlin/top/fatweb/api/exception/UserNotFoundException.kt create mode 100644 src/main/kotlin/top/fatweb/api/param/permission/ForgetParam.kt create mode 100644 src/main/kotlin/top/fatweb/api/param/permission/RetrieveParam.kt create mode 100644 src/main/resources/templates/email-password-changed-cn.vm create mode 100644 src/main/resources/templates/email-retrieve-password-cn.vm diff --git a/src/main/kotlin/top/fatweb/api/config/SecurityConfig.kt b/src/main/kotlin/top/fatweb/api/config/SecurityConfig.kt index 6a4424c..5e0dcb8 100644 --- a/src/main/kotlin/top/fatweb/api/config/SecurityConfig.kt +++ b/src/main/kotlin/top/fatweb/api/config/SecurityConfig.kt @@ -75,7 +75,9 @@ class SecurityConfig( "/swagger-ui.html", "/favicon.ico", "/login", - "/register" + "/register", + "/forget", + "/retrieve" ).anonymous() // Authentication required .anyRequest().authenticated() diff --git a/src/main/kotlin/top/fatweb/api/controller/permission/AuthenticationController.kt b/src/main/kotlin/top/fatweb/api/controller/permission/AuthenticationController.kt index fb77f50..dee6214 100644 --- a/src/main/kotlin/top/fatweb/api/controller/permission/AuthenticationController.kt +++ b/src/main/kotlin/top/fatweb/api/controller/permission/AuthenticationController.kt @@ -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 { 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 { 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 { + 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 { + authenticationService.retrieve(request, retrieveParam) + + return ResponseResult.success(ResponseCode.PERMISSION_RETRIEVE_SUCCESS) + } + /** * Login * diff --git a/src/main/kotlin/top/fatweb/api/entity/common/ResponseCode.kt b/src/main/kotlin/top/fatweb/api/entity/common/ResponseCode.kt index af874cb..23eb2d5 100644 --- a/src/main/kotlin/top/fatweb/api/entity/common/ResponseCode.kt +++ b/src/main/kotlin/top/fatweb/api/entity/common/ResponseCode.kt @@ -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), diff --git a/src/main/kotlin/top/fatweb/api/entity/permission/User.kt b/src/main/kotlin/top/fatweb/api/entity/permission/User.kt index 28c521b..14d04d2 100644 --- a/src/main/kotlin/top/fatweb/api/entity/permission/User.kt +++ b/src/main/kotlin/top/fatweb/api/entity/permission/User.kt @@ -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? = 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)" } } diff --git a/src/main/kotlin/top/fatweb/api/exception/AccountNeedResetPasswordException.kt b/src/main/kotlin/top/fatweb/api/exception/AccountNeedResetPasswordException.kt new file mode 100644 index 0000000..79fc9e1 --- /dev/null +++ b/src/main/kotlin/top/fatweb/api/exception/AccountNeedResetPasswordException.kt @@ -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") \ No newline at end of file diff --git a/src/main/kotlin/top/fatweb/api/exception/RetrieveCodeErrorOrExpiredException.kt b/src/main/kotlin/top/fatweb/api/exception/RetrieveCodeErrorOrExpiredException.kt new file mode 100644 index 0000000..a91616b --- /dev/null +++ b/src/main/kotlin/top/fatweb/api/exception/RetrieveCodeErrorOrExpiredException.kt @@ -0,0 +1,3 @@ +package top.fatweb.api.exception + +class RetrieveCodeErrorOrExpiredException : RuntimeException("Retrieve code error or expired") \ No newline at end of file diff --git a/src/main/kotlin/top/fatweb/api/exception/UserNotFoundException.kt b/src/main/kotlin/top/fatweb/api/exception/UserNotFoundException.kt new file mode 100644 index 0000000..0779276 --- /dev/null +++ b/src/main/kotlin/top/fatweb/api/exception/UserNotFoundException.kt @@ -0,0 +1,3 @@ +package top.fatweb.api.exception + +class UserNotFoundException : RuntimeException("User not found") \ No newline at end of file diff --git a/src/main/kotlin/top/fatweb/api/handler/ExceptionHandler.kt b/src/main/kotlin/top/fatweb/api/handler/ExceptionHandler.kt index ec1f87b..3d818cb 100644 --- a/src/main/kotlin/top/fatweb/api/handler/ExceptionHandler.kt +++ b/src/main/kotlin/top/fatweb/api/handler/ExceptionHandler.kt @@ -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) diff --git a/src/main/kotlin/top/fatweb/api/mapper/permission/GroupMapper.kt b/src/main/kotlin/top/fatweb/api/mapper/permission/GroupMapper.kt index 2413f06..d2b001e 100644 --- a/src/main/kotlin/top/fatweb/api/mapper/permission/GroupMapper.kt +++ b/src/main/kotlin/top/fatweb/api/mapper/permission/GroupMapper.kt @@ -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 { * @since 1.0.0 * @see IPage */ - fun selectPage(page: IPage, searchName: String?, searchRegex: Boolean): IPage + fun selectPage( + page: IPage, + @Param("searchName") searchName: String?, + @Param("searchRegex") searchRegex: Boolean + ): IPage /** * Select group with role list by list of group IDs @@ -37,7 +42,7 @@ interface GroupMapper : BaseMapper { * @since 1.0.0 * @see Group */ - fun selectListWithRoleByIds(groupIds: List): List? + fun selectListWithRoleByIds(@Param("groupIds") groupIds: List): List? /** * Select one group by ID @@ -48,5 +53,5 @@ interface GroupMapper : BaseMapper { * @since 1.0.0 * @see Group */ - fun selectOneById(id: Long): Group? + fun selectOneById(@Param("id") id: Long): Group? } diff --git a/src/main/kotlin/top/fatweb/api/mapper/permission/RoleMapper.kt b/src/main/kotlin/top/fatweb/api/mapper/permission/RoleMapper.kt index 9c67184..94c99a5 100644 --- a/src/main/kotlin/top/fatweb/api/mapper/permission/RoleMapper.kt +++ b/src/main/kotlin/top/fatweb/api/mapper/permission/RoleMapper.kt @@ -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 { * @since 1.0.0 * @see IPage */ - fun selectPage(page: IPage, searchName: String?, searchRegex: Boolean): IPage + fun selectPage( + page: IPage, + @Param("searchName") searchName: String?, + @Param("searchRegex") searchRegex: Boolean + ): IPage /** * Select role with power list by list of role IDs @@ -37,7 +42,7 @@ interface RoleMapper : BaseMapper { * @since 1.0.0 * @see Role */ - fun selectListWithPowerByIds(roleIds: List): List? + fun selectListWithPowerByIds(@Param("roleIds") roleIds: List): List? /** * Select one role by ID @@ -48,5 +53,5 @@ interface RoleMapper : BaseMapper { * @since 1.0.0 * @see Role */ - fun selectOneById(id: Long): Role? + fun selectOneById(@Param("id") id: Long): Role? } diff --git a/src/main/kotlin/top/fatweb/api/mapper/permission/UserMapper.kt b/src/main/kotlin/top/fatweb/api/mapper/permission/UserMapper.kt index 5a3489f..0118e0d 100644 --- a/src/main/kotlin/top/fatweb/api/mapper/permission/UserMapper.kt +++ b/src/main/kotlin/top/fatweb/api/mapper/permission/UserMapper.kt @@ -39,7 +39,12 @@ interface UserMapper : BaseMapper { * @since 1.0.0 * @see IPage */ - fun selectPage(page: IPage, searchType: String, searchValue: String?, searchRegex: Boolean): IPage + fun selectPage( + page: IPage, + @Param("searchType") searchType: String, + @Param("searchValue") searchValue: String?, + @Param("searchRegex") searchRegex: Boolean + ): IPage /** * Select user with role and information list by list of user IDs @@ -50,7 +55,7 @@ interface UserMapper : BaseMapper { * @since 1.0.0 * @see User */ - fun selectListWithRoleInfoByIds(userIds: List): List + fun selectListWithRoleInfoByIds(@Param("userIds") userIds: List): List /** * Select one user by ID @@ -61,7 +66,7 @@ interface UserMapper : BaseMapper { * @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 { * @author FatttSnake, fatttsnake@gmail.com * @since 1.0.0 */ - fun selectIdsWithRoleIds(roleIds: List): List + fun selectIdsWithRoleIds(@Param("roleIds") roleIds: List): List /** * Select user IDs list by list of group IDs @@ -91,5 +96,5 @@ interface UserMapper : BaseMapper { * @author FatttSnake, fatttsnake@gmail.com * @since 1.0.0 */ - fun selectIdsWithGroupIds(groupIds: List): List + fun selectIdsWithGroupIds(@Param("groupIds") groupIds: List): List } diff --git a/src/main/kotlin/top/fatweb/api/mapper/system/SysLogMapper.kt b/src/main/kotlin/top/fatweb/api/mapper/system/SysLogMapper.kt index 3bb670d..b8f0932 100644 --- a/src/main/kotlin/top/fatweb/api/mapper/system/SysLogMapper.kt +++ b/src/main/kotlin/top/fatweb/api/mapper/system/SysLogMapper.kt @@ -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 { */ fun selectPage( page: IPage, - logType: List?, - requestMethod: List?, - searchRequestUrl: String?, - searchStartTime: LocalDateTime?, - searchEndTime: LocalDateTime? + @Param("logType") logType: List?, + @Param("requestMethod") requestMethod: List?, + @Param("searchRequestUrl") searchRequestUrl: String?, + @Param("searchStartTime") searchStartTime: LocalDateTime?, + @Param("searchEndTime") searchEndTime: LocalDateTime? ): IPage } diff --git a/src/main/kotlin/top/fatweb/api/param/PageSortParam.kt b/src/main/kotlin/top/fatweb/api/param/PageSortParam.kt index b2c31c5..6692b20 100644 --- a/src/main/kotlin/top/fatweb/api/param/PageSortParam.kt +++ b/src/main/kotlin/top/fatweb/api/param/PageSortParam.kt @@ -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 } \ No newline at end of file diff --git a/src/main/kotlin/top/fatweb/api/param/permission/ForgetParam.kt b/src/main/kotlin/top/fatweb/api/param/permission/ForgetParam.kt new file mode 100644 index 0000000..97398b9 --- /dev/null +++ b/src/main/kotlin/top/fatweb/api/param/permission/ForgetParam.kt @@ -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? +) diff --git a/src/main/kotlin/top/fatweb/api/param/permission/LoginParam.kt b/src/main/kotlin/top/fatweb/api/param/permission/LoginParam.kt index d601a24..163a849 100644 --- a/src/main/kotlin/top/fatweb/api/param/permission/LoginParam.kt +++ b/src/main/kotlin/top/fatweb/api/param/permission/LoginParam.kt @@ -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? ) \ No newline at end of file diff --git a/src/main/kotlin/top/fatweb/api/param/permission/RegisterParam.kt b/src/main/kotlin/top/fatweb/api/param/permission/RegisterParam.kt index 3ea3148..731cb6f 100644 --- a/src/main/kotlin/top/fatweb/api/param/permission/RegisterParam.kt +++ b/src/main/kotlin/top/fatweb/api/param/permission/RegisterParam.kt @@ -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? diff --git a/src/main/kotlin/top/fatweb/api/param/permission/RetrieveParam.kt b/src/main/kotlin/top/fatweb/api/param/permission/RetrieveParam.kt new file mode 100644 index 0000000..cbd41b9 --- /dev/null +++ b/src/main/kotlin/top/fatweb/api/param/permission/RetrieveParam.kt @@ -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? +) diff --git a/src/main/kotlin/top/fatweb/api/param/permission/VerifyParam.kt b/src/main/kotlin/top/fatweb/api/param/permission/VerifyParam.kt index c98f2c0..a9670d1 100644 --- a/src/main/kotlin/top/fatweb/api/param/permission/VerifyParam.kt +++ b/src/main/kotlin/top/fatweb/api/param/permission/VerifyParam.kt @@ -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?, diff --git a/src/main/kotlin/top/fatweb/api/param/permission/group/GroupAddParam.kt b/src/main/kotlin/top/fatweb/api/param/permission/group/GroupAddParam.kt index 6bf7aef..b3471a4 100644 --- a/src/main/kotlin/top/fatweb/api/param/permission/group/GroupAddParam.kt +++ b/src/main/kotlin/top/fatweb/api/param/permission/group/GroupAddParam.kt @@ -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, /** diff --git a/src/main/kotlin/top/fatweb/api/param/permission/group/GroupDeleteParam.kt b/src/main/kotlin/top/fatweb/api/param/permission/group/GroupDeleteParam.kt index 398f1c3..2e2dc54 100644 --- a/src/main/kotlin/top/fatweb/api/param/permission/group/GroupDeleteParam.kt +++ b/src/main/kotlin/top/fatweb/api/param/permission/group/GroupDeleteParam.kt @@ -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 ) diff --git a/src/main/kotlin/top/fatweb/api/param/permission/group/GroupGetParam.kt b/src/main/kotlin/top/fatweb/api/param/permission/group/GroupGetParam.kt index befcf1d..cbaf63e 100644 --- a/src/main/kotlin/top/fatweb/api/param/permission/group/GroupGetParam.kt +++ b/src/main/kotlin/top/fatweb/api/param/permission/group/GroupGetParam.kt @@ -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() diff --git a/src/main/kotlin/top/fatweb/api/param/permission/group/GroupUpdateParam.kt b/src/main/kotlin/top/fatweb/api/param/permission/group/GroupUpdateParam.kt index bbb68c5..d02d4e1 100644 --- a/src/main/kotlin/top/fatweb/api/param/permission/group/GroupUpdateParam.kt +++ b/src/main/kotlin/top/fatweb/api/param/permission/group/GroupUpdateParam.kt @@ -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, /** diff --git a/src/main/kotlin/top/fatweb/api/param/permission/group/GroupUpdateStatusParam.kt b/src/main/kotlin/top/fatweb/api/param/permission/group/GroupUpdateStatusParam.kt index 9d14c9d..9a7affb 100644 --- a/src/main/kotlin/top/fatweb/api/param/permission/group/GroupUpdateStatusParam.kt +++ b/src/main/kotlin/top/fatweb/api/param/permission/group/GroupUpdateStatusParam.kt @@ -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 ) \ No newline at end of file diff --git a/src/main/kotlin/top/fatweb/api/param/permission/role/RoleAddParam.kt b/src/main/kotlin/top/fatweb/api/param/permission/role/RoleAddParam.kt index a98d84d..a44f703 100644 --- a/src/main/kotlin/top/fatweb/api/param/permission/role/RoleAddParam.kt +++ b/src/main/kotlin/top/fatweb/api/param/permission/role/RoleAddParam.kt @@ -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, /** diff --git a/src/main/kotlin/top/fatweb/api/param/permission/role/RoleDeleteParam.kt b/src/main/kotlin/top/fatweb/api/param/permission/role/RoleDeleteParam.kt index 03fa132..74a3b44 100644 --- a/src/main/kotlin/top/fatweb/api/param/permission/role/RoleDeleteParam.kt +++ b/src/main/kotlin/top/fatweb/api/param/permission/role/RoleDeleteParam.kt @@ -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 ) diff --git a/src/main/kotlin/top/fatweb/api/param/permission/role/RoleGetParam.kt b/src/main/kotlin/top/fatweb/api/param/permission/role/RoleGetParam.kt index e7367aa..469720b 100644 --- a/src/main/kotlin/top/fatweb/api/param/permission/role/RoleGetParam.kt +++ b/src/main/kotlin/top/fatweb/api/param/permission/role/RoleGetParam.kt @@ -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() diff --git a/src/main/kotlin/top/fatweb/api/param/permission/role/RoleUpdateParam.kt b/src/main/kotlin/top/fatweb/api/param/permission/role/RoleUpdateParam.kt index 36011a1..c123665 100644 --- a/src/main/kotlin/top/fatweb/api/param/permission/role/RoleUpdateParam.kt +++ b/src/main/kotlin/top/fatweb/api/param/permission/role/RoleUpdateParam.kt @@ -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, /** diff --git a/src/main/kotlin/top/fatweb/api/param/permission/role/RoleUpdateStatusParam.kt b/src/main/kotlin/top/fatweb/api/param/permission/role/RoleUpdateStatusParam.kt index 6c9116b..fa0f135 100644 --- a/src/main/kotlin/top/fatweb/api/param/permission/role/RoleUpdateStatusParam.kt +++ b/src/main/kotlin/top/fatweb/api/param/permission/role/RoleUpdateStatusParam.kt @@ -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 ) \ No newline at end of file diff --git a/src/main/kotlin/top/fatweb/api/param/permission/user/UserAddParam.kt b/src/main/kotlin/top/fatweb/api/param/permission/user/UserAddParam.kt index 6176452..a2e227b 100644 --- a/src/main/kotlin/top/fatweb/api/param/permission/user/UserAddParam.kt +++ b/src/main/kotlin/top/fatweb/api/param/permission/user/UserAddParam.kt @@ -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?, diff --git a/src/main/kotlin/top/fatweb/api/param/permission/user/UserDeleteParam.kt b/src/main/kotlin/top/fatweb/api/param/permission/user/UserDeleteParam.kt index 785593a..eba2828 100644 --- a/src/main/kotlin/top/fatweb/api/param/permission/user/UserDeleteParam.kt +++ b/src/main/kotlin/top/fatweb/api/param/permission/user/UserDeleteParam.kt @@ -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 ) diff --git a/src/main/kotlin/top/fatweb/api/param/permission/user/UserGetParam.kt b/src/main/kotlin/top/fatweb/api/param/permission/user/UserGetParam.kt index ebe5651..f06548b 100644 --- a/src/main/kotlin/top/fatweb/api/param/permission/user/UserGetParam.kt +++ b/src/main/kotlin/top/fatweb/api/param/permission/user/UserGetParam.kt @@ -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() diff --git a/src/main/kotlin/top/fatweb/api/param/permission/user/UserUpdateParam.kt b/src/main/kotlin/top/fatweb/api/param/permission/user/UserUpdateParam.kt index 946ff77..96afb83 100644 --- a/src/main/kotlin/top/fatweb/api/param/permission/user/UserUpdateParam.kt +++ b/src/main/kotlin/top/fatweb/api/param/permission/user/UserUpdateParam.kt @@ -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?, diff --git a/src/main/kotlin/top/fatweb/api/param/permission/user/UserUpdatePasswordParam.kt b/src/main/kotlin/top/fatweb/api/param/permission/user/UserUpdatePasswordParam.kt index 744a7e2..561ba34 100644 --- a/src/main/kotlin/top/fatweb/api/param/permission/user/UserUpdatePasswordParam.kt +++ b/src/main/kotlin/top/fatweb/api/param/permission/user/UserUpdatePasswordParam.kt @@ -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? ) diff --git a/src/main/kotlin/top/fatweb/api/param/system/ActiveInfoGetParam.kt b/src/main/kotlin/top/fatweb/api/param/system/ActiveInfoGetParam.kt index b7057fa..ce8b7ac 100644 --- a/src/main/kotlin/top/fatweb/api/param/system/ActiveInfoGetParam.kt +++ b/src/main/kotlin/top/fatweb/api/param/system/ActiveInfoGetParam.kt @@ -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) { diff --git a/src/main/kotlin/top/fatweb/api/param/system/MailSendParam.kt b/src/main/kotlin/top/fatweb/api/param/system/MailSendParam.kt index 6d7641a..e408664 100644 --- a/src/main/kotlin/top/fatweb/api/param/system/MailSendParam.kt +++ b/src/main/kotlin/top/fatweb/api/param/system/MailSendParam.kt @@ -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? ) diff --git a/src/main/kotlin/top/fatweb/api/param/system/OnlineInfoGetParam.kt b/src/main/kotlin/top/fatweb/api/param/system/OnlineInfoGetParam.kt index 2b38ae6..557be14 100644 --- a/src/main/kotlin/top/fatweb/api/param/system/OnlineInfoGetParam.kt +++ b/src/main/kotlin/top/fatweb/api/param/system/OnlineInfoGetParam.kt @@ -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) { diff --git a/src/main/kotlin/top/fatweb/api/param/system/SysLogGetParam.kt b/src/main/kotlin/top/fatweb/api/param/system/SysLogGetParam.kt index e732cc4..9d22674 100644 --- a/src/main/kotlin/top/fatweb/api/param/system/SysLogGetParam.kt +++ b/src/main/kotlin/top/fatweb/api/param/system/SysLogGetParam.kt @@ -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() \ No newline at end of file diff --git a/src/main/kotlin/top/fatweb/api/service/permission/IAuthenticationService.kt b/src/main/kotlin/top/fatweb/api/service/permission/IAuthenticationService.kt index 7fe91fc..cbf2483 100644 --- a/src/main/kotlin/top/fatweb/api/service/permission/IAuthenticationService.kt +++ b/src/main/kotlin/top/fatweb/api/service/permission/IAuthenticationService.kt @@ -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 * diff --git a/src/main/kotlin/top/fatweb/api/service/permission/impl/AuthenticationServiceImpl.kt b/src/main/kotlin/top/fatweb/api/service/permission/impl/AuthenticationServiceImpl.kt index 35cce8f..5cd2f76 100644 --- a/src/main/kotlin/top/fatweb/api/service/permission/impl/AuthenticationServiceImpl.kt +++ b/src/main/kotlin/top/fatweb/api/service/permission/impl/AuthenticationServiceImpl.kt @@ -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 = diff --git a/src/main/resources/db/migration/master/V1_0_0_231019__Add_table_'t_user'.sql b/src/main/resources/db/migration/master/V1_0_0_231019__Add_table_'t_user'.sql index cd04c92..f00170d 100644 --- a/src/main/resources/db/migration/master/V1_0_0_231019__Add_table_'t_user'.sql +++ b/src/main/resources/db/migration/master/V1_0_0_231019__Add_table_'t_user'.sql @@ -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 '用户表'; \ No newline at end of file diff --git a/src/main/resources/templates/email-password-changed-cn.vm b/src/main/resources/templates/email-password-changed-cn.vm new file mode 100644 index 0000000..aba67ca --- /dev/null +++ b/src/main/resources/templates/email-password-changed-cn.vm @@ -0,0 +1,78 @@ + + + + + + + 您的密码已更改 + + + +
+
+
密 码 已 更 改
+
${username},您好:
+
您在 ${appName}(${appUrl}) 的密码已更改,操作 + IP 地址为 [${ipAddress}]。如果不是您自己的操作,请尽快检查您的账号! +
+
此邮件由系统自动发送,请勿回复!
+
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/email-retrieve-password-cn.vm b/src/main/resources/templates/email-retrieve-password-cn.vm new file mode 100644 index 0000000..d520710 --- /dev/null +++ b/src/main/resources/templates/email-retrieve-password-cn.vm @@ -0,0 +1,90 @@ + + + + + + + 找回您的密码 + + + +
+
+
找 回 密 码
+
${username},您好:
+
您正在找回 ${appName}(${appUrl}) 的密码,操作 + IP 地址为 [${ipAddress}],如果是您自己的操作,请在 两小时内 点击下面的按钮找回您的密码: +
+ +
如果以上按钮无法点击,请复制此链接到浏览器地址栏中访问:${retrieveUrl}
+
如果并非本人操作,请忽略该邮件
+
此邮件由系统自动发送,请勿回复!
+
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/email-verify-account-cn.vm b/src/main/resources/templates/email-verify-account-cn.vm index c8f44c3..ead9e3a 100644 --- a/src/main/resources/templates/email-verify-account-cn.vm +++ b/src/main/resources/templates/email-verify-account-cn.vm @@ -54,6 +54,7 @@ justify-content: center; } + .verify-button a { padding: 20px 30px; color: white; @@ -75,9 +76,12 @@
账 号 激 活
${username},您好:
-
感谢注册 ${appName}(${appUrl}),在继续使用之前,我们需要确定您的电子邮箱地址的有效性,请在 两小时内 点击下面的按钮帮助我们验证:
+
感谢注册 ${appName}(${appUrl}),在继续使用之前,我们需要确定您的电子邮箱地址的有效性,请在 + 两小时内 点击下面的按钮帮助我们验证: +
-
如果以上按钮无法点击,请复制此链接到浏览器地址栏中访问:${verifyUrl}
+
如果以上按钮无法点击,请复制此链接到浏览器地址栏中访问:${verifyUrl} +
此邮件由系统自动发送,请勿回复!