• Spring Boot Security使用 JDBC 和 MySQL 进行 RBAC,自定义登录验证,登录界面增加kaptcha验证码


     在本教程中,我将指导您如何编写代码,以使用具有基于表单的身份验证的Spring安全API来保护Spring Boot应用程序中的网页。用户详细信息存储在MySQL数据库中,并使用春季JDBC连接到数据库。我们将从本教程中的 ProductManager 项目开始,向现有的弹簧启动项目添加登录和注销功能。

    1. 创建用户表和虚拟凭据

    凭据应存储在数据库中,因此让我们创建新表,表间关系ER图如下:

    1. -- --------------------------------------------------------
    2. -- 主机: 127.0.0.1
    3. -- 服务器版本: 8.0.22 - MySQL Community Server - GPL
    4. -- 服务器操作系统: Win64
    5. -- HeidiSQL 版本: 12.1.0.6537
    6. -- --------------------------------------------------------
    7. /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
    8. /*!40101 SET NAMES utf8 */;
    9. /*!50503 SET NAMES utf8mb4 */;
    10. /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
    11. /*!40103 SET TIME_ZONE='+00:00' */;
    12. /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
    13. /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
    14. /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
    15. -- 导出 product3 的数据库结构
    16. CREATE DATABASE IF NOT EXISTS `product3` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;
    17. USE `product3`;
    18. -- 导出 表 product3.permissions 结构
    19. CREATE TABLE IF NOT EXISTS `permissions` (
    20. `name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
    21. `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
    22. PRIMARY KEY (`name`)
    23. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
    24. -- 正在导出表 product3.permissions 的数据:~3 rows (大约)
    25. INSERT INTO `permissions` (`name`, `description`) VALUES
    26. ('ADMIN', NULL),
    27. ('DELETE', 'delete'),
    28. ('READ', 'read'),
    29. ('WRITE', 'write');
    30. -- 导出 表 product3.product 结构
    31. CREATE TABLE IF NOT EXISTS `product` (
    32. `id` bigint NOT NULL AUTO_INCREMENT,
    33. `brand` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
    34. `madein` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
    35. `name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
    36. `price` float NOT NULL,
    37. PRIMARY KEY (`id`)
    38. ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
    39. -- 正在导出表 product3.product 的数据:~1 rows (大约)
    40. INSERT INTO `product` (`id`, `brand`, `madein`, `name`, `price`) VALUES
    41. (1, '666', '666', '数据库', 222);
    42. -- 导出 表 product3.roles 结构
    43. CREATE TABLE IF NOT EXISTS `roles` (
    44. `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
    45. `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
    46. PRIMARY KEY (`name`)
    47. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
    48. -- 正在导出表 product3.roles 的数据:~3 rows (大约)
    49. INSERT INTO `roles` (`name`, `description`) VALUES
    50. ('ADMIN', 'Administrator role'),
    51. ('USER_P1', 'Perfil 1'),
    52. ('USER_P2', 'Perfil 2');
    53. -- 导出 表 product3.roles_permissions 结构
    54. CREATE TABLE IF NOT EXISTS `roles_permissions` (
    55. `role_name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
    56. `permission` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
    57. PRIMARY KEY (`role_name`,`permission`),
    58. KEY `RP_1` (`role_name`),
    59. KEY `RP_2` (`permission`),
    60. CONSTRAINT `RP_1` FOREIGN KEY (`role_name`) REFERENCES `roles` (`name`),
    61. CONSTRAINT `RP_2` FOREIGN KEY (`permission`) REFERENCES `permissions` (`name`)
    62. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
    63. -- 正在导出表 product3.roles_permissions 的数据:~4 rows (大约)
    64. INSERT INTO `roles_permissions` (`role_name`, `permission`) VALUES
    65. ('ADMIN', 'ADMIN'),
    66. ('ADMIN', 'DELETE'),
    67. ('ADMIN', 'READ'),
    68. ('ADMIN', 'WRITE'),
    69. ('USER_P1', 'READ'),
    70. ('USER_P2', 'DELETE'),
    71. ('USER_P2', 'WRITE');
    72. -- 导出 表 product3.users 结构
    73. CREATE TABLE IF NOT EXISTS `users` (
    74. `username` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
    75. `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
    76. `name` varchar(65) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
    77. `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
    78. `enabled` int DEFAULT NULL,
    79. PRIMARY KEY (`username`)
    80. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
    81. -- 正在导出表 product3.users 的数据:~3 rows (大约)
    82. INSERT INTO `users` (`username`, `email`, `name`, `password`, `enabled`) VALUES
    83. ('admin', 'admin@example.com', 'Administrator', '$2a$10$2/LSmp3YoEOT97KzgrYODen7I88ErBovM2Qehw9DL1dW9DZ7DZSAm', 1),
    84. ('u1', 'u1@example.com', 'User P1', '$2a$10$2/LSmp3YoEOT97KzgrYODen7I88ErBovM2Qehw9DL1dW9DZ7DZSAm', 1),
    85. ('u2', 'u2@example.com', 'User P2', '$2a$10$2/LSmp3YoEOT97KzgrYODen7I88ErBovM2Qehw9DL1dW9DZ7DZSAm', 1);
    86. -- 导出 表 product3.users_roles 结构
    87. CREATE TABLE IF NOT EXISTS `users_roles` (
    88. `username` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
    89. `role_name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
    90. PRIMARY KEY (`username`,`role_name`),
    91. KEY `UR_1` (`username`),
    92. KEY `UR_2` (`role_name`),
    93. CONSTRAINT `UR_1` FOREIGN KEY (`username`) REFERENCES `users` (`username`),
    94. CONSTRAINT `UR_2` FOREIGN KEY (`role_name`) REFERENCES `roles` (`name`)
    95. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
    96. -- 正在导出表 product3.users_roles 的数据:~0 rows (大约)
    97. INSERT INTO `users_roles` (`username`, `role_name`) VALUES
    98. ('admin', 'ADMIN'),
    99. ('u1', 'USER_P1'),
    100. ('u2', 'USER_P2');
    101. /*!40103 SET TIME_ZONE=IFNULL(@OLD_TIME_ZONE, 'system') */;
    102. /*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
    103. /*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */;
    104. /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
    105. /*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */;

    2. 配置数据源属性

    接下来,在应用程序属性文件中指定数据库连接信息,如下所示:根据您的MySQL数据库更新URL,用户名和密码。

    1. spring.jpa.hibernate.ddl-auto=update
    2. spring.datasource.url=jdbc:mysql://localhost:3306/product3?autoReconnect=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    3. spring.datasource.username=root
    4. spring.datasource.password=root
    5. #logging.level.root=WARN

    3. 声明弹簧安全性和 MySQL JDBC 驱动程序的依赖关系

    要将Spring安全API用于项目,请在pom.xml文件中声明以下依赖项:并且要将JDBC与弹簧启动和MySQL一起使用:请注意,依赖项版本已由弹簧启动初学者父项目定义。

    1. "1.0" encoding="UTF-8"?>
    2. <project xmlns="http://maven.apache.org/POM/4.0.0"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    5. <modelVersion>4.0.0modelVersion>
    6. <parent>
    7. <groupId>org.springframework.bootgroupId>
    8. <artifactId>spring-boot-starter-parentartifactId>
    9. <version>2.7.4version>
    10. <relativePath />
    11. parent>
    12. <groupId>net.codejavagroupId>
    13. <artifactId>ProductManagerJDBCAuthenticationManuallyAuthenticateCaptchaartifactId>
    14. <version>2.0version>
    15. <name>ProductManagerJDBCAuthenticationManuallyAuthenticateCaptchaname>
    16. <description>ProductManagerJDBCAuthenticationdescription>
    17. <packaging>jarpackaging>
    18. <properties>
    19. <java.version>1.8java.version>
    20. properties>
    21. <dependencies>
    22. <dependency>
    23. <groupId>org.springframework.bootgroupId>
    24. <artifactId>spring-boot-starter-data-jpaartifactId>
    25. dependency>
    26. <dependency>
    27. <groupId>org.springframework.bootgroupId>
    28. <artifactId>spring-boot-starter-thymeleafartifactId>
    29. dependency>
    30. <dependency>
    31. <groupId>org.springframework.bootgroupId>
    32. <artifactId>spring-boot-starter-webartifactId>
    33. dependency>
    34. <dependency>
    35. <groupId>org.springframework.bootgroupId>
    36. <artifactId>spring-boot-devtoolsartifactId>
    37. dependency>
    38. <dependency>
    39. <groupId>mysqlgroupId>
    40. <artifactId>mysql-connector-javaartifactId>
    41. <scope>runtimescope>
    42. dependency>
    43. <dependency>
    44. <groupId>org.springframework.bootgroupId>
    45. <artifactId>spring-boot-starter-securityartifactId>
    46. dependency>
    47. <dependency>
    48. <groupId>org.thymeleaf.extrasgroupId>
    49. <artifactId>thymeleaf-extras-springsecurity5artifactId>
    50. dependency>
    51. <dependency>
    52. <groupId>com.github.pengglegroupId>
    53. <artifactId>kaptchaartifactId>
    54. <version>2.3.2version>
    55. dependency>
    56. dependencies>
    57. <build>
    58. <plugins>
    59. <plugin>
    60. <groupId>org.springframework.bootgroupId>
    61. <artifactId>spring-boot-maven-pluginartifactId>
    62. plugin>
    63. plugins>
    64. build>
    65. project>

    4. 配置 JDBC 身份验证详细信息

    要将 Spring 安全性与基于表单的身份验证和 JDBC 结合使用,请按如下方式创建 WebSecurityConfig 类:

    1. package net.codejava;
    2. import javax.sql.DataSource;
    3. import org.springframework.beans.factory.annotation.Autowired;
    4. import org.springframework.context.annotation.Bean;
    5. import org.springframework.context.annotation.Configuration;
    6. import org.springframework.http.HttpMethod;
    7. import org.springframework.security.authentication.AuthenticationManager;
    8. import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    9. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    10. import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    11. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    12. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    13. @Configuration
    14. @EnableWebSecurity
    15. public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    16. @Autowired
    17. private DataSource dataSource;
    18. @Bean
    19. @Override
    20. public AuthenticationManager authenticationManagerBean() throws Exception {
    21. return super.authenticationManagerBean();
    22. }
    23. @Autowired
    24. public void configAuthentication(AuthenticationManagerBuilder authBuilder) throws Exception {
    25. authBuilder.jdbcAuthentication()
    26. .dataSource(dataSource)
    27. .passwordEncoder(new BCryptPasswordEncoder())
    28. .usersByUsernameQuery("select username, password, enabled from users where username=?")
    29. .authoritiesByUsernameQuery("SELECT users.username,permissions.name FROM users,roles,users_roles,permissions,roles_permissions WHERE users.username=users_roles.username AND roles.name=users_roles.role_name AND roles.name=roles_permissions.role_name AND permissions.name=roles_permissions.permission AND users.username=?");
    30. }
    31. @Override
    32. protected void configure(HttpSecurity http) throws Exception {
    33. http.authorizeRequests()
    34. .antMatchers("/edit/*", "/delete/*").hasAnyAuthority("ADMIN")
    35. .antMatchers("/common/**").permitAll()
    36. .antMatchers("/login").permitAll()
    37. .antMatchers("/verify").permitAll()
    38. .anyRequest().authenticated()
    39. .and()
    40. .formLogin().loginPage("/login")
    41. .permitAll()
    42. .and()
    43. .logout().permitAll()
    44. .and()
    45. .exceptionHandling().accessDeniedPage("/403");
    46. }
    47. }

    此安全配置类必须使用@EnableWebSecurity注释进行批注,并且是 Web 安全配置器适配器的子类。数据源对象的实例将由Spring框架创建并注入:

    1. @Autowired
    2. private DataSource dataSource;

    它将从应用程序属性文件中读取数据库连接信息。要使用JDBC配置身份验证,请编写以下方法:

    1. @Autowired
    2. public void configAuthentication(AuthenticationManagerBuilder authBuilder) throws Exception {
    3. authBuilder.jdbcAuthentication()
    4. .dataSource(dataSource)
    5. .passwordEncoder(new BCryptPasswordEncoder())
    6. .usersByUsernameQuery("select username, password, enabled from users where username=?")
    7. .authoritiesByUsernameQuery("SELECT users.username,permissions.name FROM users,roles,users_roles,permissions,roles_permissions WHERE users.username=users_roles.username AND roles.name=users_roles.role_name AND roles.name=roles_permissions.role_name AND permissions.name=roles_permissions.permission AND users.username=?");
    8. }

    如您所见,我们需要指定密码编码器(建议使用BCrypt),数据源和两个SQL语句:第一个根据用户名选择用户,第二个选择用户的角色。请注意,Spring安全性要求列名必须是用户名,密码,启用和角色。为了配置基于表单的身份验证,我们重写了 configure(HttpSecurity) 方法,如下所示:

    1. @Override
    2. protected void configure(HttpSecurity http) throws Exception {
    3. http.authorizeRequests()
    4. .antMatchers("/edit/*", "/delete/*").hasAnyAuthority("ADMIN")
    5. .anyRequest().authenticated()
    6. .and()
    7. .formLogin().permitAll()
    8. .and()
    9. .logout().permitAll()
    10. .and()
    11. .exceptionHandling().accessDeniedPage("/403");
    12. }

    在这里,我们指定所有请求都必须进行身份验证,这意味着用户必须登录才能使用该应用程序。使用Spring安全性提供的默认登录表单。要显示已登录用户的用户名,请在Thymeleaf模板文件中编写以下代码:

    1. <div sec:authorize="isAuthenticated()">
    2. Welcome <b><span sec:authentication="name">Usernamespan>b>
    3.  
    4. <i><span sec:authentication="principal.authorities">Rolesspan>i>
    5. div>

    并添加注销按钮:

    1. <form th:action="@{/logout}" method="post">
    2. <input type="submit" value="Logout" />
    3. form>

    如您所见,Spring Security将处理应用程序的登录和注销。我们不必编写重复的代码,只需指定一些配置即可。

    5.自定义登录验证过程

    1. package net.codejava;
    2. import org.springframework.beans.factory.annotation.Autowired;
    3. import org.springframework.stereotype.Controller;
    4. import org.springframework.util.StringUtils;
    5. import org.springframework.web.bind.annotation.*;
    6. import javax.servlet.http.HttpSession;
    7. import org.springframework.security.authentication.AuthenticationManager;
    8. import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    9. import org.springframework.security.core.Authentication;
    10. import org.springframework.security.core.context.SecurityContext;
    11. import org.springframework.security.core.context.SecurityContextHolder;
    12. import static org.springframework.security.web.context.HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY;
    13. @Controller
    14. public class LoginController {
    15. /**
    16. * 注入身份认证管理器
    17. */
    18. @Autowired
    19. private AuthenticationManager authenticationManager;
    20. @GetMapping("/login")
    21. public String login() {
    22. return "login";
    23. }
    24. @PostMapping(value = "/verify")
    25. public String login(@RequestParam("username") String username,
    26. @RequestParam("password") String password,
    27. @RequestParam("verifyCode") String verifyCode,
    28. HttpSession session) {
    29. System.out.println("username is:" + username);
    30. System.out.println("password is:" + password);
    31. System.out.println("verifyCode is:" + verifyCode);
    32. if (StringUtils.isEmpty(verifyCode)) {
    33. session.setAttribute("errorMsg", "The verification code cannot be empty");
    34. return "login";
    35. }
    36. if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
    37. session.setAttribute("errorMsg", "User name or password cannot be empty");
    38. return "login";
    39. }
    40. String kaptchaCode = session.getAttribute("verifyCode") + "";
    41. System.out.println("kaptchaCode is:" + kaptchaCode);
    42. if (StringUtils.isEmpty(kaptchaCode) || !verifyCode.equals(kaptchaCode)) {
    43. session.setAttribute("errorMsg", "Verification code error");
    44. return "login";
    45. }
    46. // User user = userService.login(userName, password);
    47. System.out.println(username + "==" + password + "==" + verifyCode);
    48. // 创建用户名与密码认证对象
    49. UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
    50. try {
    51. // 调用认证方法,返回认证对象
    52. Authentication authenticate = authenticationManager.authenticate(token);
    53. // 判断是否认证成功
    54. if (authenticate.isAuthenticated()) {
    55. // 设置用户认证成功,往Session中添加认证通过信息
    56. SecurityContextHolder.getContext().setAuthentication(authenticate);
    57. SecurityContext sc = SecurityContextHolder.getContext();
    58. sc.setAuthentication(authenticate);
    59. session.setAttribute(SPRING_SECURITY_CONTEXT_KEY, sc);
    60. // 重定向到登录成功页面
    61. return "redirect:/";
    62. } else {
    63. session.setAttribute("errorMsg", "Login failed");
    64. return "login";
    65. }
    66. } catch (Exception ex) {
    67. ex.printStackTrace();
    68. }
    69. return "login";
    70. }
    71. }

    kaptcha验证码

    1. package net.codejava;
    2. import com.google.code.kaptcha.impl.DefaultKaptcha;
    3. import org.springframework.beans.factory.annotation.Autowired;
    4. import org.springframework.stereotype.Controller;
    5. import org.springframework.web.bind.annotation.GetMapping;
    6. import javax.imageio.ImageIO;
    7. import javax.servlet.ServletOutputStream;
    8. import javax.servlet.http.HttpServletRequest;
    9. import javax.servlet.http.HttpServletResponse;
    10. import java.awt.image.BufferedImage;
    11. import java.io.ByteArrayOutputStream;
    12. @Controller
    13. public class KaptchaController {
    14. @Autowired
    15. private DefaultKaptcha captchaProducer;
    16. @GetMapping("/common/kaptcha")
    17. public void defaultKaptcha(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
    18. byte[] captchaOutputStream = null;
    19. ByteArrayOutputStream imgOutputStream = new ByteArrayOutputStream();
    20. try {
    21. //Produce the verification code string and save it in the session
    22. String verifyCode = captchaProducer.createText();
    23. httpServletRequest.getSession().setAttribute("verifyCode", verifyCode);
    24. BufferedImage challenge = captchaProducer.createImage(verifyCode);
    25. ImageIO.write(challenge, "jpg", imgOutputStream);
    26. } catch (IllegalArgumentException e) {
    27. httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
    28. return;
    29. }
    30. captchaOutputStream = imgOutputStream.toByteArray();
    31. httpServletResponse.setHeader("Cache-Control", "no-store");
    32. httpServletResponse.setHeader("Pragma", "no-cache");
    33. httpServletResponse.setDateHeader("Expires", 0);
    34. httpServletResponse.setContentType("image/jpeg");
    35. ServletOutputStream responseOutputStream = httpServletResponse.getOutputStream();
    36. responseOutputStream.write(captchaOutputStream);
    37. responseOutputStream.flush();
    38. responseOutputStream.close();
    39. }
    40. }
    1. package net.codejava;
    2. import com.google.code.kaptcha.impl.DefaultKaptcha;
    3. import com.google.code.kaptcha.util.Config;
    4. import org.springframework.context.annotation.Bean;
    5. import org.springframework.stereotype.Component;
    6. import java.util.Properties;
    7. @Component
    8. public class KaptchaConfig {
    9. @Bean
    10. public DefaultKaptcha getDefaultKaptcha() {
    11. DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
    12. Properties properties = new Properties();
    13. properties.put("kaptcha.border", "no");
    14. properties.put("kaptcha.textproducer.font.color", "black");
    15. properties.put("kaptcha.image.width", "150");
    16. properties.put("kaptcha.image.height", "40");
    17. properties.put("kaptcha.textproducer.font.size", "30");
    18. properties.put("kaptcha.session.key", "verifyCode");
    19. properties.put("kaptcha.textproducer.char.space", "5");
    20. Config config = new Config(properties);
    21. defaultKaptcha.setConfig(config);
    22. return defaultKaptcha;
    23. }
    24. }

    6.登录页面

    1. html>
    2. <html xmlns:th="http://www.thymeleaf.org">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
    6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    7. <title>Bootstrap 5 Sign In Form with Image Exampletitle>
    8. <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
    9. integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
    10. <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
    11. integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
    12. crossorigin="anonymous">script>
    13. <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.css">
    14. head>
    15. <body>
    16. <form th:action="@{/verify}" method="post">
    17. <div class="container-fluid vh-100" style="margin-top:50px">
    18. <div class="" style="margin-top:50px">
    19. <div class="rounded d-flex justify-content-center">
    20. <div class=" col-md-4 col-sm-12 shadow-lg p-5 bg-light">
    21. <div class="text-center">
    22. <h3 class="text-primary">请登录h3>
    23. div>
    24. <div class="p-4">
    25. <div class="input-group mb-3">
    26. <span class="input-group-text bg-secondary"><i
    27. class="bi bi-person-fill text-white">i>span>
    28. <input id="username" type="text" name="username" required class="form-control" placeholder="用户名">
    29. div>
    30. <div class="input-group mb-3">
    31. <span class="input-group-text bg-secondary"><i
    32. class="bi bi-key-fill text-white">i>span>
    33. <input id="password" type="password" name="password" required class="form-control" placeholder="密码">
    34. div>
    35. <div class="input-group mb-3">
    36. <span class="input-group-text bg-secondary"><i
    37. class="bi bi-lock-fill text-white">i>span>
    38. <input type="text" name="verifyCode" class="form-control" placeholder="输入下图中的校验码">
    39. div>
    40. <div class="input-group mb-3">
    41. <span class="input-group-text bg-secondary"><i
    42. class="bi bi-image-fill text-white">i>span>
    43. <img alt="Click the picture to refresh!" class="pointer" th:src="@{/common/kaptcha}"
    44. onclick="this.src = '/common/kaptcha?d=' + new Date() * 1">
    45. div>
    46. <div class="col-12">
    47. <button type="submit" class="btn btn-primary px-4 float-end mt-4">登录button>
    48. div>
    49. div>
    50. div>
    51. div>
    52. div>
    53. div>
    54. body>
    55. html>

    5. 测试登录和注销

    启动Spring Boot应用程序并访问 http://localhost:8080 在Web浏览器中,您将看到自定义的登录页面出现:

     现在输入正确的用户名admin和密码admin,您将看到主页如下:

     

    并注意欢迎消息后跟用户名。用户现在已通过身份验证以使用该应用程序。单击“注销”按钮,您将看到自定义的登录页面出现,这意味着我们已成功实现登录并注销到我们的Spring Boot应用程序。

    结论:

    到目前为止,您已经学会了使用基于表单的身份验证和数据库内凭据来保护Spring Boot应用程序。您会看到 Spring 安全性使实现登录和注销功能变得非常容易,并且非常方便。为方便起见,您可以下载下面的示例项目。

    下载源码:https://github.com/allwaysoft/ProductManagerJDBCAuthenticationManuallyAuthenticateCaptcha/

  • 相关阅读:
    Python魔术方法
    扩展:文件属性chattr,隐藏权限主要用来防止root误删除
    判断input标签的type类型为checkbox是否被选中
    Linux目录操作
    ChatGLM3 本地部署的解决方案
    理“ Druid 元数据”之乱
    springWeb
    String类常用方法
    数据可视化项目(二)
    Cookie 能跨域吗?如何设置?
  • 原文地址:https://blog.csdn.net/allway2/article/details/127696327