Spring Security 认证授权安全框架

news2024/11/22 7:13:41

Spring Security概述

1.什么是Spring Security?

Spring Security是一个Java框架,用于保护应用程序的安全性。它提供了一套全面的安全解决方案,包括身份验证、授权、防止攻击等功能。Spring Security基于过滤器链的概念,可以轻松地集成到任何基于Spring的应用程序中。它支持多种身份验证选项和授权策略,开发人员可以根据需要选择适合的方式。此外,Spring Security还提供了一些附加功能,如集成第三方身份验证提供商和单点登录,以及会话管理和密码编码等。总之,Spring Security是一个强大且易于使用的框架,可以帮助开发人员提高应用程序的安全性和可靠性。

什么是授权

这个根据用户的权限来控制用户使用资源的过程就是授权。

为什么要授权

认证是为了保护用户身份的合法性,授权则是为了更细的粒度的对隐私数据经行划分,授权是在认证通过后发生的,控制不同的用户能够访问不同的资源;

授权:授权是用户认证通过根据用户的权限来控制用户访问资源的过程,拥有资源的访问权限则正常访问,没有权限则拒绝访问;

Spring Security入门体验

一.快速搭建Spring Security安全框架项目;

1.1--创建一个SpringBoot项目;

1.2--修改SpringBoot的版本号,并修改jdk版本号;

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>SpringSecurity001</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>SpringSecurity001</name>
    <description>SpringSecurity001</description>
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.6.13</spring-boot.version>
        <!--SpringBoot版本号   这里使用的JDK版本为8-->
    </properties>
    <dependencies>
        <!--引入Spring Security安全框架依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--添加lombok依赖  实体类的get set方法生成-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!--测试依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>com.aaa.SpringSecurity001Application</mainClass>
                    <skip>true</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

1.3--引入SPringleSecurity依赖;

<!--引入Spring Security安全框架依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

1.4--创建一个HelloController,Controller层定义一个资源;

1.5--启动项目并访问资源路径;

访问路径:http://localhost:8080/hello

注:我们发现使用了security后在访问我们自己的接口,security会拦截并跳转到认证页面,认证后才可以访问。默认认证的账号uer密码在控制台;

二.创建Spring Security自定义账户和密码;

我们刚才使用的是security自带的账户和密码,我们自己也可以自定义账户和密码;

2.1--在application.properties配置文件中定义一个账户和密码;

自定义账户和密码文件如下:

#创建Spring Security自定义账户和密码

#账户
spring.security.user.name=admin
#密码
spring.security.user.password=123456
server.port=8080

注:配置完自定义文件和密码,重启运行,这是控制台中没有密码(控制台不会生成密码);

注:这种方式只能定义一个账户和密码,无法定义多个账户和密码;

三.自定义多个账户和密码

在配置文件中,只能定义一个账户和密码。我们可以定义一个配置类,完成多个账号和密码的定义;

1.创建Config层 MysecurityConfig;

配置类内容

package com.aaa.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication() //基于内存创建的账户和密码  未来可以用来连接数据库
                //账户
                .withUser("zhangsan")
                //密码
                .password("123456")
                //用户具备的角色
                .roles("admin")
                .and() //连接符
                .withUser("lisi")
                .password("012345")
                .roles("test")
                .and()
                .withUser("wangwu")
                .password("567890")
                .roles("group");

    }
}

注:如果使用了配置类,那么之前在配置文件中定义的账户和密码不在生效;

控制台错误提示:需要给它指定的加密器;

解决方式:添加加密器

//可以把该方法返回的对象交于Spring容器管理
    @Bean
    public PasswordEncoder passwordEncoder(){
        return  new BCryptPasswordEncoder();
    }
package com.aaa.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {

    //可以把该方法返回的对象交于Spring容器管理
    @Bean
    public PasswordEncoder passwordEncoder(){
        return  new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication() //基于内存创建的账户和密码  未来可以用来连接数据库
                //账户
                .withUser("zhangsan")
                //密码
                .password(passwordEncoder().encode("123456"))
                //用户具备的角色
                .roles("admin")
                .and() //连接符
                .withUser("lisi")
                .password(passwordEncoder().encode("012345"))
                .roles("test")
                .and()
                .withUser("wangwu")
                .password(passwordEncoder().encode("567890"))
                .roles("group");

    }
}

