当前位置: 首页 > news >正文

Spring——SpringSecurity开发经验实战

摘要

本文介绍了一个简单的 Spring Security 实战示例,涵盖基本的身份验证和授权流程。首先介绍了 Spring Security 是一个强大的安全框架,用于在 Spring 应用中实现身份验证、授权以及保护应用免受常见安全攻击。接着详细阐述了项目结构、添加 Spring Security 依赖、创建数据库表、创建实体类、创建 UserDetailsService 实现、配置 Spring Security、使用@PreAuthorize注解控制方法权限、配置启动类、配置 application.properties 以及运行和测试等步骤。

1. Spring Security简介

Spring Security 是一个强大的安全框架,主要用于在 Spring 应用中实现身份验证、授权以及保护应用免受常见安全攻击。以下是一个简单的 Spring Security 实战示例,涵盖了基本的身份验证和授权流程。

2. 项目结构

src
 └── main
      ├── java
      │    └── com
      │         └── example
      │              └── security
      │                   ├── SecurityConfig.java
      │                   ├── WebController.java
      │                   ├── Application.java
      │                   ├── CustomUserDetailsService.java
      │                   ├── User.java
      │                   ├── Role.java
      │                   └── UserRepository.java
      └── resources
           ├── application.properties
           ├── schema.sql
           └── data.sql

3. 添加 Spring Security 依赖

首先,确保在 pom.xmlbuild.gradle 中添加了 Spring Security 的依赖。

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

4. 创建数据库表

首先,我们需要为用户和角色创建数据库表。下面是一个简单的 SQL 脚本,用于在数据库中创建用户和角色表。

4.1. schema.sql 文件:

CREATE TABLE roles (
  id BIGINT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(50) NOT NULL
);

CREATE TABLE users (
  id BIGINT AUTO_INCREMENT PRIMARY KEY,
  username VARCHAR(50) NOT NULL UNIQUE,
  password VARCHAR(255) NOT NULL,
  enabled BOOLEAN NOT NULL DEFAULT true
);

CREATE TABLE user_roles (
  user_id BIGINT,
  role_id BIGINT,
  PRIMARY KEY (user_id, role_id),
  FOREIGN KEY (user_id) REFERENCES users(id),
  FOREIGN KEY (role_id) REFERENCES roles(id)
);

4.2. data.sql 文件:

INSERT INTO roles (name) VALUES ('ROLE_ADMIN');
INSERT INTO roles (name) VALUES ('ROLE_USER');

INSERT INTO users (username, password, enabled) VALUES ('admin', '{noop}admin', true);
INSERT INTO users (username, password, enabled) VALUES ('user', '{noop}user', true);

INSERT INTO user_roles (user_id, role_id) 
SELECT u.id, r.id 
FROM users u, roles r 
WHERE u.username = 'admin' AND r.name = 'ROLE_ADMIN';

INSERT INTO user_roles (user_id, role_id) 
SELECT u.id, r.id 
FROM users u, roles r 
WHERE u.username = 'user' AND r.name = 'ROLE_USER';

这里,{noop} 是 Spring Security 5 之前的一个标记,用于指示密码不加密。生产环境中应使用加密密码,如 BCrypt

5. 创建实体类

我们需要两个实体类 UserRole,分别表示用户和角色信息。

5.1. User.java

package com.example.security;

import javax.persistence.*;
import java.util.Set;

@Entity
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String username;
    private String password;
    private boolean enabled;

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(
        name = "user_roles", 
        joinColumns = @JoinColumn(name = "user_id"), 
        inverseJoinColumns = @JoinColumn(name = "role_id"))
    private Set<Role> roles;

    // Getters and Setters
}

5.2. Role.java

package com.example.security;

import javax.persistence.*;

@Entity
public class Role {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    // Getters and Setters
}

6. 创建 UserDetailsService 实现

我们将通过 UserDetailsService 从数据库加载用户信息,Spring Security 会使用这个服务来进行身份验证和权限控制。

6.1. CustomUserDetailsService.java

package com.example.security;

import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.stream.Collectors;

@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    private final UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 查询数据库,加载用户及其角色
        User user = userRepository.findByUsername(username)
        .orElseThrow(() -> new UsernameNotFoundException("User not found"));

        // 将角色转换为 GrantedAuthority
        return new User(
            user.getUsername(),
            user.getPassword(),
            user.isEnabled(),
            true, true, true,
            user.getRoles().stream()
            .map(role -> new org.springframework.security.core.authority.SimpleGrantedAuthority(role.getName()))
            .collect(Collectors.toList())
        );
    }
}

