feat: 自定义登录页

This commit is contained in:
Bunny 2025-01-27 14:18:13 +08:00
parent 4efb99a655
commit 58e0b5f4d1
19 changed files with 962 additions and 10 deletions

View File

@ -1522,3 +1522,225 @@ Thymeleaf 是一种现代化的 Java 模板引擎,广泛用于生成 HTML、XM
```
如果验证失败,错误消息将显示在 `<div>` 中。如果没有错误,它会显示默认的 "Error" 文本。
## SpringSecurity
### 密码转换器Password Encoder
Spring Security 提供了多种密码转换器Password Encoder这些转换器用于对用户密码进行加密和验证。常见的密码转换器包括
1. **BCryptPasswordEncoder**
- 使用 **BCrypt** 算法对密码进行加密。
- 是最常用的密码加密方案具有强大的加密性并且支持自动加盐salt防止暴力破解攻击。
- 示例:
```java
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
```
2. **NoOpPasswordEncoder**
- 不对密码进行加密,直接返回明文密码。
- 主要用于开发和测试环境,**不推荐在生产环境中使用**。
- 示例:
```java
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
```
3. **Pbkdf2PasswordEncoder**
- 使用 **PBKDF2** 算法进行密码加密。
- 提供较强的安全性,并且支持对密码进行哈希。
- 示例:
```java
@Bean
public PasswordEncoder passwordEncoder() {
return new Pbkdf2PasswordEncoder();
}
```
4. **Argon2PasswordEncoder**
- 使用 **Argon2** 算法对密码进行加密。
- Argon2 是目前被认为最强的密码哈希算法,支持内存密集型计算,从而防止硬件加速破解。
- 示例:
```java
@Bean
public PasswordEncoder passwordEncoder() {
return new Argon2PasswordEncoder();
}
```
5. **SCryptPasswordEncoder**
- 使用 **SCrypt** 算法进行密码加密。
- SCrypt 是另一种内存密集型的密码加密算法,与 Argon2 类似,旨在防止硬件加速破解。
- 示例:
```java
@Bean
public PasswordEncoder passwordEncoder() {
return new SCryptPasswordEncoder();
}
```
6. **MessageDigestPasswordEncoder** (已废弃)
- 基于 **MessageDigest** 算法进行加密(如 SHA-1、SHA-256 等)。
- 由于缺乏盐和密钥加密机制,已被其他更强的加密方式所替代。
> 选择密码转换器的建议:
>
> - 在现代应用中,推荐使用 **BCryptPasswordEncoder****Argon2PasswordEncoder**,这两种算法提供了强大的加密性。
> - **Pbkdf2PasswordEncoder****SCryptPasswordEncoder** 也可以作为备选方案,尤其是当你希望加密算法能够承受更多资源密集型攻击时。
> - **NoOpPasswordEncoder** 仅限于开发和测试环境。
### 访问主页
需要使用`http://localhost:8080/index`来访问主页,可以在配置中配置,访问根路径直接跳转
```java
@RequestMapping
@Controller
public class HomeController {
@Operation(summary = "主页内容")
@GetMapping("index")
public String index() {
return "index";
}
@Operation(summary = "订单内容")
@GetMapping("order")
public String order() {
return "order";
}
@Operation(summary = "login")
@GetMapping("login")
public String login() {
return "login";
}
}
```
在配置中
```java
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/")
// .setViewName("forward:/index") //两种方式写法
.setViewName("index");
registry.addViewController("/login");
}
}
```
### 自定义登录
```java
package cn.bunny.springdemo.configuration;
import cn.bunny.springdemo.dao.entity.AdminUser;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import java.util.ArrayList;
@Configuration
public class SecurityConfiguration {
@Bean
public PasswordEncoder passwordEncoder() {
return new SCryptPasswordEncoder(4, 8, 1, 8, 32);
}
/**
* 使用内存方式
*
* @param encoder 密码加密器
* @return 基于内存的用户
*/
@Bean
public UserDetailsService userDetailsService(PasswordEncoder encoder) {
ArrayList<UserDetails> userDetails = new ArrayList<>();
userDetails.add(new AdminUser("admin", encoder.encode("admin"), true));
userDetails.add(new AdminUser("bunny", encoder.encode("password"), true));
return new InMemoryUserDetailsManager(userDetails);
}
// /**
// * 使用数据库方式
// *
// * @param userService 获取用户数据(如数据库)
// * @return 基于数据库的用户
// */
// @Bean
// public UserDetailsService userDetailsService(UserService userService) {
// return username -> {
// AdminUser adminUser = userService.getOne(Wrappers.<AdminUser>lambdaQuery().eq(AdminUser::getUsername, userService));
// if (adminUser != null) {
// return adminUser;
// }
// throw new UsernameNotFoundException("未找到 AdminUser");
// };
// }
@Bean
public SecurityFilterChain filterChain(HttpSecurity security) throws Exception {
return security
.authorizeHttpRequests(authorizationManagerRequestMatcherRegistry ->
authorizationManagerRequestMatcherRegistry
.requestMatchers("/order").hasRole("USER")// 请求需要含有USER角色
.requestMatchers("/", "/index", "/login", "/images/**").permitAll()
)
/* 自定义登录页面 */
// .formLogin(AbstractAuthenticationFilterConfigurer::permitAll)// 默认的登录页会自动启用,无需额外配置
.formLogin(formLoginConfigurer -> formLoginConfigurer
.loginPage("/login")
// .loginProcessingUrl("/authenticate")
.usernameParameter("username")// 自定义用户名名称
.usernameParameter("password")// 自定义密码名称
.defaultSuccessUrl("/index")// 登录成功后默认跳转页面
// .defaultSuccessUrl("/index", true)// 登录成功后默认跳转页面,如果用户之前访问页面也需要强制跳转到 /index 可以传递第二个参数
)
.build();
}
}
```

