Spring Security 框架 - 教程

news/2025/9/18 14:54:01/文章来源:https://www.cnblogs.com/yxysuanfa/p/19098784

目录

一、什么是 Spring Security?

✅ 核心功能:

二、Spring Security 核心概念

1. Authentication(认证)

2. UserDetails & UserDetailsService

3. PasswordEncoder

4. GrantedAuthority

5. SecurityContext & SecurityContextHolder

三、Spring Security 工作流程(认证过程)

四、常用配置方式(Spring Boot)

1. 引入依赖(Maven)

2. 基础配置类(启用 Web 安全)

3. 自定义 UserDetailsService

五、权限控制(授权 Authorization)

1. 方法级别权限(推荐)

2. 页面级别权限(Thymeleaf)

六、常见自定义扩展

1. 自定义登录成功/失败处理器

2. 自定义权限异常处理

七、与 JWT / 前后端分离集成(简要)

八、最佳实践 & 注意事项

✅ 总结一句话:

学习路径建议:

送你一个完整可运行的最小示例结构:


一、什么是 Spring Security?

Spring Security 是一个功能强大、高度可定制的身份验证(Authentication)和访问控制(Authorization)框架,是保护基于 Spring 的应用的事实标准。

✅ 核心功能:

  • 用户登录认证(Authentication)
  • 权限控制、角色控制(Authorization)
  • 防止 CSRF、会话固定、点击劫持等攻击
  • 支持多种登录方式:表单登录、HTTP Basic、OAuth2、JWT、LDAP 等
  • 与 Spring Boot 无缝集成

二、Spring Security 核心概念

1. Authentication(认证)

  • 代表“当前用户是谁”,包含用户名、密码、权限等。
  • 由 AuthenticationManager 管理认证过程。

2. UserDetails & UserDetailsService

  • UserDetails:封装用户信息(用户名、密码、权限、是否锁定等)
  • UserDetailsService:根据用户名加载 UserDetails
@Override
public UserDetails loadUserByUsername(String username) {
// 从数据库查用户 → 返回 UserDetails(含加密密码 + 权限)
}

3. PasswordEncoder

  • 用于加密密码和比对密码。
  • 永远不要存储明文密码!
  • 常用实现:BCryptPasswordEncoderSCryptPasswordEncoderPbkdf2PasswordEncoder
// 注册时:
user.setPassword(passwordEncoder.encode(rawPassword));
// 登录时(框架自动调用):
passwordEncoder.matches(rawPassword, encodedPassword); // true/false

4. GrantedAuthority

  • 代表一个权限,如 "ROLE_ADMIN""user:delete"
  • 通常以 ROLE_ 开头表示角色,其它表示具体权限。

5. SecurityContext & SecurityContextHolder

  • 存储当前登录用户的信息(Authentication 对象)。
  • 可在任何地方获取当前用户:
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String username = auth.getName();

三、Spring Security 工作流程(认证过程)

sequenceDiagram
participant User
participant Filter as FilterChain (Spring Security)
participant Provider as AuthenticationProvider
participant Service as UserDetailsService
participant Encoder as PasswordEncoder
User->>Filter: 提交用户名/密码
Filter->>Provider: 调用 authenticate()
Provider->>Service: loadUserByUsername(username)
Service-->>Provider: 返回 UserDetails(含加密密码)
Provider->>Encoder: matches(输入密码, 数据库加密密码)
alt 匹配成功
Encoder-->>Provider: true
Provider-->>Filter: 返回认证成功 Authentication
Filter->>User: 登录成功,跳转
else 匹配失败
Encoder-->>Provider: false
Provider-->>Filter: 抛出异常
Filter->>User: 登录失败
end

四、常用配置方式(Spring Boot)

1. 引入依赖(Maven)

org.springframework.boot
spring-boot-starter-security

2. 基础配置类(启用 Web 安全)

@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz -> authz
.requestMatchers("/login", "/register", "/css/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/user/**").hasAnyRole("USER", "ADMIN")
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")           // 自定义登录页
.defaultSuccessUrl("/home")    // 登录成功跳转
.permitAll()
)
.logout(logout -> logout
.logoutSuccessUrl("/login?logout")
.permitAll()
);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); // 推荐使用 BCrypt
}
}

3. 自定义 UserDetailsService

@Component
public class MyUserServiceImpl implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userMapper.findUserByName(username);
if (user == null) throw new UsernameNotFoundException("用户不存在");
// ✅ 直接返回数据库中的加密密码(注册时已加密存储!)
return User.builder()
.username(user.getUsername())
.password(user.getSupwd()) // ← 不要再 encode!
.roles("USER") // 或者 .authorities(getAuthorities())
.build();
}
}

五、权限控制(授权 Authorization)

