Spring Security在Spring Boot中的讲解与实战(附源码)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: Spring Security在Spring Boot中的讲解与实战(附源码)

觉得有帮助请点赞关注收藏~~~

一、什么是Spring Security

Spring Security是一个专门针对Spring应用系统的安全框架,充分利用了Spring框架的依赖注入和AOP功能,为Spring应用系统提供安全访问控制解决方案。

在Spring Security安全框架中,有两个重要概念。一个是授权(authorization),另一个是认证(ahtuentication)。授权即确定用户在当前应用系统下所拥有的功能权限。认证即确认用户访问当前系统的身份

二、Spring Security的基本使用

1:适配器

Spring Security为Web应用提供了一个适配器类WebSecurityConfigurerAdapter 该类实现了WebSecurityConfigurer<WebSecurity>接口,并提供了两个configure方法用于认证和授权操作

2:用户认证

使用AuthenticationManagerBuilder的inMemoryAuthentication()方法可以添加在内存中的用户,并给用户 指定角色权限

3:请求授权

常用方法如下

三、Spring Boot对Spring Security的支持

在Spring Boot应用中 只需引入spring-boot-starter-security依赖即可使用Spring Security安全框架,这是因为Spring Boot对Spring Security提供了自动配置功能。

接下来通过使用基于Spring Data JPA的Spring Security安全框架来进行实战

1:修改pom.xml文件 添加以下内容

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.45</version>
</dependency>

2:配置application.properties文件

server.servlet.context-path=/ch7_1
###
##数据源信息配置
###
#数据库地址
spring.datasource.url=jdbc:mysql://localhost:3306/springbootjpa?characterEncoding=utf8
#数据库用户名
spring.datasource.username=root
#数据库密码
spring.datasource.password=root
#数据库驱动
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
####
#JPA持久化配置
####
#指定数据库类型
spring.jpa.database=MYSQL
#指定是否在日志中显示SQL语句
spring.jpa.show-sql=true
#指定自动创建、更新数据库表等配置,update表示如果数据库中存在持久化类对应的表就不创建,不存在就创建对应的表
spring.jpa.hibernate.ddl-auto=update
#让控制器输出的JSON字符串格式更美观
spring.jackson.serialization.indent-output=true 
spring.thymeleaf.cache=false
logging.level.org.springframework.security=trace

3:创建用户和权限 持久化的实体类

用户代码如下

package com.ch.ch7_1.entity;
import java.io.Serializable;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import javax.persistence.Transient;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@Entity
@Table(name = "user")
@JsonIgnoreProperties(value = { "hibernateLazyInitializer"})
public class MyUser implements Serializable{
  private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    private String username;
    private String password; 
    //这里不能是懒加载lazy,否则在MyUserSecurityService的loadUserByUsername方法中获得不到权限
    @ManyToMany(cascade = {CascadeType.REFRESH}, fetch = FetchType.EAGER)
    @JoinTable(name = "user_authority",joinColumns = @JoinColumn(name = "user_id"),
    inverseJoinColumns = @JoinColumn(name = "authority_id"))
    private List<Authority> authorityList;
    //repassword不映射到数据表
    @Transient
    private String repassword;
  public int getId() {
    return id;
  }
  public void setId(int id) {
    this.id = id;
  }
  public String getUsername() {
    return username;
  }
  public void setUsername(String username) {
    this.username = username;
  }
  public String getPassword() {
    return password;
  }
  public void setPassword(String password) {
    this.password = password;
  }
  public List<Authority> getAuthorityList() {
    return authorityList;
  }
  public void setAuthorityList(List<Authority> authorityList) {
    this.authorityList = authorityList;
  }
  public String getRepassword() {
    return repassword;
  }
  public void setRepassword(String repassword) {
    this.repassword = repassword;
  }
}

权限代码如下