注:把明文密码通过加密器经行加密;

再次访问资源

四.密码加密器

密码加密器,可以把把明文转换为密文 encode

同时也可以匹配密码 matches;

package com.aaa.Test;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

public class test {
    public static void main(String[] args) {
        //创建加密器对象
        PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        //使用加密器
        String encode = passwordEncoder.encode("123456");
        System.out.println(encode);
        //匹配密码  第一个参数是客户输得密码   第二个参数是加密器密文
        //把客户输得密码和加密过的密码经行比对是否一致,一致返回true,不一致返回flase;
        boolean matches = passwordEncoder.matches("123456", encode);
        //结果为true
        System.out.println(matches);   
    }
}

 

问题:对称加密和非对称加密

答:对称加密:加密和解密使用的密钥是同一个; --这种加密的方式可以破解

      非对称加密: 加密和解密使用的密钥不是同一个;--这种加密的方式无法破解

五.获取当前用户的信息

获取登录成功者的信息

package com.aaa.Controller;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello(){
        return "hello资源·······";
    }

    @GetMapping("/info")
    public Authentication info(){
        //把当前信息保存到SecurityContext类中;
        SecurityContext securityContext = SecurityContextHolder.getContext();
        //把当前用户封装到Authentication类中  账户  密码 权限 角色等信息
        Authentication authentication = securityContext.getAuthentication();
        return authentication;
    }
}

Security框架会把当前用户信息封装到Authentication中,并把该类对象存放到SecurityContext中;

访问资源路径http://localhost:8080/info

六.修改它的登录页面

默认security提供了一个登录页面,如果不想使用它提供的页面,我们可以指定我们自己的登录页面;

1.自己在static静态资源文件下创建一个登录页面;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录页</title>
  <style>
    body {
      background-color: #222;
      font-family: Arial, sans-serif;
      color: #fff;
      display: flex;
      align-items: center;
      justify-content: center;
      height: 100vh;
    }

    .login-container {
      background-color: #333;
      padding: 40px;
      border-radius: 10px;
      box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
    }

    h1 {
      text-align: center;
    }

    .form-group {
      margin-bottom: 20px;
    }

    .form-group label {
      display: block;
      margin-bottom: 5px;
    }

    .form-group input[type="text"],
    .form-group input[type="password"] {
      width: 100%;
      padding: 10px;
      border-radius: 5px;
      border: none;
      background-color: #555;
      color: #fff;
    }

    .form-group input[type="submit"] {
      width: 100%;
      padding: 10px;
      border-radius: 5px;
      border: none;
      background-color: #007bff;
      color: #fff;
      cursor: pointer;
      transition: background-color 0.3s ease;
    }

    .form-group input[type="submit"]:hover {
      background-color: #0056b3;
    }
  </style>
</head>
<body>
<div class="login-container">
  <h1>Welcome to Cool Login Page</h1>
  <form action="login" method="post">
    <div class="form-group">
      <label for="username">Username:</label>
      <!--账户-->
      <input type="text" id="username" name="username" required>
    </div>
    <div class="form-group">
      <label for="password">Password:</label>
      <!--密码-->
      <input type="password" id="password" name="password" required>
    </div>
    <div class="form-group">
      <input type="submit" value="Login">
    </div>
  </form>
</div>
</body>
</html>

2.修改security配置类;在config层 HelloConfig文件中重写configure方法;

 @Override
    protected void configure(HttpSecurity http) throws Exception {
        //设置表单登录信息
        http.formLogin()
                //设置自己的登录页面
                .loginPage("/login.html")
                //设置登录表单的提交路径 要和login.html中的action一致
                .loginProcessingUrl("/login")
                //这个页面允许放行
                .permitAll();

        //禁止跨域伪造请求验证
        http.csrf().disable();
        //其他请求路径都要认证
        http.authorizeRequests().anyRequest().authenticated();

    }