6.2. UserRepository.java

package com.example.security;

import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;

public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByUsername(String username);
}

7. 配置 Spring Security

SecurityConfig中,配置数据库认证,并启用方法级别的权限控制。

7.1. SecurityConfig.java

package com.example.security;

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.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)  // 启用方法级权限控制
public class SecurityConfig {

    @Autowired
    private final CustomUserDetailsService customUserDetailsService;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
        .authorizeRequests()
        .antMatchers("/login", "/public/**").permitAll()
        .anyRequest().authenticated()
        .and()
        .formLogin().permitAll()
        .and()
        .logout().permitAll();

        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(customUserDetailsService)
        .passwordEncoder(passwordEncoder());
    }
}

8. 使用@PreAuthorize注解控制方法权限

在控制器方法上使用 @PreAuthorize 注解进行权限控制。比如,你可以根据角色控制谁能访问哪些页面。

8.1. WebController.java

package com.example.security;

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

@Controller
public class WebController {

    @GetMapping("/admin")
    @PreAuthorize("hasRole('ROLE_ADMIN')")  // 只有角色为 ROLE_ADMIN 的用户可以访问
    public String adminPage() {
        return "admin";
    }

    @GetMapping("/user")
    @PreAuthorize("hasRole('ROLE_USER')")   // 只有角色为 ROLE_USER 的用户可以访问
    public String userPage() {
        return "user";
    }

    @GetMapping("/dashboard")
    @PreAuthorize("hasAnyRole('ROLE_ADMIN', 'ROLE_USER')")  // 角色为 ROLE_ADMIN 或 ROLE_USER 的用户可以访问
    public String dashboard() {
        return "dashboard";
    }
}

9. 配置启动类

确保你有一个 Application 启动类来启动 Spring Boot 应用。

9.1. Application.java

package com.example.security;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

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

10. 配置 application.properties

确保你的 application.properties 中包含数据库连接配置。

application.properties

spring.datasource.url=jdbc:mysql://localhost:3306/security_db?useSSL=false
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.security.user.name=admin
spring.security.user.password=admin

11. 运行和测试

  1. 启动 Spring Boot 应用。
  2. 使用 adminuser 用户分别登录,访问 /admin/user/dashboard 页面,检查是否能根据角色权限控制访问。

这个示例展示了如何在 Spring Boot 中使用数据库存储用户和角色信息,并通过 @PreAuthorize 注解进行方法级别的权限控制。我们通过自定义 UserDetailsService 从数据库中加载用户信息并设置相应的角色。这样,Spring Security 会根据用户的角色来控制对不同控制器方法的访问权限。

博文参考

相关文章:

  • 给小米/红米手机root(工具基本为官方工具)——KernelSU篇
  • 【Python量化金融实战】-第1章:Python量化金融概述:1.1量化金融的定义与发展历程
  • QListView实现文件选择功能
  • JAVAEE一>Spring IoC和DI详解
  • 2024全国青少年信息素养大赛python复赛真题--装错信封
  • 【自学嵌入式(9)ESP8266网络服务器的使用】
  • spring中关于Bean的复习(IOC和DI)
  • 深度学习(5)-卷积神经网络
  • Qt 是一个跨平台的 C++ 应用程序框架
  • 如何了解和学习“未知的未知”
  • python安装教程,最新版本Python3.12安装教程(附安装包)
  • 计算机组成与接口5
  • 爬虫基础之爬取某基金网站+数据分析
  • 相机标定(张正友标定法)
  • 运放的输入失调电压和输入偏置电流
  • 机器学习数学通关指南——牛顿-莱布尼茨公式
  • Python 数据分析概述 ①
  • 操作系统知识点5
  • 玩转 Java 与 Python 交互,JEP 库来助力
  • 开源一个可以调RGB三色的小灯棒子
  • 遵义桐梓疫情最新情况/seo站长综合查询工具
  • 建站公司网站建设/英文网站seo
  • 辽宁电力建设监理有限公司网站/黑帽seo是什么
  • 做家装的设计公司网站/高手优化网站
  • 网站建设三剑客/一份完整的营销策划方案
  • 织梦做中英文企业网站/seo搜索优化排名