1. 方法级别权限(推荐)

@Service
public class ArticleService {
@PreAuthorize("hasRole('ADMIN')") // 需要 ADMIN 角色
public void deleteArticle(Long id) {
// ...
}
@PreAuthorize("hasAuthority('article:edit')") // 需要具体权限
public void editArticle(Article article) {
// ...
}
@PostAuthorize("returnObject.owner == authentication.name")
public Article getArticle(Long id) {
// 返回后检查:只有文章主人才能看
}
}

⚠️ 要启用方法级权限,需在配置类加:@EnableMethodSecurity

@Configuration
@EnableWebSecurity
@EnableMethodSecurity // ← 启用 @PreAuthorize 等注解
public class SecurityConfig { ... }

2. 页面级别权限(Thymeleaf)

管理后台

需引入:

org.thymeleaf.extras
thymeleaf-extras-springsecurity6

六、常见自定义扩展

1. 自定义登录成功/失败处理器

@Component
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException {
response.sendRedirect("/home?loginSuccess");
}
}

在配置中使用:

.formLogin(form -> form
.successHandler(mySuccessHandler)
.failureHandler(myFailureHandler)
)

2. 自定义权限异常处理

@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
response.sendRedirect("/403");
}
}

配置:

.exceptionHandling(ex -> ex
.accessDeniedHandler(myAccessDeniedHandler)
)

七、与 JWT / 前后端分离集成(简要)

如果你是前后端分离项目(如 Vue + Spring Boot),通常不用 Session,改用 JWT:

  1. 用户 POST /login 提交用户名密码
  2. 后端验证成功 → 生成 JWT Token 返回
  3. 前端后续请求在 Header 中携带 Authorization: Bearer <token>
  4. 后端用 Filter 解析 Token → 设置 SecurityContext

⚠️ 此时 UserDetailsService 依然有用 —— 用于从 Token 中的用户名加载用户权限!


八、最佳实践 & 注意事项

项目建议
密码存储必须加密(BCrypt 最常用)
密码比对交给 Spring Security,不要手动比对
权限设计角色(ROLE_) + 细粒度权限(user:delete)结合
登录页可自定义,但路径要 permitAll
CSRF表单登录默认开启,JWT 项目可关闭
调试可临时 .authorizeHttpRequests(authz -> authz.anyRequest().permitAll()) 放行所有

✅ 总结一句话:

Spring Security = 认证(你是谁)+ 授权(你能干什么)+ 安全防护,你只需要提供“用户数据”和“权限规则”,框架自动完成验证和拦截。


学习路径建议:

  1. 先跑通表单登录 + 自定义 UserDetailsService
  2. 学会配置 URL 权限控制
  3. 掌握方法级权限 @PreAuthorize
  4. 学习自定义处理器(登录成功/失败、无权限)
  5. 进阶:JWT、OAuth2、方法权限表达式、动态权限

送你一个完整可运行的最小示例结构:

src/
├── controller/
│   └── LoginController.java       // 登录页、首页
├── service/
│   └── MyUserServiceImpl.java     // loadUserByUsername
├── config/
│   └── SecurityConfig.java        // 权限配置 + PasswordEncoder
└── entity/
└── User.java                  // 用户实体(含加密密码字段)

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

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

相关文章

Android 安卓 困难处理记录 腾讯IM和厂商离线推送难题 点击离线推送无法唤醒APP启动页但某些Service服务和Application被启动

Android 安卓 困难处理记录 腾讯IM和厂商离线推送难题 点击离线推送无法唤醒APP启动页但某些Service服务和Application被启动pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !im…

百度地图如何获取瓦片图

百度地图如何获取瓦片图1.根据百度地图的经度和纬度来获取瓦片图的 x、y坐标值。 使用第三方javascript库,已经有牛人实现了。 tile-lnglat-transform-es6 如果想表现一下自己很牛,也可以自己去根据思路是实现。 使…

Codeforces Round 1051 (Div 2)

cf1051 Div2 ABCD1D2E题解Problem - A. All Lengths Subtraction 思路: 我们希望 n 和 n - 1 相邻,n - 1, n 和 n - 2 相邻 ... 不断往外扩展 所以我们可以维护 l 和 r 表示当前扩展到了哪里 通过判断下一个数是否和…

scheduleAtFixedRate

定时任务中的scheduleAtFixedRate方法 在Java的并发编程中,scheduleAtFixedRate是ScheduledExecutorService接口中的一个方法,用于在给定的初始延迟后,以固定的周期执行所提交的任务。这个方法非常适合需要多次执行…

redis-string类型常用命令

redis-string类型常用命令String类型value是Redis中最常用,最基本的类型,String类型的value可以存放任意类型数据,包括数值型,二进制的图片,音频,视频,序列化对象等等。一个String类型的value最大时521M。 1.se…

