最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot?Security使用MySQL實現(xiàn)驗證與權(quán)限管理

 更新時間:2022年11月07日 17:05:07   作者:allway2  
安全管理是軟件系統(tǒng)必不可少的的功能。根據(jù)經(jīng)典的“墨菲定律”——凡是可能,總會發(fā)生。如果系統(tǒng)存在安全隱患,最終必然會出現(xiàn)問題,這篇文章主要介紹了SpringBoot安全管理Spring?Security基本配置

在本教程中,我將指導您如何編寫代碼,以使用具有基于表單的身份驗證的Spring安全API來保護Spring Boot應用程序中的網(wǎng)頁。用戶詳細信息存儲在MySQL數(shù)據(jù)庫中,并使用春季JDBC連接到數(shù)據(jù)庫。我們將從本教程中的 ProductManager 項目開始,向現(xiàn)有的彈簧啟動項目添加登錄和注銷功能。

1. 創(chuàng)建用戶表和虛擬憑據(jù)

憑據(jù)應存儲在數(shù)據(jù)庫中,因此讓我們創(chuàng)建新表,表間關系ER圖如下:

-- --------------------------------------------------------
-- 主機:                           127.0.0.1
-- 服務器版本:                        8.0.22 - MySQL Community Server - GPL
-- 服務器操作系統(tǒng):                      Win64
-- HeidiSQL 版本:                  12.1.0.6537
-- --------------------------------------------------------
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!50503 SET NAMES utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!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 */;
-- 導出 product3 的數(shù)據(jù)庫結(jié)構(gòu)
CREATE DATABASE IF NOT EXISTS `product3` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;
USE `product3`;
-- 導出  表 product3.permission 結(jié)構(gòu)
CREATE TABLE IF NOT EXISTS `permission` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
  `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `uri` varchar(8192) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `method` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 正在導出表  product3.permission 的數(shù)據(jù):~5 rows (大約)
INSERT INTO `permission` (`id`, `name`, `description`, `uri`, `method`) VALUES
	(3, 'product_create', '增加產(chǎn)品', '/new', 'GET'),
	(4, 'product_delete', '刪除產(chǎn)品', '/delete/*', 'GET'),
	(5, 'product_save', '保存產(chǎn)品', '/save', 'POST'),
	(9, 'product_read', '讀取產(chǎn)品', '/', 'GET'),
	(10, 'product_edit', '編輯產(chǎn)品', '/edit/*', 'GET');
-- 導出  表 product3.product 結(jié)構(gòu)
CREATE TABLE IF NOT EXISTS `product` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `brand` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `madein` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `price` float NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 正在導出表  product3.product 的數(shù)據(jù):~2 rows (大約)
INSERT INTO `product` (`id`, `brand`, `madein`, `name`, `price`) VALUES
	(6, '6', '6', '6', 6),
	(7, '7', '7', '7', 7);
-- 導出  表 product3.role 結(jié)構(gòu)
CREATE TABLE IF NOT EXISTS `role` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
  `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 正在導出表  product3.role 的數(shù)據(jù):~3 rows (大約)
INSERT INTO `role` (`id`, `name`, `description`) VALUES
	(1, 'ADMIN', 'Administrator role'),
	(2, 'USER_P1', 'Perfil 1'),
	(3, 'USER_P2', 'Perfil 2');