package com.ch.ch7_1.entity;
import java.io.Serializable;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@Entity
@Table(name = "authority")
@JsonIgnoreProperties(value = { "hibernateLazyInitializer"})
public class Authority implements Serializable{
  private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    @Column(nullable = false)
    private String name;
    @ManyToMany(mappedBy = "authorityList")
    @JsonIgnore
    private List<MyUser> userList;
  public int getId() {
    return id;
  }
  public void setId(int id) {
    this.id = id;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public List<MyUser> getUserList() {
    return userList;
  }
  public void setUserList(List<MyUser> userList) {
    this.userList = userList;
  }
}

4:创建数据访问层接口

package com.ch.ch7_1.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.ch.ch7_1.entity.MyUser;
public interface MyUserRepository extends JpaRepository<MyUser, Integer>{
  //根据用户名查询用户,方法名命名符合Spring Data JPA规范
  MyUser findByUsername(String username);
}

5:创建业务层

接口代码如下

package com.ch.ch7_1.service;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.ui.Model;
import com.ch.ch7_1.entity.MyUser;
public interface UserService {
  public String register(MyUser userDomain);
  public String loginSuccess(Model model);
  public String main(Model model);
  public String deniedAccess(Model model);
  public String logout(HttpServletRequest request, HttpServletResponse response);
}

实现类代码如下

package com.ch.ch7_1.service;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import com.ch.ch7_1.entity.Authority;
import com.ch.ch7_1.entity.MyUser;
import com.ch.ch7_1.repository.MyUserRepository;
@Service
public class UserServiceImpl implements UserService{
  @Autowired
  private MyUserRepository myUserRepository;
  /**
   * 实现注册
   */
  @Override
  public String register(MyUser userDomain) {
    String username = userDomain.getUsername();
    List<Authority> authorityList = new ArrayList<Authority>();
    //管理员权限
    if("admin".equals(username)) {
      Authority a1 = new Authority();
      Authority a2 = new Authority();
      a1.setId(1);
      a1.setName("ROLE_ADMIN");
      a2.setId(2);
      a2.setName("ROLE_DBA");
      authorityList.add(a1);
      authorityList.add(a2);
    }else {//用户权限
      Authority a1 = new Authority();
      a1.setId(3);
      a1.setName("ROLE_USER");
      authorityList.add(a1);
    }
    userDomain.setAuthorityList(authorityList);
    //加密密码
    String secret  = new BCryptPasswordEncoder().encode(userDomain.getPassword());
    userDomain.setPassword(secret);
    MyUser mu = myUserRepository.save(userDomain);
    if(mu != null)//注册成功
      return "/login";
    return "/register";//注册失败
  }
  /**
   * 用户登录成功
   */
  @Override
  public String loginSuccess(Model model) {
    model.addAttribute("user", getUname());
    model.addAttribute("role", getAuthorities());
    return "/user/loginSuccess";
  }
  /**
   * 管理员登录成功
   */
  @Override
  public String main(Model model) {
    model.addAttribute("user", getUname());
    model.addAttribute("role", getAuthorities());
    return "/admin/main";
  }
  /**
   * 注销用户
   */
  @Override
  public String logout(HttpServletRequest request, HttpServletResponse response) {
    //获得用户认证信息
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    if(authentication != null) {
      //注销
      new SecurityContextLogoutHandler().logout(request, response, authentication);
    }
    return "redirect:/login?logout";
  }
  /**
   * 没有权限拒绝访问
   */
  @Override
  public String deniedAccess(Model model) {
    model.addAttribute("user", getUname());
    model.addAttribute("role", getAuthorities());
    return "deniedAccess";
  }
  /**
   * 获得当前用户名称
   */
  private String getUname() {
    return SecurityContextHolder.getContext().getAuthentication().getName();
  }
  /**
   * 获得当前用户权限
   */
  private String getAuthorities() {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    List<String> roles = new ArrayList<String>();
    for (GrantedAuthority ga : authentication.getAuthorities()) {
      roles.add(ga.getAuthority());
    }
    return roles.toString();
  }
}

此处代码太多 需要源码请点赞关注收藏后评论区留言或私信博主

6:创建控制器类

7:创建应用的安全控制相关实现

8:创建用于测试的视图页面

页面效果如下

登录首页

拒绝访问页面

用户登录界面

用户注册界面

相关文章
|
24天前
|
JSON 安全 Java
什么是JWT?如何使用Spring Boot Security实现它?
什么是JWT?如何使用Spring Boot Security实现它?
101 5
|
1月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
76 2
|
1月前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
2天前
|
Java 数据库连接 Maven
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
自动装配是现在面试中常考的一道面试题。本文基于最新的 SpringBoot 3.3.3 版本的源码来分析自动装配的原理,并在文未说明了SpringBoot2和SpringBoot3的自动装配源码中区别,以及面试回答的拿分核心话术。
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
|
12天前
|
存储 JavaScript 前端开发
基于 SpringBoot 和 Vue 开发校园点餐订餐外卖跑腿Java源码
一个非常实用的校园外卖系统,基于 SpringBoot 和 Vue 的开发。这一系统源于黑马的外卖案例项目 经过站长的进一步改进和优化,提供了更丰富的功能和更高的可用性。 这个项目的架构设计非常有趣。虽然它采用了SpringBoot和Vue的组合,但并不是一个完全分离的项目。 前端视图通过JS的方式引入了Vue和Element UI,既能利用Vue的快速开发优势,
71 13
|
28天前
|
监控 Java 数据库连接
详解Spring Batch:在Spring Boot中实现高效批处理
详解Spring Batch:在Spring Boot中实现高效批处理
152 12
|
20天前
|
JavaScript 安全 Java
java版药品不良反应智能监测系统源码,采用SpringBoot、Vue、MySQL技术开发
基于B/S架构,采用Java、SpringBoot、Vue、MySQL等技术自主研发的ADR智能监测系统,适用于三甲医院,支持二次开发。该系统能自动监测全院患者药物不良反应,通过移动端和PC端实时反馈,提升用药安全。系统涵盖规则管理、监测报告、系统管理三大模块,确保精准、高效地处理ADR事件。
|
21天前
|
存储 缓存 Java
Spring面试必问:手写Spring IoC 循环依赖底层源码剖析
在Spring框架中,IoC(Inversion of Control,控制反转)是一个核心概念,它允许容器管理对象的生命周期和依赖关系。然而,在实际应用中,我们可能会遇到对象间的循环依赖问题。本文将深入探讨Spring如何解决IoC中的循环依赖问题,并通过手写源码的方式,让你对其底层原理有一个全新的认识。
41 2
|
28天前
|
安全 Java 测试技术
详解Spring Profiles:在Spring Boot中实现环境配置管理
详解Spring Profiles:在Spring Boot中实现环境配置管理
79 10
|
24天前
|
负载均衡 Java 开发者
深入探索Spring Cloud与Spring Boot:构建微服务架构的实践经验
深入探索Spring Cloud与Spring Boot:构建微服务架构的实践经验
82 5