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
This commit is contained in:
+78
@@ -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
|
||||||
@@ -23,6 +23,8 @@ dependencies {
|
|||||||
implementation("org.springframework.boot:spring-boot-starter")
|
implementation("org.springframework.boot:spring-boot-starter")
|
||||||
implementation("org.jetbrains.kotlin:kotlin-reflect")
|
implementation("org.jetbrains.kotlin:kotlin-reflect")
|
||||||
implementation("org.springframework.boot:spring-boot-starter-web")
|
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.mysql:mysql-connector-j")
|
||||||
implementation("com.baomidou:mybatis-plus-spring-boot4-starter:3.5.15")
|
implementation("com.baomidou:mybatis-plus-spring-boot4-starter:3.5.15")
|
||||||
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
||||||
|
|||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<User>()
|
||||||
|
.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<User>()
|
||||||
|
.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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user