diff --git a/src/main/kotlin/com/msksbr/bookmgr/BookMgrApplication.kt b/src/main/kotlin/com/msksbr/bookmgr/BookMgrApplication.kt index f97b220..63f2373 100644 --- a/src/main/kotlin/com/msksbr/bookmgr/BookMgrApplication.kt +++ b/src/main/kotlin/com/msksbr/bookmgr/BookMgrApplication.kt @@ -3,6 +3,9 @@ package com.msksbr.bookmgr import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication +/* +* Spring Boot 启动类 +*/ @SpringBootApplication class BookMgrApplication diff --git a/src/main/kotlin/com/msksbr/bookmgr/config/IpExtractor.kt b/src/main/kotlin/com/msksbr/bookmgr/config/IpExtractor.kt index 70219d4..d912585 100644 --- a/src/main/kotlin/com/msksbr/bookmgr/config/IpExtractor.kt +++ b/src/main/kotlin/com/msksbr/bookmgr/config/IpExtractor.kt @@ -3,7 +3,9 @@ package com.msksbr.bookmgr.config import jakarta.servlet.http.HttpServletRequest import org.springframework.stereotype.Component -//获取真实IP的bean +/* +* 从请求头中提取真实客户端 IP(处理反向代理) +*/ @Component class IpExtractor { fun getRealIp(request: HttpServletRequest): String { diff --git a/src/main/kotlin/com/msksbr/bookmgr/config/JwtUtils.kt b/src/main/kotlin/com/msksbr/bookmgr/config/JwtUtils.kt index f5a7bec..677b23b 100644 --- a/src/main/kotlin/com/msksbr/bookmgr/config/JwtUtils.kt +++ b/src/main/kotlin/com/msksbr/bookmgr/config/JwtUtils.kt @@ -13,7 +13,8 @@ import java.util.* import javax.crypto.SecretKey /* -* 注册JWT的失效时间和密钥 +* JWT 令牌工具:签发、解析 +* 密钥来源:环境变量 JWT_SECRET,未配置时自动生成(重启失效) */ @Component class JwtUtils( @@ -22,10 +23,9 @@ class JwtUtils( ) { private val secretKey: SecretKey - // 没有配置key时自动生成 + // 初始化密钥:有配置时用 SHA-256 哈希,无配置时随机生成 init { val keyBytes = if (configuredSecret.isNotBlank()) { - // 把用户提供的secret,用SHA-256哈希成256字节固定长度 val md = MessageDigest.getInstance("SHA-256") md.digest(configuredSecret.toByteArray()) } else { @@ -39,7 +39,7 @@ class JwtUtils( secretKey = Keys.hmacShaKeyFor(keyBytes) } - // 生成token + // 签发 token,payload 包含 role fun generateToken(username: String, role: String): String { val claims = Jwts.claims().add("role", role).build() val token = Jwts.builder().claims(claims).subject(username) @@ -52,16 +52,16 @@ class JwtUtils( return token } - // 解析token + // 解析 token,校验失败时记日志并返回 null fun parseToken(token: String): Claims? { try { val claims = Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(token) return claims.payload } catch (e: JwtException) { - log.error("Token parsing failed", e) + log.error("[JWT] parse failed: {}", e.message) } catch (e: IllegalArgumentException) { - log.error("Token parsing failed with illegalArguments: $token", e) + log.error("[JWT] parse failed: illegal argument") } return null } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/msksbr/bookmgr/config/LoggingAspect.kt b/src/main/kotlin/com/msksbr/bookmgr/config/LoggingAspect.kt index 7077b31..c223132 100644 --- a/src/main/kotlin/com/msksbr/bookmgr/config/LoggingAspect.kt +++ b/src/main/kotlin/com/msksbr/bookmgr/config/LoggingAspect.kt @@ -7,6 +7,11 @@ import org.aspectj.lang.annotation.Aspect import org.aspectj.lang.annotation.Pointcut import org.springframework.stereotype.Component +/* +* AOP 日志切面:自动记录方法入口/出口/耗时 +* - controller/service/runner/jwt:DEBUG 级别,超 500ms 时 WARN +* - mapper:TRACE 级别,日常不输出 +*/ @Aspect @Component class LoggingAspect { diff --git a/src/main/kotlin/com/msksbr/bookmgr/config/PasswordConfig.kt b/src/main/kotlin/com/msksbr/bookmgr/config/PasswordConfig.kt index e0e1124..a5ccece 100644 --- a/src/main/kotlin/com/msksbr/bookmgr/config/PasswordConfig.kt +++ b/src/main/kotlin/com/msksbr/bookmgr/config/PasswordConfig.kt @@ -5,6 +5,9 @@ import org.springframework.context.annotation.Configuration import org.springframework.security.crypto.argon2.Argon2PasswordEncoder import org.springframework.security.crypto.password.PasswordEncoder +/* +* Argon2 密码编码器配置 +*/ // 将Argon2的加盐哈希方法注册成Bean @Configuration class PasswordConfig { diff --git a/src/main/kotlin/com/msksbr/bookmgr/controller/AdminBookController.kt b/src/main/kotlin/com/msksbr/bookmgr/controller/AdminBookController.kt index 5b3e480..f7c07ad 100644 --- a/src/main/kotlin/com/msksbr/bookmgr/controller/AdminBookController.kt +++ b/src/main/kotlin/com/msksbr/bookmgr/controller/AdminBookController.kt @@ -2,6 +2,9 @@ package com.msksbr.bookmgr.controller import org.springframework.web.bind.annotation.RestController +/* +* 管理端图书接口 +*/ @RestController class AdminBookController { } \ No newline at end of file diff --git a/src/main/kotlin/com/msksbr/bookmgr/controller/AdminBorrowController.kt b/src/main/kotlin/com/msksbr/bookmgr/controller/AdminBorrowController.kt index aff4ef5..ceada83 100644 --- a/src/main/kotlin/com/msksbr/bookmgr/controller/AdminBorrowController.kt +++ b/src/main/kotlin/com/msksbr/bookmgr/controller/AdminBorrowController.kt @@ -2,6 +2,9 @@ package com.msksbr.bookmgr.controller import org.springframework.web.bind.annotation.RestController +/* +* 管理端借阅接口 +*/ @RestController class AdminBorrowController { } \ No newline at end of file diff --git a/src/main/kotlin/com/msksbr/bookmgr/controller/AuthController.kt b/src/main/kotlin/com/msksbr/bookmgr/controller/AuthController.kt index 9ec4498..98a49d6 100644 --- a/src/main/kotlin/com/msksbr/bookmgr/controller/AuthController.kt +++ b/src/main/kotlin/com/msksbr/bookmgr/controller/AuthController.kt @@ -14,8 +14,7 @@ import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController /* -* 登录接口 -* 接收DTO,返回json +* 认证接口:登录 / 登出 */ @RestController @RequestMapping("/api/auth") @@ -31,14 +30,13 @@ class AuthController( loginDTO: UserLoginDTO, request: HttpServletRequest ): Result { - log.info("Login from ${ipExtractor.getRealIp(request)} username: ${loginDTO.username}") - log.info("UA: ${request.getHeader("User-Agent")}") - // 调用service验证 + log.info("[Auth] login attempt: user={}, ip={}", loginDTO.username, ipExtractor.getRealIp(request)) + log.debug("[Auth] user agent: {}", request.getHeader("User-Agent")) val user = authService.login(loginDTO) return if (user != null) { - // 登录成功,返回JWT + // 登录成功,签发 JWT val token = jwtUtils.generateToken(user.username, user.role) - log.info("Login success") + log.info("[Auth] login success: user={}", user.username) Result.success( mapOf( "token" to token, @@ -47,8 +45,8 @@ class AuthController( ) ) } else { - log.info("Login failed") - Result.error("username or password not match") + log.info("[Auth] login failed: user={}", loginDTO.username) + Result.error("Incorrect username or password") } } @@ -56,10 +54,10 @@ class AuthController( fun logout( request: HttpServletRequest ): Result { - log.info("Logout from ${ipExtractor.getRealIp(request)}") - log.info("UA: ${request.getHeader("User-Agent")}") - // JWT无状态,只需返回成功让客户端自行删除token即可 - log.info("Logout success") + log.info("[Auth] logout: ip={}", ipExtractor.getRealIp(request)) + log.debug("[Auth] user agent: {}", request.getHeader("User-Agent")) + // JWT 无状态,登出只需客户端删除 token + log.info("[Auth] logout success") return Result.success("logout successfully") } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/msksbr/bookmgr/controller/BookController.kt b/src/main/kotlin/com/msksbr/bookmgr/controller/BookController.kt index 2db09c3..42fb6c5 100644 --- a/src/main/kotlin/com/msksbr/bookmgr/controller/BookController.kt +++ b/src/main/kotlin/com/msksbr/bookmgr/controller/BookController.kt @@ -2,6 +2,9 @@ package com.msksbr.bookmgr.controller import org.springframework.web.bind.annotation.RestController +/* +* 图书接口 +*/ @RestController class BookController { } \ No newline at end of file diff --git a/src/main/kotlin/com/msksbr/bookmgr/controller/BorrowController.kt b/src/main/kotlin/com/msksbr/bookmgr/controller/BorrowController.kt index e00638a..f706e54 100644 --- a/src/main/kotlin/com/msksbr/bookmgr/controller/BorrowController.kt +++ b/src/main/kotlin/com/msksbr/bookmgr/controller/BorrowController.kt @@ -2,6 +2,9 @@ package com.msksbr.bookmgr.controller import org.springframework.web.bind.annotation.RestController +/* +* 借阅接口 +*/ @RestController class BorrowController { } \ No newline at end of file diff --git a/src/main/kotlin/com/msksbr/bookmgr/controller/DashBoardController.kt b/src/main/kotlin/com/msksbr/bookmgr/controller/DashBoardController.kt index 1e2e882..bcdf8af 100644 --- a/src/main/kotlin/com/msksbr/bookmgr/controller/DashBoardController.kt +++ b/src/main/kotlin/com/msksbr/bookmgr/controller/DashBoardController.kt @@ -2,6 +2,9 @@ package com.msksbr.bookmgr.controller import org.springframework.web.bind.annotation.RestController +/* +* 仪表盘接口 +*/ @RestController class DashBoardController { } \ No newline at end of file diff --git a/src/main/kotlin/com/msksbr/bookmgr/dto/UserLoginDTO.kt b/src/main/kotlin/com/msksbr/bookmgr/dto/UserLoginDTO.kt index b8fc39a..c784c10 100644 --- a/src/main/kotlin/com/msksbr/bookmgr/dto/UserLoginDTO.kt +++ b/src/main/kotlin/com/msksbr/bookmgr/dto/UserLoginDTO.kt @@ -2,7 +2,9 @@ package com.msksbr.bookmgr.dto import jakarta.validation.constraints.NotBlank - +/* +* 登录请求体 +*/ data class UserLoginDTO( @NotBlank(message = "username is required") val username: String?, diff --git a/src/main/kotlin/com/msksbr/bookmgr/entity/Book.kt b/src/main/kotlin/com/msksbr/bookmgr/entity/Book.kt index a6f3553..d73ea23 100644 --- a/src/main/kotlin/com/msksbr/bookmgr/entity/Book.kt +++ b/src/main/kotlin/com/msksbr/bookmgr/entity/Book.kt @@ -4,6 +4,9 @@ import com.baomidou.mybatisplus.annotation.IdType import com.baomidou.mybatisplus.annotation.TableId import com.baomidou.mybatisplus.annotation.TableName +/* +* 图书实体,映射 book 表 +*/ @TableName("book") data class Book( @TableId(type = IdType.AUTO) diff --git a/src/main/kotlin/com/msksbr/bookmgr/entity/BorrowRecord.kt b/src/main/kotlin/com/msksbr/bookmgr/entity/BorrowRecord.kt index 2487b51..7b91493 100644 --- a/src/main/kotlin/com/msksbr/bookmgr/entity/BorrowRecord.kt +++ b/src/main/kotlin/com/msksbr/bookmgr/entity/BorrowRecord.kt @@ -5,6 +5,9 @@ import com.baomidou.mybatisplus.annotation.TableId import com.baomidou.mybatisplus.annotation.TableName import java.util.Date +/* +* 借阅记录实体,映射 book_record 表 +*/ @TableName("book_record") data class BorrowRecord( @TableId(type = IdType.AUTO) diff --git a/src/main/kotlin/com/msksbr/bookmgr/entity/User.kt b/src/main/kotlin/com/msksbr/bookmgr/entity/User.kt index 4a04d77..1321a14 100644 --- a/src/main/kotlin/com/msksbr/bookmgr/entity/User.kt +++ b/src/main/kotlin/com/msksbr/bookmgr/entity/User.kt @@ -4,6 +4,9 @@ import com.baomidou.mybatisplus.annotation.IdType import com.baomidou.mybatisplus.annotation.TableId import com.baomidou.mybatisplus.annotation.TableName +/* +* 用户实体,映射 user 表 +*/ @TableName("user") data class User( @TableId(type = IdType.AUTO) // 设置自增主键 diff --git a/src/main/kotlin/com/msksbr/bookmgr/interceptor/JwtAuthInterceptor.kt b/src/main/kotlin/com/msksbr/bookmgr/interceptor/JwtAuthInterceptor.kt index 04d21da..5894a03 100644 --- a/src/main/kotlin/com/msksbr/bookmgr/interceptor/JwtAuthInterceptor.kt +++ b/src/main/kotlin/com/msksbr/bookmgr/interceptor/JwtAuthInterceptor.kt @@ -1,12 +1,13 @@ package com.msksbr.bookmgr.interceptor -import com.fasterxml.jackson.databind.ObjectMapper + import com.msksbr.bookmgr.config.JwtUtils import com.msksbr.bookmgr.template.Result import jakarta.servlet.http.HttpServletRequest import jakarta.servlet.http.HttpServletResponse import org.springframework.stereotype.Component import org.springframework.web.servlet.HandlerInterceptor +import tools.jackson.databind.ObjectMapper @Component class JwtAuthInterceptor( diff --git a/src/main/kotlin/com/msksbr/bookmgr/mapper/BookMapper.kt b/src/main/kotlin/com/msksbr/bookmgr/mapper/BookMapper.kt index 6c6d075..d231b91 100644 --- a/src/main/kotlin/com/msksbr/bookmgr/mapper/BookMapper.kt +++ b/src/main/kotlin/com/msksbr/bookmgr/mapper/BookMapper.kt @@ -4,5 +4,8 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper import com.msksbr.bookmgr.entity.Book import org.apache.ibatis.annotations.Mapper +/* +* 图书 Mapper,继承 MyBatis-Plus BaseMapper 获得通用 CRUD +*/ @Mapper interface BookMapper: BaseMapper \ No newline at end of file diff --git a/src/main/kotlin/com/msksbr/bookmgr/mapper/BorrowRecordMapper.kt b/src/main/kotlin/com/msksbr/bookmgr/mapper/BorrowRecordMapper.kt index 76513a3..183c2c9 100644 --- a/src/main/kotlin/com/msksbr/bookmgr/mapper/BorrowRecordMapper.kt +++ b/src/main/kotlin/com/msksbr/bookmgr/mapper/BorrowRecordMapper.kt @@ -4,5 +4,8 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper import com.msksbr.bookmgr.entity.BorrowRecord import org.apache.ibatis.annotations.Mapper +/* +* 借阅记录 Mapper,继承 MyBatis-Plus BaseMapper 获得通用 CRUD +*/ @Mapper interface BorrowRecordMapper: BaseMapper \ No newline at end of file diff --git a/src/main/kotlin/com/msksbr/bookmgr/mapper/UserMapper.kt b/src/main/kotlin/com/msksbr/bookmgr/mapper/UserMapper.kt index 19b236b..dee0bbd 100644 --- a/src/main/kotlin/com/msksbr/bookmgr/mapper/UserMapper.kt +++ b/src/main/kotlin/com/msksbr/bookmgr/mapper/UserMapper.kt @@ -4,5 +4,8 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper import com.msksbr.bookmgr.entity.User import org.apache.ibatis.annotations.Mapper +/* +* 用户 Mapper,继承 MyBatis-Plus BaseMapper 获得通用 CRUD +*/ @Mapper interface UserMapper: BaseMapper \ No newline at end of file diff --git a/src/main/kotlin/com/msksbr/bookmgr/runner/InitUserRunner.kt b/src/main/kotlin/com/msksbr/bookmgr/runner/InitUserRunner.kt index 56485c6..9bd5fb6 100644 --- a/src/main/kotlin/com/msksbr/bookmgr/runner/InitUserRunner.kt +++ b/src/main/kotlin/com/msksbr/bookmgr/runner/InitUserRunner.kt @@ -10,21 +10,24 @@ import org.springframework.security.crypto.password.PasswordEncoder import org.springframework.stereotype.Component import org.springframework.transaction.annotation.Transactional +/* +* 应用启动时初始化默认用户(admin / user01 / user02) +* 已存在的用户会跳过,因此可安全重复执行 +*/ @Component class InitUserRunner( val passwordEncoder: PasswordEncoder, val userMapper: UserMapper, ) : ApplicationRunner { - // 添加注解,失败时可回滚 @Transactional override fun run(args: ApplicationArguments) { - log.info("Starting default user initialization") + log.info("[InitUser] starting") val existsAdmin = userMapper.selectOne( QueryWrapper() .eq("username", "admin") ) if (existsAdmin == null) { - log.info("Admin user not found, creating...") + log.info("[InitUser] admin not found, creating") insertAdmin() } val existsUser01 = userMapper.selectOne( @@ -32,7 +35,7 @@ class InitUserRunner( .eq("username", "user01") ) if (existsUser01 == null) { - log.info("Common user01 not found, creating...") + log.info("[InitUser] user01 not found, creating") insertUser01() } val existsUser02 = userMapper.selectOne( @@ -40,10 +43,10 @@ class InitUserRunner( .eq("username", "user02") ) if (existsUser02 == null) { - log.info("Common user02 not found, creating...") + log.info("[InitUser] user02 not found, creating") insertUser02() } - log.info("Default user initialization completed") + log.info("[InitUser] completed") } fun insertAdmin() { @@ -75,4 +78,4 @@ class InitUserRunner( ) userMapper.insert(user) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/msksbr/bookmgr/script/Log.kt b/src/main/kotlin/com/msksbr/bookmgr/script/Log.kt index 1c3cf8a..7a24263 100644 --- a/src/main/kotlin/com/msksbr/bookmgr/script/Log.kt +++ b/src/main/kotlin/com/msksbr/bookmgr/script/Log.kt @@ -4,7 +4,7 @@ import org.slf4j.Logger import org.slf4j.LoggerFactory /* -* 手动日志属性 +* SLF4J 日志扩展属性,通过 T.log 在任意类获取 Logger */ val T.log: Logger diff --git a/src/main/kotlin/com/msksbr/bookmgr/service/AuthService.kt b/src/main/kotlin/com/msksbr/bookmgr/service/AuthService.kt index 7c6bf4f..51b9a9a 100644 --- a/src/main/kotlin/com/msksbr/bookmgr/service/AuthService.kt +++ b/src/main/kotlin/com/msksbr/bookmgr/service/AuthService.kt @@ -3,6 +3,9 @@ package com.msksbr.bookmgr.service import com.msksbr.bookmgr.dto.UserLoginDTO import com.msksbr.bookmgr.entity.User +/* +* 认证服务 +*/ interface AuthService { fun login(loginDTO: UserLoginDTO): User? } \ No newline at end of file diff --git a/src/main/kotlin/com/msksbr/bookmgr/service/impl/AuthServiceImpl.kt b/src/main/kotlin/com/msksbr/bookmgr/service/impl/AuthServiceImpl.kt index 39419be..405841b 100644 --- a/src/main/kotlin/com/msksbr/bookmgr/service/impl/AuthServiceImpl.kt +++ b/src/main/kotlin/com/msksbr/bookmgr/service/impl/AuthServiceImpl.kt @@ -8,6 +8,9 @@ import com.msksbr.bookmgr.service.AuthService import org.springframework.security.crypto.password.PasswordEncoder import org.springframework.stereotype.Service +/* +* 认证服务实现,含时序攻击防护 +*/ @Service class AuthServiceImpl(private val userMapper: UserMapper, private val passwordEncoder: PasswordEncoder) : AuthService { override fun login(loginDTO: UserLoginDTO): User? { diff --git a/src/main/kotlin/com/msksbr/bookmgr/template/Result.kt b/src/main/kotlin/com/msksbr/bookmgr/template/Result.kt index c6d4771..723100e 100644 --- a/src/main/kotlin/com/msksbr/bookmgr/template/Result.kt +++ b/src/main/kotlin/com/msksbr/bookmgr/template/Result.kt @@ -1,5 +1,8 @@ package com.msksbr.bookmgr.template +/* +* 统一 API 响应格式 +*/ data class Result( var code: Int, var message: String,