-- 導出  表 product3.role_permission 結(jié)構(gòu)
CREATE TABLE IF NOT EXISTS `role_permission` (
  `id` int NOT NULL AUTO_INCREMENT,
  `role_id` int NOT NULL DEFAULT '0',
  `permission_id` int NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `role_id_permission_id` (`role_id`,`permission_id`),
  KEY `FK_role_permission_permission` (`permission_id`),
  CONSTRAINT `FK_role_permission_permission` FOREIGN KEY (`permission_id`) REFERENCES `permission` (`id`),
  CONSTRAINT `FK_role_permission_role` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 正在導出表  product3.role_permission 的數(shù)據(jù):~10 rows (大約)
INSERT INTO `role_permission` (`id`, `role_id`, `permission_id`) VALUES
	(1, 1, 3),
	(2, 1, 4),
	(3, 1, 5),
	(4, 1, 9),
	(5, 1, 10),
	(8, 2, 5),
	(6, 2, 9),
	(7, 2, 10),
	(10, 3, 4),
	(9, 3, 9);
-- 導出  表 product3.urls 結(jié)構(gòu)
CREATE TABLE IF NOT EXISTS `urls` (
  `name` varchar(500) COLLATE utf8mb4_unicode_ci NOT NULL,
  `description` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 正在導出表  product3.urls 的數(shù)據(jù):~0 rows (大約)
-- 導出  表 product3.user 結(jié)構(gòu)
CREATE TABLE IF NOT EXISTS `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
  `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `name` varchar(65) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
  `enabled` int DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 正在導出表  product3.user 的數(shù)據(jù):~3 rows (大約)
INSERT INTO `user` (`id`, `username`, `email`, `name`, `password`, `enabled`) VALUES
	(1, 'admin', 'admin@example.com', 'Administrator', '$2a$10$2/LSmp3YoEOT97KzgrYODen7I88ErBovM2Qehw9DL1dW9DZ7DZSAm', 1),
	(2, 'u1', 'u1@example.com', 'User P1', '$2a$10$2/LSmp3YoEOT97KzgrYODen7I88ErBovM2Qehw9DL1dW9DZ7DZSAm', 1),
	(3, 'u2', 'u2@example.com', 'User P2', '$2a$10$2/LSmp3YoEOT97KzgrYODen7I88ErBovM2Qehw9DL1dW9DZ7DZSAm', 1);
-- 導出  表 product3.user_role 結(jié)構(gòu)
CREATE TABLE IF NOT EXISTS `user_role` (
  `id` int NOT NULL AUTO_INCREMENT,
  `user_id` int NOT NULL DEFAULT '0',
  `role_id` int NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `user_id_role_id` (`user_id`,`role_id`),
  KEY `FK_user_role_role` (`role_id`),
  CONSTRAINT `FK_user_role_role` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`),
  CONSTRAINT `FK_user_role_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 正在導出表  product3.user_role 的數(shù)據(jù):~3 rows (大約)
INSERT INTO `user_role` (`id`, `user_id`, `role_id`) VALUES
	(1, 1, 1),
	(2, 2, 2),
	(3, 3, 3);
/*!40103 SET TIME_ZONE=IFNULL(@OLD_TIME_ZONE, 'system') */;
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */;

2. 配置數(shù)據(jù)源屬性

接下來,在應用程序?qū)傩晕募兄付〝?shù)據(jù)庫連接信息,如下所示:根據(jù)您的MySQL數(shù)據(jù)庫更新URL,用戶名和密碼。

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

3. 聲明彈簧安全性和MySQL JDBC驅(qū)動程序的依賴關系

要將Spring安全API用于項目,請在pom.xml文件中聲明以下依賴項:并且要將JDBC與彈簧啟動和MySQL一起使用:請注意,依賴項版本已由彈簧啟動初學者父項目定義。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.4</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>net.codejava</groupId>
    <artifactId>ProductManagerJDBCAuthenticationManuallyAuthenticateCaptchaAccess</artifactId>
    <version>2.0</version>
    <name>ProductManagerJDBCAuthenticationManuallyAuthenticateCaptchaAccess</name>
    <description>ProductManagerJDBCAuthentication</description>
    <packaging>jar</packaging>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
        </dependency>
        <dependency>
            <groupId>com.github.penggle</groupId>
            <artifactId>kaptcha</artifactId>
            <version>2.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

4. 配置 JDBC 身份驗證詳細信息

要將 Spring 安全性與基于表單的身份驗證和 JDBC 結(jié)合使用,請按如下方式創(chuàng)建WebSecurityConfig類:

package com.example;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private DataSource dataSource;
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
    @Autowired
    public void configAuthentication(AuthenticationManagerBuilder authBuilder) throws Exception {
        authBuilder.jdbcAuthentication()
                .dataSource(dataSource)
                .passwordEncoder(new BCryptPasswordEncoder())
                .usersByUsernameQuery("select username, password, enabled from user where username=?")
                .authoritiesByUsernameQuery("SELECT user.username,permission.name FROM user,role,user_role,permission,role_permission WHERE user.id=user_role.user_id AND role.id=user_role.role_id AND role.id=role_permission.role_id AND permission.id=role_permission.permission_id  AND user.username=?");
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/common/**").permitAll()
                .antMatchers("/login").permitAll()
                .antMatchers("/logout").permitAll()
                .antMatchers("/verify").permitAll()
                .anyRequest()
                .access("@rbacService.hasPermission(request , authentication)")
                .and()
                .formLogin().loginPage("/login")
                .permitAll()
                .and()
                .logout().permitAll()
                .and()
                .exceptionHandling().accessDeniedPage("/403");
    }
}

此安全配置類必須使用@EnableWebSecurity注釋進行批注,并且是Web 安全配置器適配器的子類。數(shù)據(jù)源對象的實例將由Spring框架創(chuàng)建并注入:

    @Autowired
    private DataSource dataSource;

它將從應用程序?qū)傩晕募凶x取數(shù)據(jù)庫連接信息。要使用JDBC配置身份驗證,請編寫以下方法:

    @Autowired
    public void configAuthentication(AuthenticationManagerBuilder authBuilder) throws Exception {
        authBuilder.jdbcAuthentication()
                .dataSource(dataSource)
                .passwordEncoder(new BCryptPasswordEncoder())
                .usersByUsernameQuery("select username, password, enabled from users where username=?")
                .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=?");
    }

如您所見,我們需要指定密碼編碼器(建議使用BCrypt),數(shù)據(jù)源和兩個SQL語句:第一個根據(jù)用戶名選擇用戶,第二個選擇用戶的角色。請注意,Spring安全性要求列名必須是用戶名,密碼,啟用和角色。為了配置基于表單的身份驗證,我們重寫了 configure(HttpSecurity)方法,如下所示:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/edit/*", "/delete/*").hasAnyAuthority("ADMIN")
                .anyRequest().authenticated()
                .and()
                .formLogin().permitAll()
                .and()
                .logout().permitAll()
                .and()
                .exceptionHandling().accessDeniedPage("/403");
    }

在這里,我們指定所有請求都必須進行身份驗證,這意味著用戶必須登錄才能使用該應用程序。使用Spring安全性提供的默認登錄表單。要顯示已登錄用戶的用戶名,請在Thymeleaf模板文件中編寫以下代碼:

<div sec:authorize="isAuthenticated()">
                Welcome <b><span sec:authentication="name">Username</span></b>
                &nbsp;
                <i><span sec:authentication="principal.authorities">Roles</span></i>
            </div>

并添加注銷按鈕:

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

如您所見,Spring Security將處理應用程序的登錄和注銷。我們不必編寫重復的代碼,只需指定一些配置即可。

5. 自定義登錄驗證過程

package com.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpSession;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import static org.springframework.security.web.context.HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY;
@Controller
public class LoginController {
    /**
     * 注入身份認證管理器
     */
    @Autowired
    private AuthenticationManager authenticationManager;
    @GetMapping("/login")
    public String login() {
        return "login";
    }
    @PostMapping(value = "/verify")
    public String login(@RequestParam("username") String username,
            @RequestParam("password") String password,
            @RequestParam("verifyCode") String verifyCode,
            HttpSession session) {
        System.out.println("username is:" + username);
        System.out.println("password is:" + password);
        System.out.println("verifyCode is:" + verifyCode);
        if (StringUtils.isEmpty(verifyCode)) {
            session.setAttribute("errorMsg", "The verification code cannot be empty");
            return "login";
        }
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
            session.setAttribute("errorMsg", "User name or password cannot be empty");
            return "login";
        }
        String kaptchaCode = session.getAttribute("verifyCode") + "";
        System.out.println("kaptchaCode is:" + kaptchaCode);
        if (StringUtils.isEmpty(kaptchaCode) || !verifyCode.equals(kaptchaCode)) {
            session.setAttribute("errorMsg", "Verification code error");
            return "login";
        }
//        User user = userService.login(userName, password);
        System.out.println(username + "==" + password + "==" + verifyCode);
        // 創(chuàng)建用戶名與密碼認證對象
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
        try {
            // 調(diào)用認證方法,返回認證對象
            Authentication authenticate = authenticationManager.authenticate(token);
            // 判斷是否認證成功
            if (authenticate.isAuthenticated()) {
                // 設置用戶認證成功,往Session中添加認證通過信息
                SecurityContextHolder.getContext().setAuthentication(authenticate);
                SecurityContext sc = SecurityContextHolder.getContext();
                sc.setAuthentication(authenticate);
                session.setAttribute(SPRING_SECURITY_CONTEXT_KEY, sc);
                // 重定向到登錄成功頁面
                return "redirect:/";
            } else {
                session.setAttribute("errorMsg", "Login failed");
                return "login";
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return "login";
    }
}

kaptcha驗證碼

package net.codejava;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
@Controller
public class KaptchaController {
    @Autowired
    private DefaultKaptcha captchaProducer;
    @GetMapping("/common/kaptcha")
    public void defaultKaptcha(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        byte[] captchaOutputStream = null;
        ByteArrayOutputStream imgOutputStream = new ByteArrayOutputStream();
        try {
            //Produce the verification code string and save it in the session
            String verifyCode = captchaProducer.createText();
            httpServletRequest.getSession().setAttribute("verifyCode", verifyCode);
            BufferedImage challenge = captchaProducer.createImage(verifyCode);
            ImageIO.write(challenge, "jpg", imgOutputStream);
        } catch (IllegalArgumentException e) {
            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
        captchaOutputStream = imgOutputStream.toByteArray();
        httpServletResponse.setHeader("Cache-Control", "no-store");
        httpServletResponse.setHeader("Pragma", "no-cache");
        httpServletResponse.setDateHeader("Expires", 0);
        httpServletResponse.setContentType("image/jpeg");
        ServletOutputStream responseOutputStream = httpServletResponse.getOutputStream();
        responseOutputStream.write(captchaOutputStream);
        responseOutputStream.flush();
        responseOutputStream.close();
    }
}
package net.codejava;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import java.util.Properties;
@Component
public class KaptchaConfig {
    @Bean
    public DefaultKaptcha getDefaultKaptcha() {
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        Properties properties = new Properties();
        properties.put("kaptcha.border", "no");
        properties.put("kaptcha.textproducer.font.color", "black");
        properties.put("kaptcha.image.width", "150");
        properties.put("kaptcha.image.height", "40");
        properties.put("kaptcha.textproducer.font.size", "30");
        properties.put("kaptcha.session.key", "verifyCode");
        properties.put("kaptcha.textproducer.char.space", "5");
        Config config = new Config(properties);
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }
}

6. 登錄頁面

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Bootstrap 5 Sign In Form with Image Example</title>
        <link  rel="external nofollow"  rel="stylesheet"
              integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
                integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
        crossorigin="anonymous"></script>
        <link rel="stylesheet"  rel="external nofollow" >
    </head>
    <body>
        <form th:action="@{/verify}" method="post">
            <div class="container-fluid vh-100" style="margin-top:50px">
                <div class="" style="margin-top:50px">
                    <div class="rounded d-flex justify-content-center">
                        <div class=" col-md-4 col-sm-12 shadow-lg p-5 bg-light">
                            <div class="text-center">
                                <h3 class="text-primary">請登錄</h3>
                            </div>
                            <div class="p-4">
                                <div class="input-group mb-3">
                                    <span class="input-group-text bg-secondary"><i
                                            class="bi bi-person-fill text-white"></i></span>
                                    <input id="username" type="text" name="username" required class="form-control" placeholder="用戶名">
                                </div>
                                <div class="input-group mb-3">
                                    <span class="input-group-text bg-secondary"><i
                                            class="bi bi-key-fill text-white"></i></span>
                                    <input  id="password" type="password" name="password" required class="form-control" placeholder="密碼">
                                </div>
                                <div class="input-group mb-3">
                                    <span class="input-group-text bg-secondary"><i
                                            class="bi bi-lock-fill text-white"></i></span>
                                    <input type="text" name="verifyCode"  class="form-control" placeholder="輸入下圖中的校驗碼">
                                </div>
                                <div class="input-group mb-3">
                                    <span class="input-group-text bg-secondary"><i
                                            class="bi bi-image-fill text-white"></i></span>
                                    <img alt="Click the picture to refresh!" class="pointer" th:src="@{/common/kaptcha}"
                                         onclick="this.src = '/common/kaptcha?d=' + new Date() * 1">
                                </div>
                                <div class="col-12">
                                    <button type="submit" class="btn btn-primary px-4 float-end mt-4">登錄</button>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
    </body>
</html>

7. 測試登錄和注銷

啟動Spring Boot應用程序并訪問 http://localhost:8080 在Web瀏覽器中,您將看到自定義的登錄頁面出現(xiàn):

現(xiàn)在輸入正確的用戶名admin和密碼admin,您將看到主頁如下:

并注意歡迎消息后跟用戶名。用戶現(xiàn)在已通過身份驗證以使用該應用程序。單擊“注銷”按鈕,您將看到自定義的登錄頁面出現(xiàn),這意味著我們已成功實現(xiàn)登錄并注銷到我們的Spring Boot應用程序。

自定義從數(shù)據(jù)庫中獲取動態(tài)權(quán)限驗證

package com.example;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Data;
@Data
@Entity
public class Permission {
    @Id
    private Long id;
    private String name;
    private String description;
    private String uri;
    private String method;
}
package com.example;
import org.springframework.data.jpa.repository.JpaRepository;
public interface PermissionRepository extends JpaRepository<Permission, Long> {
    public Permission findByName(String name);
}
package com.example;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.core.Authentication;
/**
 * RBAC模型實現(xiàn)Security,即通過角色對用戶進行分組,在對每個角色進行權(quán)限授權(quán)就, 進而簡化用戶權(quán)限分配以及管理。 需要的表: user:
 * 用戶信息表 保存有的用戶id,用戶名、密碼、賬號、狀態(tài)、salt加鹽 role:角色表 user_role:用戶角色關聯(lián)表 permission: 權(quán)限表
 * 保存的有權(quán)限相關信息 role_permission: 角色與權(quán)限管理表
 */
public interface RbacService {
    //用戶判斷當前請求是否有操作權(quán)限
    boolean hasPermission(HttpServletRequest request, Authentication authentication);
}
package com.example;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
@Component("rbacService")
public class RbacServiceImpl implements RbacService {
    @Autowired
    private PermissionRepository permissionRepository;
    private AntPathMatcher antPathMatcher = new AntPathMatcher();
    @Override
    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
        //獲取用戶認證信息
        System.out.println(authentication.getAuthorities());
        Object principal = authentication.getPrincipal();
        System.out.println(principal.getClass());
        //判斷數(shù)據(jù)是否為空 以及類型是否正確
        if (null != principal && principal instanceof User) {
            String username = ((User) principal).getUsername();
            System.out.println(username);
        }
        String requestURI = request.getRequestURI();
        System.out.println(requestURI);
        String method = request.getMethod();
        System.out.println(method);
        Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
        boolean hasPermission = false;
        for (GrantedAuthority authority : authorities) {
            String authorityname = authority.getAuthority();
            System.out.println(authority.getAuthority());
            Permission permission = permissionRepository.findByName(authorityname);
            System.out.println(permissionRepository.findByName(authorityname));
            if (null != permission && permission.getMethod().equals(request.getMethod()) && antPathMatcher.match(permission.getUri(), request.getRequestURI())) {
                hasPermission = true;
                break;
            }
        }
        System.out.println(hasPermission);
        return hasPermission;
    }
}

thymeleaf視圖文件中,根據(jù)權(quán)限顯示連接菜單

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
    <head>
        <meta charset="ISO-8859-1">
        <title>Product Manager</title>
    </head>
    <body>
        <div align="center">
            <div sec:authorize="isAuthenticated()">
                Welcome <b><span sec:authentication="name">Username</span></b>
                &nbsp;
                <i><span sec:authentication="principal.authorities">Roles</span></i>
            </div>
            <form th:action="@{/logout}" method="post">
                <input type="submit" value="Logout" />
            </form>
            <h1>Product Manager</h1>
            <div sec:authorize="hasAnyAuthority('product_create')">
                <a href="/new" rel="external nofollow" >Create New Product</a>
            </div>
            <br/><br/>
            <table border="1" cellpadding="10">
                <thead>
                    <tr>
                        <th>Product ID</th>
                        <th>Name</th>
                        <th>Brand</th>
                        <th>Made In</th>
                        <th>Price</th>
                        <th sec:authorize="hasAnyAuthority('product_edit', 'product_delete')">Actions</th>
                    </tr>
                </thead>
                <tbody>
                    <tr th:each="product : ${listProducts}">
                        <td th:text="${product.id}">Product ID</td>
                        <td th:text="${product.name}">Name</td>
                        <td th:text="${product.brand}">Brand</td>
                        <td th:text="${product.madein}">Made in</td>
                        <td th:text="${product.price}">Price</td>
                        <td>
                            <a sec:authorize="hasAuthority('product_edit')" th:href="@{'/edit/' + ${product.id}}" rel="external nofollow" >Edit</a>
                            &nbsp;&nbsp;&nbsp;&nbsp;
                            <a sec:authorize="hasAuthority('product_delete')" th:href="@{'/delete/' + ${product.id}}" rel="external nofollow" >Delete</a>
                        </td>
                    </tr>
                </tbody>
            </table>
        </div>
    </body>
</html>

結(jié)論

到目前為止,您已經(jīng)學會了使用基于表單的身份驗證和數(shù)據(jù)庫內(nèi)憑據(jù)來保護Spring Boot應用程序。您會看到 Spring 安全性使實現(xiàn)登錄和注銷功能變得非常容易,并且非常方便。為方便起見,您可以下載下面的示例項目。

下載源碼:傳送門

到此這篇關于SpringBoot Security使用MySQL實現(xiàn)驗證與權(quán)限管理的文章就介紹到這了,更多相關SpringBoot Security內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java日期時間處理問題(從Date、Calendar到SimpleDateFormat)

    Java日期時間處理問題(從Date、Calendar到SimpleDateFormat)

    這篇文章主要介紹了Java日期時間處理深度解析(從Date、Calendar到SimpleDateFormat),我們詳細討論了Java中的日期和時間處理,包括Date、Calendar和SimpleDateFormat類的使用,以及Java?8引入的新的日期時間API的優(yōu)勢,需要的朋友可以參考下
    2024-08-08
  • 在 Spring Boot 中集成 MinIO 對象存儲

    在 Spring Boot 中集成 MinIO 對象存儲

    MinIO 是一個開源的對象存儲服務器,專注于高性能、分布式和兼容S3 API的存儲解決方案,本文將介紹如何在 Spring Boot 應用程序中集成 MinIO,以便您可以輕松地將對象存儲集成到您的應用中,需要的朋友可以參考下
    2023-09-09
  • 如何基于Spring使用工廠模式實現(xiàn)程序解耦

    如何基于Spring使用工廠模式實現(xiàn)程序解耦

    這篇文章主要介紹了如何基于Spring使用工廠模式實現(xiàn)程序解耦,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-12-12
  • SpringBoot?RESTful?應用中的異常處理梳理小結(jié)

    SpringBoot?RESTful?應用中的異常處理梳理小結(jié)

    這篇文章主要介紹了SpringBoot?RESTful?應用中的異常處理梳理小結(jié),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-05-05
  • Java集合Set、List、Map的遍歷方法

    Java集合Set、List、Map的遍歷方法

    這篇文章主要介紹了Java集合Set、List、Map的遍歷方法,是非常實用的遍歷技巧,需要的朋友可以參考下
    2014-09-09
  • Java中Mybatis,SpringMVC,Spring的介紹及聯(lián)系

    Java中Mybatis,SpringMVC,Spring的介紹及聯(lián)系

    這篇文章主要為大家詳細介紹了Java中Mybatis,SpringMVC,Spring的介紹及聯(lián)系,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • Java selenium上傳文件的實現(xiàn)

    Java selenium上傳文件的實現(xiàn)

    本文主要介紹了Java selenium上傳文件的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-04-04
  • java實現(xiàn)題目以及選項亂序的方法實例

    java實現(xiàn)題目以及選項亂序的方法實例

    這篇文章主要給大家介紹了關于java實現(xiàn)題目以及選項亂序的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-03-03
  • MyBatis的mapper.xml文件中入?yún)⒑头祷刂档膶崿F(xiàn)

    MyBatis的mapper.xml文件中入?yún)⒑头祷刂档膶崿F(xiàn)

    這篇文章主要介紹了MyBatis的mapper.xml文件中入?yún)⒑头祷刂档膶崿F(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • 關于SpringCloud灰度發(fā)布的實現(xiàn)

    關于SpringCloud灰度發(fā)布的實現(xiàn)

    這篇文章主要介紹了關于SpringCloud灰度發(fā)布的實現(xiàn),灰度發(fā)布又稱金絲雀發(fā)布,是在系統(tǒng)升級的時候能夠平滑過渡的一種發(fā)布方式,灰度發(fā)布可以保證整體系統(tǒng)的穩(wěn)定,在初始灰度的時候就可以發(fā)現(xiàn)、調(diào)整問題,以保證其影響度,需要的朋友可以參考下
    2023-08-08

最新評論

措美县| 大姚县| 吴桥县| 承德县| 古丈县| 桓台县| 凤庆县| 安庆市| 建始县| 昂仁县| 肇源县| 嫩江县| 西丰县| 射阳县| 平武县| 武城县| 禄丰县| 鄱阳县| 庆元县| 平阳县| 五台县| 施甸县| 莲花县| 垣曲县| 云安县| 宕昌县| 合作市| 宁城县| 临沂市| 河津市| 寿光市| 读书| 扶余县| 剑河县| 临洮县| 客服| 元氏县| 绥芬河市| 琼海市| 陕西省| 颍上县|