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:创建用于测试的视图页面

页面效果如下

登录首页

拒绝访问页面

用户登录界面

用户注册界面

相关文章
|
17天前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
1天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
9 2
|
7天前
|
前端开发 Java 开发者
Spring生态学习路径与源码深度探讨
【11月更文挑战第13天】Spring框架作为Java企业级开发中的核心框架,其丰富的生态系统和强大的功能吸引了无数开发者的关注。学习Spring生态不仅仅是掌握Spring Framework本身,更需要深入理解其周边组件和工具,以及源码的底层实现逻辑。本文将从Spring生态的学习路径入手,详细探讨如何系统地学习Spring,并深入解析各个重点的底层实现逻辑。
28 9
|
16天前
|
JavaScript Java 项目管理
Java毕设学习 基于SpringBoot + Vue 的医院管理系统 持续给大家寻找Java毕设学习项目(附源码)
基于SpringBoot + Vue的医院管理系统,涵盖医院、患者、挂号、药物、检查、病床、排班管理和数据分析等功能。开发工具为IDEA和HBuilder X,环境需配置jdk8、Node.js14、MySQL8。文末提供源码下载链接。
|
22天前
|
自然语言处理 Java API
Spring Boot 接入大模型实战:通义千问赋能智能应用快速构建
【10月更文挑战第23天】在人工智能(AI)技术飞速发展的今天,大模型如通义千问(阿里云推出的生成式对话引擎)等已成为推动智能应用创新的重要力量。然而,对于许多开发者而言,如何高效、便捷地接入这些大模型并构建出功能丰富的智能应用仍是一个挑战。
89 6
|
25天前
|
缓存 NoSQL Java
Spring Boot与Redis:整合与实战
【10月更文挑战第15天】本文介绍了如何在Spring Boot项目中整合Redis,通过一个电商商品推荐系统的案例,详细展示了从添加依赖、配置连接信息到创建配置类的具体步骤。实战部分演示了如何利用Redis缓存提高系统响应速度,减少数据库访问压力,从而提升用户体验。
62 2
|
1月前
|
Java Spring
Spring底层架构源码解析(三)
Spring底层架构源码解析(三)
104 5
|
1月前
|
Java 测试技术 开发者
springboot学习四:Spring Boot profile多环境配置、devtools热部署
这篇文章主要介绍了如何在Spring Boot中进行多环境配置以及如何整合DevTools实现热部署,以提高开发效率。
54 2
|
1月前
|
前端开发 Java 程序员
springboot 学习十五:Spring Boot 优雅的集成Swagger2、Knife4j
这篇文章是关于如何在Spring Boot项目中集成Swagger2和Knife4j来生成和美化API接口文档的详细教程。
68 1
|
1月前
|
Java API Spring
springboot学习七:Spring Boot2.x 拦截器基础入门&实战项目场景实现
这篇文章是关于Spring Boot 2.x中拦截器的入门教程和实战项目场景实现的详细指南。
23 0
springboot学习七:Spring Boot2.x 拦截器基础入门&实战项目场景实现