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

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
云数据库 RDS PostgreSQL,高可用系列 2核4GB
简介: 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:创建用于测试的视图页面

页面效果如下

登录首页

拒绝访问页面

用户登录界面

用户注册界面

相关文章
|
1月前
|
前端开发 Java 应用服务中间件
《深入理解Spring》 Spring Boot——约定优于配置的革命者
Spring Boot基于“约定优于配置”理念,通过自动配置、起步依赖、嵌入式容器和Actuator四大特性,简化Spring应用的开发与部署,提升效率,降低门槛,成为现代Java开发的事实标准。
|
1月前
|
XML Java 测试技术
《深入理解Spring》:IoC容器核心原理与实战
Spring IoC通过控制反转与依赖注入实现对象间的解耦,由容器统一管理Bean的生命周期与依赖关系。支持XML、注解和Java配置三种方式,结合作用域、条件化配置与循环依赖处理等机制,提升应用的可维护性与可测试性,是现代Java开发的核心基石。
|
1月前
|
前端开发 Java 微服务
《深入理解Spring》:Spring、Spring MVC与Spring Boot的深度解析
Spring Framework是Java生态的基石,提供IoC、AOP等核心功能;Spring MVC基于其构建,实现Web层MVC架构;Spring Boot则通过自动配置和内嵌服务器,极大简化了开发与部署。三者层层演进,Spring Boot并非替代,而是对前者的高效封装与增强,适用于微服务与快速开发,而深入理解Spring Framework有助于更好驾驭整体技术栈。
|
1月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
354 2
|
1月前
|
监控 Cloud Native Java
Spring Boot 3.x 微服务架构实战指南
🌟蒋星熠Jaxonic,技术宇宙中的星际旅人。深耕Spring Boot 3.x与微服务架构,探索云原生、性能优化与高可用系统设计。以代码为笔,在二进制星河中谱写极客诗篇。关注我,共赴技术星辰大海!(238字)
Spring Boot 3.x 微服务架构实战指南
|
2月前
|
人工智能 Java 机器人
基于Spring AI Alibaba + Spring Boot + Ollama搭建本地AI对话机器人API
Spring AI Alibaba集成Ollama,基于Java构建本地大模型应用,支持流式对话、knife4j接口可视化,实现高隐私、免API密钥的离线AI服务。
1837 1
基于Spring AI Alibaba + Spring Boot + Ollama搭建本地AI对话机器人API
存储 JSON Java
473 0
|
2月前
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
|
2月前
|
负载均衡 监控 Java
Spring Cloud Gateway 全解析:路由配置、断言规则与过滤器实战指南
本文详细介绍了 Spring Cloud Gateway 的核心功能与实践配置。首先讲解了网关模块的创建流程,包括依赖引入(gateway、nacos 服务发现、负载均衡)、端口与服务发现配置,以及路由规则的设置(需注意路径前缀重复与优先级 order)。接着深入解析路由断言,涵盖 After、Before、Path 等 12 种内置断言的参数、作用及配置示例,并说明了自定义断言的实现方法。随后重点阐述过滤器机制,区分路由过滤器(如 AddRequestHeader、RewritePath、RequestRateLimiter 等)与全局过滤器的作用范围与配置方式,提
Spring Cloud Gateway 全解析:路由配置、断言规则与过滤器实战指南
下一篇
oss云网关配置