From 52298e7fff8f4db0395fc626902941f1f0616a6b Mon Sep 17 00:00:00 2001 From: msksbr515 Date: Wed, 20 May 2026 12:43:05 +0800 Subject: [PATCH] feat(auth): add password encoding and default user initialization - Register Argon2PasswordEncoder as a Spring bean - Implement InitUserRunner to seed default users on startup - Add spring-security-crypto and bouncycastle dependencies - Include database schema initialization script --- bookmgr.sql | 78 +++++++++++++++++++ build.gradle.kts | 2 + .../msksbr/bookmgr/config/PasswordConfig.kt | 15 ++++ .../msksbr/bookmgr/runner/InitUserRunner.kt | 75 ++++++++++++++++++ 4 files changed, 170 insertions(+) create mode 100644 bookmgr.sql create mode 100644 src/main/kotlin/com/msksbr/bookmgr/config/PasswordConfig.kt create mode 100644 src/main/kotlin/com/msksbr/bookmgr/runner/InitUserRunner.kt diff --git a/bookmgr.sql b/bookmgr.sql new file mode 100644 index 0000000..d4e1a4d --- /dev/null +++ b/bookmgr.sql @@ -0,0 +1,78 @@ +-- MySQL dump 10.13 Distrib 8.0.45, for Linux (x86_64) +-- +-- Host: 127.0.0.1 Database: bookmgr +-- ------------------------------------------------------ +-- Server version 8.0.45 + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!50503 SET NAMES utf8mb4 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `book` +-- + +DROP TABLE IF EXISTS `book`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `book` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `author` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `stock` int DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `borrow_record` +-- + +DROP TABLE IF EXISTS `borrow_record`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `borrow_record` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `user_id` bigint DEFAULT NULL, + `book_id` bigint DEFAULT NULL, + `borrow_time` datetime DEFAULT NULL, + `return_time` datetime DEFAULT NULL, + `status` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `user` +-- + +DROP TABLE IF EXISTS `user`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `user` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `username` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL, + `password` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `role` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT 'USER', + PRIMARY KEY (`id`), + UNIQUE KEY `username` (`username`) +) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed on 2026-05-19 19:07:05 diff --git a/build.gradle.kts b/build.gradle.kts index 3e6edfa..06a1f3c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -23,6 +23,8 @@ dependencies { implementation("org.springframework.boot:spring-boot-starter") implementation("org.jetbrains.kotlin:kotlin-reflect") implementation("org.springframework.boot:spring-boot-starter-web") + implementation("org.springframework.security:spring-security-crypto") + implementation("org.bouncycastle:bcprov-jdk18on:1.84") implementation("com.mysql:mysql-connector-j") implementation("com.baomidou:mybatis-plus-spring-boot4-starter:3.5.15") testImplementation("org.springframework.boot:spring-boot-starter-test") diff --git a/src/main/kotlin/com/msksbr/bookmgr/config/PasswordConfig.kt b/src/main/kotlin/com/msksbr/bookmgr/config/PasswordConfig.kt new file mode 100644 index 0000000..e0e1124 --- /dev/null +++ b/src/main/kotlin/com/msksbr/bookmgr/config/PasswordConfig.kt @@ -0,0 +1,15 @@ +package com.msksbr.bookmgr.config + +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.security.crypto.argon2.Argon2PasswordEncoder +import org.springframework.security.crypto.password.PasswordEncoder + +// 将Argon2的加盐哈希方法注册成Bean +@Configuration +class PasswordConfig { + @Bean + fun passwordEncoder(): PasswordEncoder { + return Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8() + } +} \ 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 new file mode 100644 index 0000000..d3f9967 --- /dev/null +++ b/src/main/kotlin/com/msksbr/bookmgr/runner/InitUserRunner.kt @@ -0,0 +1,75 @@ +package com.msksbr.bookmgr.runner + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper +import com.msksbr.bookmgr.entity.User +import com.msksbr.bookmgr.mapper.UserMapper +import org.slf4j.LoggerFactory +import org.springframework.boot.ApplicationArguments +import org.springframework.boot.ApplicationRunner +import org.springframework.security.crypto.password.PasswordEncoder +import org.springframework.stereotype.Component +import org.springframework.transaction.annotation.Transactional + +@Component +class InitUserRunner( + val passwordEncoder: PasswordEncoder, + val userMapper: UserMapper, +) : ApplicationRunner { + private val logger= LoggerFactory.getLogger(InitUserRunner::class.java) + // 添加注解,失败时可回滚 + @Transactional + override fun run(args: ApplicationArguments) { + logger.info("Init user") + insertUser() + logger.info("Init user complete") + } + + fun insertUser() { + // 创建admin账户 + logger.info("create admin user") + val admin = User( + null, + "admin", + // 1. 使用 Argon2 对密码进行哈希处理(自动包含随机 salt) + // 2. encode() 来自 Java 接口,Kotlin 会将返回值视为平台类型,因此这里断言非空 + passwordEncoder.encode("admin")!!, + "admin" + ) + logger.info("insert common user") + // 创建普通账户 + val user = User( + null, + "user", + passwordEncoder.encode("user")!!, + "user" + ) + // 插入到数据库 + // 先查询数据库中是否有admin账户 + logger.info("select admin user from database") + val existsAdmin = userMapper.selectOne( + QueryWrapper() + .eq("username", admin.username) + ) + // 没有则插入 + if (existsAdmin == null) { + logger.info("admin user not found") + logger.info("insert admin user to database") + userMapper.insert(admin) + }else{ + logger.info("found exists admin user") + } + + logger.info("select common user from database") + val existsUser = userMapper.selectOne( + QueryWrapper() + .eq("username", user.username) + ) + if (existsUser == null) { + logger.info("common user not found") + logger.info("insert common user to database") + userMapper.insert(user) + }else{ + logger.info("found exists common user") + } + } +} \ No newline at end of file