访问路径访问info或者hello都可以进入到自己的登录页面;

七.设置跳转登录成功页面

默认登录成功 / 或原来的访问路径

创建SuccessController

package com.aaa.Controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

@Controller
public class SuccessController {

    @PostMapping("/success")
    public String success(){
        return "redirect:/success.html";
    }
}

创建一个success.html登录成功页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>登录成功</h1>
</body>
</html>

输入账号和密码

登录成功

授权的实现

授权:用户具有的权限和资源绑定的过程就是授权;

第一步:修改config  MySecurityConfig配置文件

 第二步:创建自定义资源访问  controller层  AuthController资源文件

package com.aaa.Controller;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

//资源
@RestController
public class AuthController {


    @GetMapping("select")
    public String select(){
        System.out.println("查询资源");
        return "查询资源";
    }
    @GetMapping("update")
    public String update(){
        System.out.println("修改资源");
        return "修改资源";
    }
    @GetMapping("delete")
    public String delete(){
        System.out.println("删除资源");
        return "删除资源";
    }
    @GetMapping("xxx")
    public String xxx(){
        System.out.println("共享资源");
        return "共享资源";
    }
}

第三步: 权限和资源进行绑定   config  MySecurityConfig配置文件

package com.aaa.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {

    //可以把该方法返回的对象交于Spring容器管理
    @Bean
    public PasswordEncoder passwordEncoder(){
        return  new BCryptPasswordEncoder();
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //设置表单登录信息
        http.formLogin()
                //设置自己的登录页面
                .loginPage("/login.html")
                //设置登录表单的提交路径 要和login.html中的action一致
                .loginProcessingUrl("/login")
                //表示登录成功跳转路径 提交方式必须为post请求
                .successForwardUrl("/success")
                //这个页面允许放行
                .permitAll();

        //设定资源和权限进行绑定
        http.authorizeRequests()
                .antMatchers("/select").hasAnyAuthority("user:select")
                .antMatchers("/update").hasAnyAuthority("user:update")
                .antMatchers("/delect").hasAnyAuthority("user:delect")
                .antMatchers("/xxx").hasAnyAuthority("user:xxx");

        //异常处理页面
        http.exceptionHandling().accessDeniedPage("/403.html");
        //禁止跨域伪造请求验证
        http.csrf().disable();
        //其他请求路径都要认证
        http.authorizeRequests().anyRequest().authenticated();

    }




    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication() //基于内存创建的账户和密码  未来可以用来连接数据库
                //账户
                .withUser("zhangsan")
                //密码
                .password(passwordEncoder().encode("123456"))
                //用户具备的角色
                .roles("admin")
                //设定用户权限
                .authorities("user:select","user:update","user:delete")
                .and() //连接符
                .withUser("lisi")
                .password(passwordEncoder().encode("012345"))
                .roles("test")
                .authorities("user:xxx")
                .and()
                .withUser("wangwu")
                .password(passwordEncoder().encode("567890"))
                .roles("group");


    }
}

第四步:访问资源

上面再访问没有的权限资源时,出现上面的错误界面,这种界面对客户友好。跳转到一个权限不足的界面;  

使用security注解完成授权

(思考: 上面权限和资源得到绑定 需要手动一一绑定。真正再开发中我们具有的权限和资源是非常多的。如果手动一一绑定是很麻烦的。)

第一步:开启security权限注解驱动

第二步:再相应的资源上使用注解  

controller层  AuthController资源文件

package com.aaa.Controller;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

//资源
@RestController
public class AuthController {


