添加登录组件

This commit is contained in:
筱锋xiao_lfeng 2023-11-29 23:26:15 +08:00
parent 86006196c8
commit b6db17290b
No known key found for this signature in database
GPG Key ID: 3D44FF873E0CD0E3
11 changed files with 200 additions and 16 deletions

View File

@ -26,6 +26,11 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.mindrot</groupId>
<artifactId>jbcrypt</artifactId>
<version>0.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-kotlin</artifactId>

View File

@ -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?,

View File

@ -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<BaseResponse>? {
): ResponseEntity<BaseResponse> {
// 判断请求体是否为空
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<BaseResponse> {
// 判断请求体是否为空
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
}
}

View File

@ -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?

View File

@ -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,
)

View File

@ -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,
)

View File

@ -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
}

View File

@ -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
}

View File

@ -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<BaseResponse> {
// 检查用户是否存在
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<BaseResponse> {
// 检查用户和邮箱是否存在
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)
}
}
}

View File

@ -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,

View File

@ -15,7 +15,8 @@ class ResultUtil constructor(val output: String, val code: Int, val message: Str
*
* @return BaseResponse
*/
fun success(): ResponseEntity<BaseResponse> {
fun success(httpServletRequest: HttpServletRequest): ResponseEntity<BaseResponse> {
println("${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())} [Log] <200>Success | Message:OK | URI:${httpServletRequest.requestURI}")
return ResponseEntity
.status(200)
.body(BaseResponse())