CRMEB标准版PHP核销功能深度解析,附权限配置技巧

订单核销,使用核销码或立即核销进行核销 核销订单:用户购买商品时选择到店自提的订单。到店后需要出示核销码以供核销。 1、收入核销码核销 订单—>订单管理—>立即核销在订单列表页,点击左上角订单核销按钮,…

一文详细说明大模型安全评估要怎么做

一文详细说明大模型安全评估要怎么做《网络安全技术 生成式人工智能服务安全基本要求》 《基本要求》是大模型安全总纲性文件,提纲挈领地指出模型备案上线所需具备的基础条件,是大模型备案技术性指导文件《生成式人工…

apache doris 和 clickhouse的区别

Apache Doris 和 ClickHouse 均为 MPP(大规模并行处理)架构的列式存储 OLAP 数据库,核心定位都是解决海量数据下的高性能分析查询场景,但二者在技术设计、生态适配、适用场景等维度存在显著差异。以下从 核心架构、…

Python numba jit加速计算

安装pip install numba使用示例import timefrom numba import jit# 原始函数 def python_sum(n):total = 0for i in range(n):total += ireturn total# Numba 加速版本 @jit(nopython=True) def numba_sum(n):total = …

人机协作开发新体验:花两天时间与Cursor共同打造一个微信小程序

前言 在过去的几天里,我完成了一个完整的微信小程序项目——双色球机选应用。 这个项目的独特之处在于,所有的代码编写工作都是由 Cursor 完成的,而我主要负责需求分析、功能规划和调试测试。项目概述 应用功能 我开…

OEC-Turbo刷群晖Armbian流程记录

记录OEC-Turbo的刷机流程,为以后反复折腾做参考。 设备版本:OEC L2.0,不清楚1.0和2.0的区别 系统:Windows 11 准备工具瑞芯微驱动 瑞芯微烧录工具 Loader文件 固件 镊子 Type-C数据线工具下载链接:https://pan.qu…

01_网络分层模型

一、OSI 七层网络模型 所谓七层就是基于 URL 等应用层信息的负载均衡,四层就是基于 IP + 端口的负载均衡,同样的还有基于二层 MAC 地址,三层 IP 地址的负载均衡。 而 OSI(Open System Interconnection,开放式通信互…

SaaS 是什么?一文带你看懂 SaaS 与传统软件的区别

SaaS 发音类似于「萨斯」,是 Software as a Service 的缩写,直译过来就是「软件即服务」。你可以这样理解: 在 SaaS 模式下,软件变得和水电气很相似,你只需要每月缴纳固定的费用即可享受服务。再举个比较具体的例…

FreeCAD-即时入门-全-

FreeCAD 即时入门(全)原文:zh.annas-archive.org/md5/ba46ce5f33da4fa68df84701f1baaf8a 译者:飞龙 协议:CC BY-NC-SA 4.0前言 FreeCAD 是一个面向工程世界的通用建模工具。与为动画师和艺术家设计的其他建模工具…

UOS统信服务器操作系统V20(1070)安装mysql8.0.41(建议安装glibc2.28版本)

环境:OS:UOS Server 20 统信服务器操作系统V20(1070)mysql:8.0.41 glib.2.17 操作系统下载https://www.chinauos.com/resource/download-server查看系统glibc版本[root@localhost yum.repos.d]# ldd --versionldd (GNU…

MyEMS:重新定义人与能源的关系 —— 一场藏在数据里的能源管理革命

能源,这个推动现代文明运转却始终隐形的主角,正通过数字技术与我们建立全新的对话方式。MyEMS作为开源能源管理系统,正在悄然引领这场变革——它不仅改变我们管理能源的方式,更在重新定义人与能源之间的关系。 从被…

TJOI2007--线段

题目传送门代码点击查看代码 #include<bits/stdc++.h> using namespace std; const int N=2e4+10; int n; int l[N],r[N],len[N]; int dp[N][2]; //dp[i][0]表示停留在本行左端点 //那么就要到右端点在再回到左…

KEITHLEY 数字万用表 能测试电阻吗

KEITHLEY 数字万用表 能测试电阻吗KEITHLEY 数字万用表(DMM, Digital Multimeter) 都具备 电阻测量功能。 🔹 一般 KEITHLEY 的 DMM(如 DMM6500、DMM7510、2000/2100 系列 等)都有以下功能:直流电压 DCV交流电压…

PolarFire SoC 移植 xprintf

PolarFire SoC 移植 xprintf1、xprintf 简介ELM - Embedded String Functions xprintf 是一个紧凑的字符串 I/O 库。它非常适合程序内存不足的微型微控制器来执行常规 printf 功能。推荐用途是:将格式化的字符串写入 …