    @GetMapping("select")
    @PreAuthorize(value = "hasAuthority('user:select')")
    public String select(){
        System.out.println("查询资源");
        return "查询资源";
    }
    @GetMapping("update")
    @PreAuthorize(value = "hasAuthority('user:upate')")
    public String update(){
        System.out.println("修改资源");
        return "修改资源";
    }
    @GetMapping("delete")
    @PreAuthorize(value = "hasAuthority('user:delete')")
    public String delete(){
        System.out.println("删除资源");
        return "删除资源";
    }
    @GetMapping("xxx")
    @PreAuthorize(value = "hasAuthority('user:xxx')")
    public String xxx(){
        System.out.println("共享资源");
        return "共享资源";
    }
}

第三步:修改security配置

第四步:访问资源,流程是一样的  略

了解security认证的流程(源码)

核心过滤器:UsernamePasswordAuthenticationFilter

 

使用Spring Security连接数据库(自定义认证--需要连接数据库)

第一步:创建securtiy数据库

DROP TABLE IF EXISTS `sys_permission`;
CREATE TABLE `sys_permission`  (
  `perid` int(0) NOT NULL AUTO_INCREMENT,
  `pername` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `percode` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`perid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of sys_permission
-- ----------------------------
INSERT INTO `sys_permission` VALUES (1, '用户查询', 'user:query');
INSERT INTO `sys_permission` VALUES (2, '用户添加', 'user:add');
INSERT INTO `sys_permission` VALUES (3, '用户修改', 'user:update');
INSERT INTO `sys_permission` VALUES (4, '用户删除', 'user:delete');
INSERT INTO `sys_permission` VALUES (5, '用户导出', 'user:export');

-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role`  (
  `roleid` int(0) NOT NULL AUTO_INCREMENT,
  `rolename` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`roleid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES (1, '管理员');
INSERT INTO `sys_role` VALUES (2, '测试人员');
INSERT INTO `sys_role` VALUES (3, '普通用户');

-- ----------------------------
-- Table structure for sys_role_permission
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_permission`;
CREATE TABLE `sys_role_permission`  (
  `perid` int(0) NULL DEFAULT NULL,
  `roleid` int(0) NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of sys_role_permission
-- ----------------------------
INSERT INTO `sys_role_permission` VALUES (2, 1);
INSERT INTO `sys_role_permission` VALUES (1, 1);
INSERT INTO `sys_role_permission` VALUES (3, 1);
INSERT INTO `sys_role_permission` VALUES (4, 1);
INSERT INTO `sys_role_permission` VALUES (2, 2);
INSERT INTO `sys_role_permission` VALUES (1, 2);
INSERT INTO `sys_role_permission` VALUES (3, 2);
INSERT INTO `sys_role_permission` VALUES (1, 3);
INSERT INTO `sys_role_permission` VALUES (5, 3);

-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user`  (
  `userid` int(0) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `userpwd` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `sex` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `address` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`userid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES (1, '张三', '$2a$10$cI7e7bgSs9.9nNHhxKO9LuK/Ll.AeZwgUyZb77oD2y3UwwZyZhWG6', '男', '郑州');
INSERT INTO `sys_user` VALUES (2, '李四', '$2a$10$cI7e7bgSs9.9nNHhxKO9LuK/Ll.AeZwgUyZb77oD2y3UwwZyZhWG6', '男', '北京');
INSERT INTO `sys_user` VALUES (3, '王五', '$2a$10$cI7e7bgSs9.9nNHhxKO9LuK/Ll.AeZwgUyZb77oD2y3UwwZyZhWG6', '女', '杭州');

-- ----------------------------
-- Table structure for sys_user_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role`  (
  `userid` int(0) NOT NULL,
  `roleid` int(0) NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of sys_user_role
-- ----------------------------
INSERT INTO `sys_user_role` VALUES (1, 1);
INSERT INTO `sys_user_role` VALUES (2, 2);
INSERT INTO `sys_user_role` VALUES (3, 3);
INSERT INTO `sys_user_role` VALUES (1, 2);

SET FOREIGN_KEY_CHECKS = 1;

 

第二步:创建一个SpringBoot项目--------引入相关的依赖(lombok依赖   mysql驱动依赖  mybatis-plus依赖,security启动依赖)

 <dependencies>
        <!--加入security安全框架依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!--lombok依赖-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!--mysql驱动依赖-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--mybatis-plus依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.4</version>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

第三步:创建实体类   entity层 (User  Role  Permission)

User实体类

package com.aaa.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

@Data
@TableName("sys_user")   //实体类和数据库表名不一致时,使用该注解进行映射
public class User {
    @TableId(type = IdType.AUTO)    //主键自增
    private Integer userid;
    private String username;
    private String userpwd;
    private String sex;
    private String address;
}

Role实体类

package com.aaa.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

@Data
@TableName("sys_role")    //实体类和数据库表名不一致时,使用该注解进行映射
public class Role {
    @TableId(type = IdType.AUTO)    //主键自增
    private Integer roleid;
    private  String rolename;
}

Permission实体类

package com.aaa.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

@Data
@TableName("sys_permission")    //实体类和数据库表名不一致时,使用该注解进行映射
public class Permission {
    @TableId(type = IdType.AUTO)    //主键自增
    private Integer perid;
    private String pername;
    private String percode;
}

第四步:创建相应的Dao接口   Dao层  (UserDao  RoleDao  PermissionDao)

UserDao接口

package com.aaa.dao;

import com.aaa.entity.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

public interface UserDao extends BaseMapper<User> {

}

ReloDao接口

package com.aaa.dao;

import com.aaa.entity.Role;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

public interface RoleDao extends BaseMapper<Role> {
}

PermissionDao接口

package com.aaa.dao;

import com.aaa.entity.Permission;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface PermissionDao extends BaseMapper<Permission> {


    //查找用户的权限
    @Select("select distinct p.* from sys_user_role u join sys_role_permission r on u.roleid=r.roleid join sys_permission p on r.perid=p.perid where userid=#{userId}")
    public List<Permission> selectByUserId(Integer userId);

}

第五步:创建业务层 Service     MyUserDetailService代码

package com.aaa.service;

import com.aaa.dao.PermissionDao;
import com.aaa.dao.UserDao;
import com.aaa.entity.Permission;
import com.aaa.entity.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

@Service
public class MyUserDetailService implements UserDetailsService {
    @Autowired
    private UserDao userDao;
    @Autowired
    private PermissionDao permissionDao;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //1. 根据账户查找用户信息
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username",username);
        User user = userDao.selectOne(queryWrapper);
        //2.判断用户是否为null
        if(user!=null){
            //3.查找用户的具体权限
            List<Permission> permissions = permissionDao.selectByUserId(user.getUserid());
            /**
             * String username, 账户
             * String password, 密码-->而是数据库中存在的密码
             * Collection<? extends GrantedAuthority> authorities 当前用户具有的权限
             */
            Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
            //把List<Permission>转化为Collection<SimpleGrantedAuthority>
            for(Permission per:permissions){
                SimpleGrantedAuthority simpleGrantedAuthority=new SimpleGrantedAuthority(per.getPercode());
                authorities.add(simpleGrantedAuthority);
            }
            org.springframework.security.core.userdetails.User userDetail=new org.springframework.security.core.userdetails.User(user.getUsername(),user.getUserpwd(),authorities);
            return userDetail;
        }
        return null;
    }
}

第六步:创建Security配置文件   config层   mySecurityConfig文件

package com.aaa.config;

import com.aaa.service.MyUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private MyUserDetailService userDetailService;
    //添加加密器
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //使用数据库账号和密码
        auth.userDetailsService(userDetailService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //设置表单信息
        //使用自己的前端登录页面
        http.formLogin().loginPage("/login.html")
                .loginProcessingUrl("/login")
                .successForwardUrl("/success")
                .permitAll();

        //异常处理页面
        http.exceptionHandling().accessDeniedPage("/403.html");
        //禁用跨域伪造响应
        http.csrf().disable();

        //其他所有路径通过都需要认证
        http.authorizeRequests().anyRequest().authenticated();


    }
}

第七步:配置application.properties文件,连接数据库

server.port=8080
spring.datasource.url=jdbc:mysql://localhost:3306/security
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root

第八步:在SpringSecurity002Application  启动类中添加注解让其扫描到com.aaa.dao层

package com;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
//添加注解  包扫描到dao层

@MapperScan(basePackages = "com.aaa.dao")
public class SpringSecurity002Application {

    public static void main(String[] args) {
        SpringApplication.run(SpringSecurity002Application.class, args);
    }

}

第九步:访问资源

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1461243.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

白盒测试接口测试自动化测试

一、白盒测试&#xff1a;一种测试策略&#xff0c;允许我们检查程序的内部结构&#xff0c;对程序的逻辑结构进行检查&#xff0c;从中获取测试数据。白盒测试的对象基本是源程序&#xff0c;所以它又称为结构测试或逻辑驱动测试&#xff0c;白盒测试方法一般分为静态测试和动…

Cesium 问题:加载 gltf 格式的模型之后太小,如何让相机视角拉近

文章目录 问题分析问题 刚加载的模型太小,如何拉近视角放大 分析 在这里有两种方式进行拉近视角, 一种是点击复位进行视角拉近一种是刚加载就直接拉近视角// 模型三加载 this.damModel = new Cesium.Entity({name: "gltf模型",position:</

leetcode hot100零钱兑换Ⅱ

本题可以看出也是背包问题&#xff0c;但区别于之前的01背包问题&#xff0c;这个是完全背包问题的变形形式。 下面介绍01背包和完全背包的区别与联系&#xff1a; 01背包是背包中的物品只能用一次&#xff0c;不可以重复使用&#xff0c;而完全背包则是可以重复使用。01/完全…

一命通关动态规划dp

前言 这篇文章详细概括了动态规划的所有题型&#xff0c;以及各个题型的解决公式方法。如果看完这篇动态规划还是不会做题&#xff0c;我来给你补&#xff0c;我爱说点实话。 动态规划 何为动态规划&#xff1f; 动态规划&#xff0c;有一点暴力求解的感觉。用最通俗的语言来…

利用nbsp设置空格

想要实现上面效果&#xff0c;一开始直接<el-col :span"8" >{{ item.name }} </el-col> 或者<el-col :span"8" >{{ item.name }}</el-col>或者<el-col :span"8" >{{ item.name }}</el-col> 都无…

【办公类-16-07-02】“2023下学期 周计划-户外游戏 每班1周五天相同场地,6周一次循环”(python 排班表系列)

背景需求&#xff1a; 又到了开学季&#xff0c;新的自主游戏&#xff08;户外游戏&#xff09;安排表出炉了。 这张是贴在美术活动室的安排表&#xff0c;我需要转换成班级为单位的安排表&#xff0c;便于批量制作周计划。 设计思路&#xff1a; 1、一个班级每周轮到的一个场…

网工内推 | 上市公司、外企网工,厂商认证优先,最高18K*13薪

01 北京电旗通讯技术股份有限公司 招聘岗位&#xff1a;网络运维工程师 职责描述&#xff1a; 1.负责内部核心网络的运行监控、故障处理。 2.对网络性能进行监控和调优。 3.负责网络设备的规划选型。 4.设计网络架构拓扑图,制定网络规范。 5.分析处理复杂网络故障。 6.负…

sizeof()的易错点

你也可以传入一个变量的名字&#xff08;而不只是类型&#xff09;给 sizeof()&#xff0c;但在一些情况下&#xff0c;可能得不到你要的结果&#xff0c;所以要小心使用。例如&#xff0c;看看下面的代码片段&#xff1a; 在第一行&#xff0c;我们为 10 个整数的数组声明了空…

【前端】前端三要素之JavsScript基础

写在前面&#xff1a;本文仅包含JavaScript内容&#xff0c;DOM知识传送门在这里&#xff0c;BOM传送门在这里。 本文内容是假期中刷的黑马Pink老师视频&#xff08;十分感谢Pink老师&#xff09;&#xff0c;原文保存在个人的GitLab中&#xff0c;如果需要写的网页内容信息等可…

笔记:torch.roll

最近在准备写 swin transformer 的文章&#xff0c;记录下 torch.roll 的用法&#xff1a; >>> x torch.tensor([1, 2, 3, 4, 5, 6, 7, 8]).view(4, 2) >>> x tensor([[1, 2],[3, 4],[5, 6],[7, 8]]) 第0维度向下移1位&#xff0c;多出的[7,8]补充到顶部 &g…

【Flink网络通讯(一)】Flink RPC框架的整体设计

文章目录 1. Akka基本概念与Actor模型2. Akka相关demo2.1. 创建Akka系统2.2. 根据path获取Actor并与之通讯 3. Flink RPC框架与Akka的关系4.运行时RPC整体架构设计5. RpcEndpoint的设计与实现 我们从整体的角度看一下Flink RPC通信框架的设计与实现&#xff0c;了解其底层Akka通…

JS进阶——解构赋值

数组解构 基本&#xff1a; let [a, b, c] [1, 2, 3]; // a 1 // b 2 // c 3 可嵌套 let [a, [[b], c]] [1, [[2], 3]]; // a 1 // b 2 // c 3 可忽略 let [a, , b] [1, 2, 3]; // a 1 // b 3 不完全解构 let [a 1, b] []; // a 1, b undefined 剩余运…

基于RHEL8部署Zabbix6.0,监控不再困难!

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

5G——物理层仿真

1.前置条件 2.仿真流程 1.填写搜索过程 解&#xff1a; 2.填写每一步细节 2.2.1 准备 解&#xff1a; &#xff08;1&#xff09;BCH &#xff08;2&#xff09;BCCH 解析&#xff1a;因为PBCH是物理广播信道&#xff0c;BCCH是用于广播系统控制信息的下行信道&#…

vulfocus靶场搭建

vulfocus靶场搭建 什么是vulfocus搭建教程靶场配置场景靶场编排靶场优化 什么是vulfocus Vulfocus 是一个漏洞集成平台&#xff0c;将漏洞环境 docker 镜像&#xff0c;放入即可使用&#xff0c;开箱即用&#xff0c;我们可以通过搭建该靶场&#xff0c;简单方便地复现一些框架…

数据库专题——分库分表

一. 分库分表介绍二. 分库分表实践 一. 分库分表介绍 1.1 分库分表解决了什么问题 先说分库&#xff1a; 《高性能MySQL》中提到了两种数据库扩展方式&#xff1a;垂直扩展和水平扩展。前者意味着买更多性能强悍的硬件&#xff0c;但是总会达到扩展的天花板&#xff0c;且成本…

​LeetCode解法汇总105. 从前序与中序遍历序列构造二叉树

目录链接&#xff1a; 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目&#xff1a; https://github.com/September26/java-algorithms 原题链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 描述&#xff1a; 给定两个整…

js 多对象去重(多属性去重)

需求中发现后端可能没有处理重复数据&#xff0c;这个时候前段可以直接解决。 在 JavaScript 中&#xff0c;可以使用 Set 数据结构来进行多对象的去重。Set 是 ES6 新引入的集合类型&#xff0c;其特点是元素不会重复且无序。 下面是一个示例代码&#xff0c;展示如何通过 S…

python基础教程—总结篇

这篇是Python基础教程系列的总结篇&#xff0c;这里这个专栏的地址&#xff1a;《Python教程》 首先必须声明一点&#xff0c;这是基础教程&#xff0c;所以面向的是新人&#xff0c;没有学过Python的同学&#xff0c;所以这套教程并没有涉及到比较难的并发编程模块&#xff0…

【Git教程】(二)入门 ——关于工作区与版本库、版本提交、查看信息、克隆、推送与拉回的简单介绍 ~

Git教程 入门 1️⃣ 准备Git 环境1.1 创建版本库1.2 首次提交1.3 显示历史 2️⃣ Git 的协作功能2.1 克隆版本库2.2 从另一版本库中获取修改2.3 从任意版本库中取回修改2.4 创建共享版本库2.5 用 push 命令上载修改2.6 Pull 命令&#xff1a;取回修改 &#x1f33e; 总结 如果…