From b6db17290b9c66b9b44d147c8edb0622f1eec37f Mon Sep 17 00:00:00 2001 From: XiaoLFeng Date: Wed, 29 Nov 2023 23:26:15 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=99=BB=E5=BD=95=E7=BB=84?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 5 ++ .../controllers/TokenController.kt | 4 +- .../controllers/UserController.kt | 63 ++++++++++++-- .../dromstarkotlin/entity/doData/UserDO.kt | 2 + .../dromstarkotlin/entity/voData/SignInVO.kt | 8 +- .../dromstarkotlin/entity/voData/SignUpVO.kt | 16 ++++ .../xlf/dromstarkotlin/mapper/TokenMapper.kt | 4 + .../xlf/dromstarkotlin/mapper/UserMapper.kt | 15 ++++ .../dromstarkotlin/services/UserService.kt | 84 +++++++++++++++++++ .../com/xlf/dromstarkotlin/utils/ErrorCode.kt | 12 +++ .../xlf/dromstarkotlin/utils/ResultUtil.kt | 3 +- 11 files changed, 200 insertions(+), 16 deletions(-) create mode 100644 src/main/kotlin/com/xlf/dromstarkotlin/entity/voData/SignUpVO.kt create mode 100644 src/main/kotlin/com/xlf/dromstarkotlin/services/UserService.kt diff --git a/pom.xml b/pom.xml index 4466549..3d78b0e 100644 --- a/pom.xml +++ b/pom.xml @@ -26,6 +26,11 @@ org.springframework.boot spring-boot-starter-aop + + org.mindrot + jbcrypt + 0.4 + com.fasterxml.jackson.module jackson-module-kotlin diff --git a/src/main/kotlin/com/xlf/dromstarkotlin/controllers/TokenController.kt b/src/main/kotlin/com/xlf/dromstarkotlin/controllers/TokenController.kt index a6e3ca1..d1960b1 100644 --- a/src/main/kotlin/com/xlf/dromstarkotlin/controllers/TokenController.kt +++ b/src/main/kotlin/com/xlf/dromstarkotlin/controllers/TokenController.kt @@ -9,7 +9,7 @@ import jakarta.servlet.http.HttpServletResponse import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.CookieValue import org.springframework.web.bind.annotation.CrossOrigin -import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController @@ -23,7 +23,7 @@ class TokenController( /** * 创建 Token 组件 */ - @PostMapping("/create") + @GetMapping("/create") fun createToken( @CookieValue("session") token: String?, httpServletResponse: HttpServletResponse, @RequestParam("return") returnLink: String?, diff --git a/src/main/kotlin/com/xlf/dromstarkotlin/controllers/UserController.kt b/src/main/kotlin/com/xlf/dromstarkotlin/controllers/UserController.kt index 20691d2..3816ef5 100644 --- a/src/main/kotlin/com/xlf/dromstarkotlin/controllers/UserController.kt +++ b/src/main/kotlin/com/xlf/dromstarkotlin/controllers/UserController.kt @@ -4,15 +4,19 @@ import com.frontleaves.general.utils.BaseResponse import com.frontleaves.general.utils.ErrorCode import com.frontleaves.general.utils.ResultUtil import com.xlf.dromstarkotlin.entity.voData.SignInVO +import com.xlf.dromstarkotlin.entity.voData.SignUpVO import com.xlf.dromstarkotlin.exception.BusinessException import com.xlf.dromstarkotlin.services.TokenService +import com.xlf.dromstarkotlin.services.UserService import jakarta.servlet.http.HttpServletRequest import jakarta.servlet.http.HttpServletResponse import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.CookieValue -import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController +import java.util.Date /** * 用户控制器 @@ -25,31 +29,72 @@ import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/api/user") class UserController( - private val tokenService: TokenService + private val tokenService: TokenService, + private val userService: UserService ) { /** * 用户登录组件 */ - @PostMapping("/sign/in") + @GetMapping("/sign/in") fun signIn( - signInVO: SignInVO?, @CookieValue("sessionId") token: String?, httpServletResponse: HttpServletResponse, + @RequestBody signInVO: SignInVO?, @CookieValue("session") token: String?, httpServletResponse: HttpServletResponse, httpServletRequest: HttpServletRequest - ): ResponseEntity? { + ): ResponseEntity { + // 判断请求体是否为空 if (signInVO == null) { return BusinessException().backInfo(ErrorCode.MISSING_REQUEST_BODY, httpServletRequest) } else { + // 判断时间戳 + if (signInVO.timestamp + 5000 < Date().time || signInVO.timestamp - 5000 > Date().time) { + return ResultUtil.error(ErrorCode.TIMESTAMP_EXPIRED, httpServletRequest) + } // 对 Token 进行校验 - if (token != null) { + return if (token != null) { // 对 token 进行校验 if (!tokenService.tokenVerify(token, httpServletResponse)) { // 校验失败 - return BusinessException().backInfo(ErrorCode.TOKEN_VERIFY_FAILED, httpServletRequest) + BusinessException().backInfo(ErrorCode.TOKEN_VERIFY_FAILED, httpServletRequest) + } else { + // 用户登录操作 + userService.signIn(signInVO, token, httpServletRequest) } } else { // 跳转至创建 Token 页面 - return ResultUtil.redirect("/api/token/create", httpServletRequest) + ResultUtil.redirect("/api/token/create", httpServletRequest) + } + } + } + + /** + * 用户注册组件 + */ + @GetMapping("/sign/up") + fun signUp( + @RequestBody signUpVO: SignUpVO?, @CookieValue("session") token: String?, httpServletResponse: HttpServletResponse, + httpServletRequest: HttpServletRequest + ): ResponseEntity { + // 判断请求体是否为空 + if (signUpVO == null) { + return ResultUtil.error(ErrorCode.MISSING_REQUEST_BODY, httpServletRequest) + } else { + // 判断时间戳 + if (signUpVO.timestamp + 5000 < Date().time || signUpVO.timestamp - 5000 > Date().time) { + return ResultUtil.error(ErrorCode.TIMESTAMP_EXPIRED, httpServletRequest) + } + // 对 Token 进行校验 + return if (token != null) { + // 对 token 进行校验 + if (!tokenService.tokenVerify(token, httpServletResponse)) { + // 校验失败 + BusinessException().backInfo(ErrorCode.TOKEN_VERIFY_FAILED, httpServletRequest) + } else { + // 用户登录操作 + userService.signUp(signUpVO, token, httpServletRequest) + } + } else { + // 跳转至创建 Token 页面 + ResultUtil.redirect("/api/token/create", httpServletRequest) } } - return null } } \ No newline at end of file diff --git a/src/main/kotlin/com/xlf/dromstarkotlin/entity/doData/UserDO.kt b/src/main/kotlin/com/xlf/dromstarkotlin/entity/doData/UserDO.kt index 161f174..1ead46f 100644 --- a/src/main/kotlin/com/xlf/dromstarkotlin/entity/doData/UserDO.kt +++ b/src/main/kotlin/com/xlf/dromstarkotlin/entity/doData/UserDO.kt @@ -6,6 +6,8 @@ data class UserDO( var id: Long?, var user: String?, var password: String?, + var email: String?, + var tel: String?, var permission: Short?, var createdAt: Timestamp?, var updatedAt: Timestamp? diff --git a/src/main/kotlin/com/xlf/dromstarkotlin/entity/voData/SignInVO.kt b/src/main/kotlin/com/xlf/dromstarkotlin/entity/voData/SignInVO.kt index 07d5df4..be1f795 100644 --- a/src/main/kotlin/com/xlf/dromstarkotlin/entity/voData/SignInVO.kt +++ b/src/main/kotlin/com/xlf/dromstarkotlin/entity/voData/SignInVO.kt @@ -7,8 +7,8 @@ package com.xlf.dromstarkotlin.entity.voData * @since v1.0.0 */ data class SignInVO ( - var action: String? = null, - var username: String? = null, - var password: String? = null, - var timestamp: Long? = null, + val action: String, + val username: String, + val password: String, + val timestamp: Long, ) \ No newline at end of file diff --git a/src/main/kotlin/com/xlf/dromstarkotlin/entity/voData/SignUpVO.kt b/src/main/kotlin/com/xlf/dromstarkotlin/entity/voData/SignUpVO.kt new file mode 100644 index 0000000..6491446 --- /dev/null +++ b/src/main/kotlin/com/xlf/dromstarkotlin/entity/voData/SignUpVO.kt @@ -0,0 +1,16 @@ +package com.xlf.dromstarkotlin.entity.voData + +/** + * 注册用户信息自定义实体类 + * + * @author 筱锋xiao_lfeng + * @since v1.0.0 + */ +data class SignUpVO ( + val action: String, + val username: String, + val password: String, + val email: String, + val telephone: String?, + val timestamp: Long, +) diff --git a/src/main/kotlin/com/xlf/dromstarkotlin/mapper/TokenMapper.kt b/src/main/kotlin/com/xlf/dromstarkotlin/mapper/TokenMapper.kt index c986964..3747773 100644 --- a/src/main/kotlin/com/xlf/dromstarkotlin/mapper/TokenMapper.kt +++ b/src/main/kotlin/com/xlf/dromstarkotlin/mapper/TokenMapper.kt @@ -5,6 +5,7 @@ import org.apache.ibatis.annotations.Delete import org.apache.ibatis.annotations.Insert import org.apache.ibatis.annotations.Mapper import org.apache.ibatis.annotations.Select +import org.apache.ibatis.annotations.Update @Mapper interface TokenMapper { @@ -19,4 +20,7 @@ interface TokenMapper { @Insert("INSERT INTO dormstar.ds_token (user_id, token, user_agent, ip, created_at) VALUES (#{userId}, #{token}, #{userAgent}, #{ip}, #{createdAt})") fun insertToken(token: TokenDO): Boolean + + @Update("UPDATE dormstar.ds_token SET user_id = #{userId}, updated_at = #{updatedAt} WHERE token = #{token}") + fun tokenAuthorization(token: TokenDO): Boolean } \ No newline at end of file diff --git a/src/main/kotlin/com/xlf/dromstarkotlin/mapper/UserMapper.kt b/src/main/kotlin/com/xlf/dromstarkotlin/mapper/UserMapper.kt index 64d643e..14f8f26 100644 --- a/src/main/kotlin/com/xlf/dromstarkotlin/mapper/UserMapper.kt +++ b/src/main/kotlin/com/xlf/dromstarkotlin/mapper/UserMapper.kt @@ -1,4 +1,19 @@ package com.xlf.dromstarkotlin.mapper +import com.xlf.dromstarkotlin.entity.doData.UserDO +import org.apache.ibatis.annotations.Insert +import org.apache.ibatis.annotations.Mapper +import org.apache.ibatis.annotations.Select + +@Mapper interface UserMapper { + + @Select("SELECT * FROM dormstar.ds_user WHERE user = #{username}") + fun getUserByUsername(username: String?): UserDO? + + @Select("SELECT * FROM dormstar.ds_user WHERE user = #{username} OR email = #{email} OR tel = #{phone} LIMIT 1") + fun getUser(username: String, email: String, phone: String?): UserDO? + + @Insert("INSERT INTO dormstar.ds_user (user, password, email, tel, created_at) VALUES (#{user}, #{password}, #{email}, #{tel}, #{createdAt})") + fun insertUser(user: UserDO): Boolean } \ No newline at end of file diff --git a/src/main/kotlin/com/xlf/dromstarkotlin/services/UserService.kt b/src/main/kotlin/com/xlf/dromstarkotlin/services/UserService.kt new file mode 100644 index 0000000..0cfbb8d --- /dev/null +++ b/src/main/kotlin/com/xlf/dromstarkotlin/services/UserService.kt @@ -0,0 +1,84 @@ +package com.xlf.dromstarkotlin.services + +import com.frontleaves.general.utils.BaseResponse +import com.frontleaves.general.utils.ErrorCode +import com.frontleaves.general.utils.ResultUtil +import com.xlf.dromstarkotlin.entity.doData.UserDO +import com.xlf.dromstarkotlin.entity.voData.SignInVO +import com.xlf.dromstarkotlin.entity.voData.SignUpVO +import com.xlf.dromstarkotlin.mapper.TokenMapper +import com.xlf.dromstarkotlin.mapper.UserMapper +import jakarta.servlet.http.HttpServletRequest +import org.mindrot.jbcrypt.BCrypt +import org.springframework.http.ResponseEntity +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.sql.Timestamp +import java.util.* + +@Service +class UserService( + val userMapper: UserMapper, + val tokenMapper: TokenMapper +) { + + @Transactional + fun signIn( + signInVO: SignInVO, token:String, httpServletRequest: HttpServletRequest + ): ResponseEntity { + // 检查用户是否存在 + val user = userMapper.getUserByUsername(signInVO.username) + return if (user != null) { + // 检查用户密码是否匹配 + if (BCrypt.checkpw(signInVO.password, user.password)) { + val tokenDO = tokenMapper.getToken(token) + .also { it!!.userId = user.id } + if (tokenDO!!.userId == null) { + // 授权 token + if (tokenMapper.tokenAuthorization(tokenDO)) { + ResultUtil.success("登陆成功", httpServletRequest) + } else { + ResultUtil.error(ErrorCode.DATABASE_UPDATE_OPERATION_FAILED, httpServletRequest) + } + } else { + ResultUtil.error(ErrorCode.YOU_ARE_ALREADY_LOGIN, httpServletRequest) + } + } else { + ResultUtil.error(ErrorCode.WRONG_PASSWORD, httpServletRequest) + } + } else { + ResultUtil.error(ErrorCode.USER_NOT_FOUNDED, httpServletRequest) + } + } + + @Transactional + fun signUp( + signUpVO: SignUpVO, token: String, httpServletRequest: HttpServletRequest + ): ResponseEntity { + // 检查用户和邮箱是否存在 + val user = userMapper.getUser(signUpVO.username, signUpVO.email, signUpVO.telephone) + if (user == null) { + val tokenDO = tokenMapper.getToken(token) + if (tokenDO!!.userId == null) { + // 处理用户注册程序 + val hashPassword = BCrypt.hashpw(signUpVO.password, BCrypt.gensalt()) + val newUser = UserDO(null, signUpVO.username, hashPassword, signUpVO.email, signUpVO.telephone, 0, Timestamp(Date().time), null) + // 数据输入数据库 + return if (userMapper.insertUser(newUser)) { + // 授权 token + if (tokenMapper.tokenAuthorization(tokenDO)) { + ResultUtil.success("注册成功", httpServletRequest) + } else { + ResultUtil.error(ErrorCode.DATABASE_UPDATE_OPERATION_FAILED, httpServletRequest) + } + } else { + ResultUtil.error(ErrorCode.DATABASE_INSERT_OPERATION_FAILED, httpServletRequest) + } + } else { + return ResultUtil.error(ErrorCode.YOU_ARE_ALREADY_LOGIN, httpServletRequest) + } + } else { + return ResultUtil.error(ErrorCode.USER_EXIST, httpServletRequest) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/xlf/dromstarkotlin/utils/ErrorCode.kt b/src/main/kotlin/com/xlf/dromstarkotlin/utils/ErrorCode.kt index 981f199..ec1f9fb 100644 --- a/src/main/kotlin/com/xlf/dromstarkotlin/utils/ErrorCode.kt +++ b/src/main/kotlin/com/xlf/dromstarkotlin/utils/ErrorCode.kt @@ -66,6 +66,12 @@ enum class ErrorCode(val output: String, val code: Int, val message: String, val "无法生成验证密钥(VerifyKey)", HttpStatus.BAD_REQUEST ), + YOU_ARE_ALREADY_LOGIN( + "YouAreAlreadyLogin", + 40026, + "您已经登录", + HttpStatus.BAD_REQUEST + ), YOU_ARE_NOT_LOGIN( "YouAreNotLogin", 40110, @@ -120,6 +126,12 @@ enum class ErrorCode(val output: String, val code: Int, val message: String, val "apikey不正确", HttpStatus.FORBIDDEN ), + TIMESTAMP_EXPIRED( + "TimestampExpired", + 40318, + "时间戳过期", + HttpStatus.FORBIDDEN + ), METHOD_NOT_ALLOWED( "MethodNotAllowed", 40510, diff --git a/src/main/kotlin/com/xlf/dromstarkotlin/utils/ResultUtil.kt b/src/main/kotlin/com/xlf/dromstarkotlin/utils/ResultUtil.kt index 3cf6d8d..ebf67dc 100644 --- a/src/main/kotlin/com/xlf/dromstarkotlin/utils/ResultUtil.kt +++ b/src/main/kotlin/com/xlf/dromstarkotlin/utils/ResultUtil.kt @@ -15,7 +15,8 @@ class ResultUtil constructor(val output: String, val code: Int, val message: Str * * @return BaseResponse */ - fun success(): ResponseEntity { + fun success(httpServletRequest: HttpServletRequest): ResponseEntity { + println("${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())} [Log] <200>Success | Message:OK | URI:${httpServletRequest.requestURI}") return ResponseEntity .status(200) .body(BaseResponse())