View File

@ -17,7 +17,7 @@
<properties>
<java.version>17</java.version>
<mybatis-plus.version>3.5.6</mybatis-plus.version>
<mysql.version>8.0.30</mysql.version>
<mysql.version>8.0.33</mysql.version>
<HikariCP.version>5.1.0</HikariCP.version>
</properties>
@ -43,7 +43,6 @@
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>

View File

@ -30,3 +30,63 @@
11:13:44:041 INFO 12616 --- [spring-demo] [main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet ''
11:13:44:042 INFO 12616 --- [spring-demo] [main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 1 ms
11:13:44:062 INFO 12616 --- [spring-demo] [main] c.b.s.controller.HomeControllerTest : Started HomeControllerTest in 0.888 seconds (process running for 1.466)
12:56:08:799 INFO 10508 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : Starting SpringDemoApplicationTests using Java 17.0.9 with PID 10508 (started by 13199 in F:\学习\代码\Java\MultiThread\spring-demo)
12:56:08:802 INFO 10508 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : The following 1 profile is active: "dev"
12:56:09:855 INFO 10508 --- [spring-demo] [main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page template: index
12:56:09:868 INFO 10508 --- [spring-demo] [main] o.s.v.b.OptionalValidatorFactoryBean : Failed to set up a Bean Validation provider: jakarta.validation.NoProviderFoundException: Unable to create a Configuration, because no Jakarta Bean Validation provider could be found. Add a provider like Hibernate Validator (RI) to your classpath.
12:56:10:093 INFO 10508 --- [spring-demo] [main] r$InitializeUserDetailsManagerConfigurer : Global AuthenticationManager configured with UserDetailsService bean with name userDetailsService
12:56:10:240 INFO 10508 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : Started SpringDemoApplicationTests in 1.717 seconds (process running for 2.253)
12:56:30:906 INFO 21060 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : Starting SpringDemoApplicationTests using Java 17.0.9 with PID 21060 (started by 13199 in F:\学习\代码\Java\MultiThread\spring-demo)
12:56:30:909 INFO 21060 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : The following 1 profile is active: "dev"
12:56:31:936 INFO 21060 --- [spring-demo] [main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page template: index
12:56:31:950 INFO 21060 --- [spring-demo] [main] o.s.v.b.OptionalValidatorFactoryBean : Failed to set up a Bean Validation provider: jakarta.validation.NoProviderFoundException: Unable to create a Configuration, because no Jakarta Bean Validation provider could be found. Add a provider like Hibernate Validator (RI) to your classpath.
12:56:32:175 INFO 21060 --- [spring-demo] [main] r$InitializeUserDetailsManagerConfigurer : Global AuthenticationManager configured with UserDetailsService bean with name userDetailsService
12:56:32:317 INFO 21060 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : Started SpringDemoApplicationTests in 1.675 seconds (process running for 2.201)
12:56:49:178 INFO 19580 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : Starting SpringDemoApplicationTests using Java 17.0.9 with PID 19580 (started by 13199 in F:\学习\代码\Java\MultiThread\spring-demo)
12:56:49:181 INFO 19580 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : The following 1 profile is active: "dev"
12:56:50:206 INFO 19580 --- [spring-demo] [main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page template: index
12:56:50:220 INFO 19580 --- [spring-demo] [main] o.s.v.b.OptionalValidatorFactoryBean : Failed to set up a Bean Validation provider: jakarta.validation.NoProviderFoundException: Unable to create a Configuration, because no Jakarta Bean Validation provider could be found. Add a provider like Hibernate Validator (RI) to your classpath.
12:56:50:449 INFO 19580 --- [spring-demo] [main] r$InitializeUserDetailsManagerConfigurer : Global AuthenticationManager configured with UserDetailsService bean with name userDetailsService
12:56:50:598 INFO 19580 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : Started SpringDemoApplicationTests in 1.688 seconds (process running for 2.241)
12:57:19:701 INFO 12696 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : Starting SpringDemoApplicationTests using Java 17.0.9 with PID 12696 (started by 13199 in F:\学习\代码\Java\MultiThread\spring-demo)
12:57:19:704 INFO 12696 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : The following 1 profile is active: "dev"
12:57:20:735 INFO 12696 --- [spring-demo] [main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page template: index
12:57:20:750 INFO 12696 --- [spring-demo] [main] o.s.v.b.OptionalValidatorFactoryBean : Failed to set up a Bean Validation provider: jakarta.validation.NoProviderFoundException: Unable to create a Configuration, because no Jakarta Bean Validation provider could be found. Add a provider like Hibernate Validator (RI) to your classpath.
12:57:20:979 INFO 12696 --- [spring-demo] [main] r$InitializeUserDetailsManagerConfigurer : Global AuthenticationManager configured with UserDetailsService bean with name userDetailsService
12:57:21:127 INFO 12696 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : Started SpringDemoApplicationTests in 1.708 seconds (process running for 2.258)
12:57:45:076 INFO 9352 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : Starting SpringDemoApplicationTests using Java 17.0.9 with PID 9352 (started by 13199 in F:\学习\代码\Java\MultiThread\spring-demo)
12:57:45:079 INFO 9352 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : The following 1 profile is active: "dev"
12:57:46:202 INFO 9352 --- [spring-demo] [main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page template: index
12:57:46:219 INFO 9352 --- [spring-demo] [main] o.s.v.b.OptionalValidatorFactoryBean : Failed to set up a Bean Validation provider: jakarta.validation.NoProviderFoundException: Unable to create a Configuration, because no Jakarta Bean Validation provider could be found. Add a provider like Hibernate Validator (RI) to your classpath.
12:57:46:462 INFO 9352 --- [spring-demo] [main] r$InitializeUserDetailsManagerConfigurer : Global AuthenticationManager configured with UserDetailsService bean with name userDetailsService
12:57:46:630 INFO 9352 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : Started SpringDemoApplicationTests in 1.858 seconds (process running for 2.69)
12:58:16:559 INFO 1652 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : Starting SpringDemoApplicationTests using Java 17.0.9 with PID 1652 (started by 13199 in F:\学习\代码\Java\MultiThread\spring-demo)
12:58:16:563 INFO 1652 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : The following 1 profile is active: "dev"
12:58:17:571 INFO 1652 --- [spring-demo] [main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page template: index
12:58:17:585 INFO 1652 --- [spring-demo] [main] o.s.v.b.OptionalValidatorFactoryBean : Failed to set up a Bean Validation provider: jakarta.validation.NoProviderFoundException: Unable to create a Configuration, because no Jakarta Bean Validation provider could be found. Add a provider like Hibernate Validator (RI) to your classpath.
12:58:17:813 INFO 1652 --- [spring-demo] [main] r$InitializeUserDetailsManagerConfigurer : Global AuthenticationManager configured with UserDetailsService bean with name userDetailsService
12:58:17:955 INFO 1652 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : Started SpringDemoApplicationTests in 1.689 seconds (process running for 2.236)
12:58:31:856 INFO 4352 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : Starting SpringDemoApplicationTests using Java 17.0.9 with PID 4352 (started by 13199 in F:\学习\代码\Java\MultiThread\spring-demo)
12:58:31:860 INFO 4352 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : The following 1 profile is active: "dev"
12:58:42:935 INFO 4352 --- [spring-demo] [main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page template: index
12:58:42:951 INFO 4352 --- [spring-demo] [main] o.s.v.b.OptionalValidatorFactoryBean : Failed to set up a Bean Validation provider: jakarta.validation.NoProviderFoundException: Unable to create a Configuration, because no Jakarta Bean Validation provider could be found. Add a provider like Hibernate Validator (RI) to your classpath.
12:58:43:193 INFO 4352 --- [spring-demo] [main] r$InitializeUserDetailsManagerConfigurer : Global AuthenticationManager configured with UserDetailsService bean with name userDetailsService
12:58:43:364 INFO 4352 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : Started SpringDemoApplicationTests in 11.813 seconds (process running for 12.431)
12:58:47:757 INFO 22540 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : Starting SpringDemoApplicationTests using Java 17.0.9 with PID 22540 (started by 13199 in F:\学习\代码\Java\MultiThread\spring-demo)
12:58:47:760 INFO 22540 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : The following 1 profile is active: "dev"
12:58:53:578 INFO 22540 --- [spring-demo] [main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page template: index
12:58:53:593 INFO 22540 --- [spring-demo] [main] o.s.v.b.OptionalValidatorFactoryBean : Failed to set up a Bean Validation provider: jakarta.validation.NoProviderFoundException: Unable to create a Configuration, because no Jakarta Bean Validation provider could be found. Add a provider like Hibernate Validator (RI) to your classpath.
12:58:53:835 INFO 22540 --- [spring-demo] [main] r$InitializeUserDetailsManagerConfigurer : Global AuthenticationManager configured with UserDetailsService bean with name userDetailsService
12:58:54:003 INFO 22540 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : Started SpringDemoApplicationTests in 6.548 seconds (process running for 7.169)
12:59:00:364 INFO 21332 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : Starting SpringDemoApplicationTests using Java 17.0.9 with PID 21332 (started by 13199 in F:\学习\代码\Java\MultiThread\spring-demo)
12:59:00:367 INFO 21332 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : The following 1 profile is active: "dev"
12:59:01:498 INFO 21332 --- [spring-demo] [main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page template: index
12:59:01:514 INFO 21332 --- [spring-demo] [main] o.s.v.b.OptionalValidatorFactoryBean : Failed to set up a Bean Validation provider: jakarta.validation.NoProviderFoundException: Unable to create a Configuration, because no Jakarta Bean Validation provider could be found. Add a provider like Hibernate Validator (RI) to your classpath.
12:59:01:752 INFO 21332 --- [spring-demo] [main] r$InitializeUserDetailsManagerConfigurer : Global AuthenticationManager configured with UserDetailsService bean with name userDetailsService
12:59:01:920 INFO 21332 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : Started SpringDemoApplicationTests in 1.851 seconds (process running for 2.456)
13:02:06:411 INFO 13172 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : Starting SpringDemoApplicationTests using Java 17.0.9 with PID 13172 (started by 13199 in F:\学习\代码\Java\MultiThread\spring-demo)
13:02:06:416 INFO 13172 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : The following 1 profile is active: "dev"
13:02:07:458 INFO 13172 --- [spring-demo] [main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page template: index
13:02:07:471 INFO 13172 --- [spring-demo] [main] o.s.v.b.OptionalValidatorFactoryBean : Failed to set up a Bean Validation provider: jakarta.validation.NoProviderFoundException: Unable to create a Configuration, because no Jakarta Bean Validation provider could be found. Add a provider like Hibernate Validator (RI) to your classpath.
13:02:07:695 INFO 13172 --- [spring-demo] [main] r$InitializeUserDetailsManagerConfigurer : Global AuthenticationManager configured with UserDetailsService bean with name userDetailsService
13:02:07:837 INFO 13172 --- [spring-demo] [main] c.b.s.SpringDemoApplicationTests : Started SpringDemoApplicationTests in 1.696 seconds (process running for 2.265)

View File

@ -30,6 +30,9 @@
<java.version>17</java.version>
<fastjson2.version>2.0.47</fastjson2.version>
<version>${junit.version}</version>
<mybatis-plus.version>3.5.6</mybatis-plus.version>
<mysql.version>8.0.33</mysql.version>
<HikariCP.version>5.1.0</HikariCP.version>
</properties>
<dependencies>
<dependency>
@ -45,6 +48,17 @@
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version> <!-- 请使用最新版本 -->
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpg-jdk15on</artifactId>
<version>1.70</version> <!-- 请使用最新版本 -->
</dependency>
<!-- devtools -->
<dependency>
<groupId>org.springframework.boot</groupId>
@ -92,7 +106,24 @@
<artifactId>hutool-all</artifactId>
<version>5.8.27</version>
</dependency>
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!-- mysql连接池 -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>${HikariCP.version}</version>
</dependency>
</dependencies>
<build>

View File

@ -0,0 +1,76 @@
package cn.bunny.springdemo.configuration;
import cn.bunny.springdemo.dao.entity.AdminUser;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import java.util.ArrayList;
@Configuration
public class SecurityConfiguration {
@Bean
public PasswordEncoder passwordEncoder() {
return new SCryptPasswordEncoder(4, 8, 1, 8, 32);
}
/**
* 使用内存方式
*
* @param encoder 密码加密器
* @return 基于内存的用户
*/
@Bean
public UserDetailsService userDetailsService(PasswordEncoder encoder) {
ArrayList<UserDetails> userDetails = new ArrayList<>();
userDetails.add(new AdminUser("admin", encoder.encode("admin"), true));
userDetails.add(new AdminUser("bunny", encoder.encode("password"), true));
return new InMemoryUserDetailsManager(userDetails);
}
// /**
// * 使用数据库方式
// *
// * @param userService 获取用户数据如数据库
// * @return 基于数据库的用户
// */
// @Bean
// public UserDetailsService userDetailsService(UserService userService) {
// return username -> {
// AdminUser adminUser = userService.getOne(Wrappers.<AdminUser>lambdaQuery().eq(AdminUser::getUsername, userService));
// if (adminUser != null) {
// return adminUser;
// }
// throw new UsernameNotFoundException("未找到 AdminUser");
// };
// }
@Bean
public SecurityFilterChain filterChain(HttpSecurity security) throws Exception {
return security
.authorizeHttpRequests(authorizationManagerRequestMatcherRegistry ->
authorizationManagerRequestMatcherRegistry
.requestMatchers("/order").hasRole("USER")// 请求需要含有USER角色
.requestMatchers("/", "/index", "/login", "/images/**").permitAll()
)
/* 自定义登录页面 */
// .formLogin(AbstractAuthenticationFilterConfigurer::permitAll)// 默认的登录页会自动启用无需额外配置
.formLogin(formLoginConfigurer -> formLoginConfigurer
.loginPage("/login")
// .loginProcessingUrl("/authenticate")
.usernameParameter("username")// 自定义用户名名称
.usernameParameter("password")// 自定义密码名称
.defaultSuccessUrl("/index")// 登录成功后默认跳转页面
// .defaultSuccessUrl("/index", true)// 登录成功后默认跳转页面如果用户之前访问页面也需要强制跳转到 /index 可以传递第二个参数
)
.build();
}
}

View File

@ -0,0 +1,16 @@
package cn.bunny.springdemo.configuration;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/")
// .setViewName("forward:/index") //两种方式写法
.setViewName("index");
}
}

View File

@ -14,4 +14,16 @@ public class HomeController {
public String index() {
return "index";
}
@Operation(summary = "订单内容")
@GetMapping("order")
public String order() {
return "order";
}
@Operation(summary = "login")
@GetMapping("login")
public String login() {
return "login";
}
}

View File

@ -0,0 +1,48 @@
package cn.bunny.springdemo.dao;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@Schema(name = "BaseEntity", title = "基础信息字段", description = "基础信息字段")
public class BaseEntity implements Serializable {
@Schema(name = "id", title = "唯一标识")
@TableId(value = "id", type = IdType.ASSIGN_ID)
@JsonFormat(shape = JsonFormat.Shape.STRING)
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
@Schema(name = "createTime", title = "创建时间")
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@Schema(name = "updateTime", title = "更新时间")
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@Schema(name = "createUser", title = "创建用户")
@TableField(fill = FieldFill.INSERT)
@JsonFormat(shape = JsonFormat.Shape.STRING)
@JsonSerialize(using = ToStringSerializer.class)
private Long createUser;
@Schema(name = "updateUser", title = "操作用户")
@TableField(fill = FieldFill.INSERT_UPDATE)
@JsonFormat(shape = JsonFormat.Shape.STRING)
@JsonSerialize(using = ToStringSerializer.class)
private Long updateUser;
@Schema(name = "isDeleted", title = "是否被删除")
@TableLogic
private Boolean isDeleted;
}

View File

@ -0,0 +1,18 @@
package cn.bunny.springdemo.dao;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
@Schema(name = "BaseUserEntity", title = "基础信息字段包含用户信息", description = "基础信息字段包含用户信息")
public class BaseUserEntity extends BaseEntity {
@Schema(name = "username", title = "用户名")
private String createUsername;
@Schema(name = "nickname", title = "昵称")
private String updateUsername;
}

View File

@ -0,0 +1,44 @@
package cn.bunny.springdemo.dao.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Schema(name = "BillDto对象", title = "账单信息查询内容", description = "账单信息查询内容")
public class BillDto {
@Schema(name = "userId", title = "绑定的用户id")
private Long userId;
@Schema(name = "amount", title = "金额")
private BigDecimal amount;
@Schema(name = "categoryIds", title = "类别分类")
private List<Long> categoryIds;
@Schema(name = "username", title = "类型1 - 收入,-1 - 支出")
private Byte type;
@Schema(name = "description", title = "描述")
private String description;
@Schema(name = "startDate", title = "开始交易日期")
@JsonFormat(locale = "zh", timezone = "GMT+8", pattern = "yyyy-MM-dd")
private LocalDate startDate;
@Schema(name = "endDate", title = "结束交易日期")
@JsonFormat(locale = "zh", timezone = "GMT+8", pattern = "yyyy-MM-dd")
private LocalDate endDate;
}

View File

@ -0,0 +1,49 @@
package cn.bunny.springdemo.dao.entity;
import cn.bunny.springdemo.dao.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.List;
/**
* <p>
* 管理员用户信息
* </p>
*
* @author Bunny
* @since 2024-06-26
*/
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
@TableName("sys_user")
@Schema(name = "AdminUser对象", title = "用户信息", description = "用户信息")
public class AdminUser extends BaseEntity implements UserDetails {
@Schema(name = "username", title = "用户名")
private String username;
@Schema(name = "password", title = "密码")
private String password;
@Schema(name = "status", title = "状态", description = "1:禁用 0:正常")
private Boolean status;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return List.of(new SimpleGrantedAuthority("ROLE_USER"));
}
}

View File

@ -0,0 +1,49 @@
package cn.bunny.springdemo.dao.entity;
import cn.bunny.springdemo.dao.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* <p>
* 账单信息
* </p>
*
* @author Bunny
* @since 2024-11-07
*/
@Getter
@Setter
@Accessors(chain = true)
@TableName("t_bill")
@Schema(name = "Bill对象", title = "账单信息", description = "账单信息")
public class Bill extends BaseEntity {
@Schema(name = "username", title = "类型1 - 收入,-1 - 支出")
private Byte type;
@Schema(name = "userId", title = "绑定的用户id")
private Long userId;
@Schema(name = "amount", title = "金额")
private BigDecimal amount;
@Schema(name = "description", title = "描述")
private String description;
@Schema(name = "transactionDate", title = "交易日期")
private LocalDateTime transactionDate;
@Schema(name = "categoryId", title = "类别id")
private Long categoryId;
}

View File

@ -0,0 +1,19 @@
package cn.bunny.springdemo.mapper;
import cn.bunny.springdemo.dao.entity.AdminUser;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* 用户信息 Mapper 接口
* </p>
*
* @author Bunny
* @since 2024-09-26
*/
@Mapper
public interface UserMapper extends BaseMapper<AdminUser> {
}

View File

@ -0,0 +1,16 @@
package cn.bunny.springdemo.services;
import cn.bunny.springdemo.dao.entity.AdminUser;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 用户信息 服务类
* </p>
*
* @author Bunny
* @since 2024-09-26
*/
public interface UserService extends IService<AdminUser> {
}

View File

@ -0,0 +1,21 @@
package cn.bunny.springdemo.services.impl;
import cn.bunny.springdemo.dao.entity.AdminUser;
import cn.bunny.springdemo.mapper.UserMapper;
import cn.bunny.springdemo.services.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* 用户信息 服务实现类
*
* @author Bunny
* @since 2024-09-26
*/
@Service
@Transactional
public class UserServiceImpl extends ServiceImpl<UserMapper, AdminUser> implements UserService {
}

View File

@ -8,12 +8,12 @@ spring:
multipart:
max-file-size: 6MB
# datasource:
# type: com.zaxxer.hikari.HikariDataSource
# driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://${bunny.master.host}:${bunny.master.port}/${bunny.master.database}?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true
# username: ${bunny.master.username}
# password: ${bunny.master.password}
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://${bunny.master.host}:${bunny.master.port}/${bunny.master.database}?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true
username: ${bunny.master.username}
password: ${bunny.master.password}
jackson:
date-format: yyyy-MM-dd HH:mm:ss

View File

@ -0,0 +1,255 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>边框流动效果的login页面 www.bootstrapmb.com</title>
<meta charset="UTF-8"/>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
<meta content="ie=edge" http-equiv="X-UA-Compatible"/>
<style media="screen">
* {
padding: 0;
margin: 0;
box-sizing: border-box
}
body {
font-family: sans-serif;
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
background: #0c0116
}
.form {
position: relative;
padding: 60px 15px;
width: 270px;
height: 350px;
background: #0c0116;
overflow: hidden;
box-shadow: 0 0 10px 0 #747772;
border-radius: 5px
}
.form-inner {
position: absolute;
height: 98%;
width: 98%;
top: 50%;
left: 50%;
background: #0c0116;
transform: translate(-50%, -50%)
}
.content {
height: 100%;
width: 100%;
padding: 25px
}
.form-inner h2 {
font-size: 25px;
color: #d7a3d7;
text-align: center;
padding-top: 35px
}
.input {
display: block;
padding: 12px 15px;
width: 100%;
left: 50%;
border-radius: 10px;
margin-top: 20px;
border: 1.5px solid #6d5779;
outline: 0;
background: #19052c;
color: white
}
.btn {
cursor: pointer;
color: white;
margin-top: 40px;
width: 100%;
padding: 12px;
outline: 0;
background: #800080;
border: 0;
font-size: 18px;
border-radius: 10px;
transition: .4s
}
.btn:hover {
background: #c907c9
}
.form span {
position: absolute;
height: 50%;
width: 50%
}
.form span:nth-child(1) {
background: #ffda05;
top: 0;
left: -48%;
animation: 5s span1 infinite linear;
animation-delay: 1s
}
.form span:nth-child(2) {
background: #00a800;
bottom: 0;
right: -48%;
animation: 5s span2 infinite linear
}
.form span:nth-child(3) {
background: #800080;
right: -48%;
top: 0;
animation: 5s span3 infinite linear
}
.form span:nth-child(4) {
background: #f00;
bottom: 0;
right: -48%;
animation: 5s span4 infinite linear;
animation-delay: 1s
}
@keyframes span1 {
0% {
top: -48%;
left: -48%
}
25% {
top: -48%;
left: 98%
}
50% {
top: 98%;
left: 98%
}
75% {
top: 98%;
left: -48%
}
100% {
top: -48%;
left: -48%
}
}
@keyframes span2 {
0% {
bottom: -48%;
right: -48%
}
25% {
bottom: -48%;
right: 98%
}
50% {
bottom: 98%;
right: 98%
}
75% {
bottom: 98%;
right: -48%
}
100% {
bottom: -48%;
right: -48%
}
}
@keyframes span3 {
0% {
top: -48%;
left: -48%
}
25% {
top: -48%;
left: 98%
}
50% {
top: 98%;
left: 98%
}
75% {
top: 98%;
left: -48%
}
100% {
top: -48%;
left: -48%
}
}
@keyframes span4 {
0% {
bottom: -48%;
right: -48%
}
25% {
bottom: -48%;
right: 98%
}
50% {
bottom: 98%;
right: 98%
}
75% {
bottom: 98%;
right: -48%
}
100% {
bottom: -48%;
right: -48%
}
}
</style>
</head>
<body>
<form class="form" method="post" th:action="@{/login}">
<span></span>
<span></span>
<span></span>
<span></span>
<div class="form-inner">
<h2>登录界面</h2>
<div class="content">
<label>
<input class="input" name="username" placeholder="用户名" type="text" value="admin"/>
</label>
<label>
<input class="input" name="password" placeholder="密码" type="password" value="admin"/>
</label>
<button class="btn">登录</button>
</div>
</div>
</form>
</body>
</html>

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>订单内容</title>
</head>
<body>
<h1>订单内容</h1>
</body>
</html>

View File

@ -1,13 +1,20 @@
package cn.bunny.springdemo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.crypto.password.PasswordEncoder;
@SpringBootTest
class SpringDemoApplicationTests {
@Autowired
PasswordEncoder passwordEncoder;
@Test
void contextLoads() {
String s = passwordEncoder.encode("admin123");
System.out.println(s);
}
}