Spring Boot 3 集成 Spring Security(2)授权
文章目录
- 授权
- 配置 SecurityFilterChain
- 基于注解的授权控制
- 自定义权限决策
在《Spring Boot 3 集成 Spring Security(1)》中,我们简单实现了 Spring Security 的认证功能,通过实现用户身份验证来确保系统的安全性。Spring Security的重要核心功能功能是“认证”和“授权”。接下来我们将深入了解授权机制,看如何控制用户在系统中可以访问的资源和操作。在 Spring Security 中,授权主要基于角色和权限的概念进行控制。
角色(Role):通常用来定义一组权限,用于定义用户身份的层级。比如 ADMIN(ROOT) 角色可能包含管理用户、查看日志等权限。
权限(Authority):具体的操作或资源访问权,则更细粒度地控制用户具体能做什么操作。比如 READ_PRIVILEGES、WRITE_PRIVILEGES 等。
Spring Security 提供了基于角色和权限的访问控制机制,使我们可以轻松管理系统中的授权逻辑。
授权
要实现授权,我们需要在 Spring Security 的配置类中定义用户的角色和访问策略。
代码实现过程:
- 定义两个用户分别赋予角色 admin -> ROOT、user -> USER
- 定义Controller 使用不同的用户登录访问接口 AdminController、UserController、SecuredController
- 登录不同账户验证授权
配置 SecurityFilterChain
package cn.harry.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
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.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;/*** @author harry*/
@Configuration
@EnableWebSecurity()
@EnableMethodSecurity(securedEnabled = true) // 开启方法级别的权限控制
public class SecurityConfig {@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {http.authorizeHttpRequests(auth -> auth// 公开访问.requestMatchers("/").permitAll()// 只有 ROOT 角色可以访问 /admin 目录下的资源.requestMatchers("/admin/**").hasRole("ROOT")// USER 和 ROOT 角色都可以访问 /user 目录下的资源.requestMatchers("/user/**").hasAnyRole("ROOT", "USER")// 其他接口需认证.anyRequest().authenticated())// 开启基于表单的登录.formLogin(Customizer.withDefaults())
// // 开启注销功能
// .logout(Customizer.withDefaults())
// // 开启 HTTP Basic 认证
// .httpBasic(Customizer.withDefaults())
// // 开启 CSRF 防护
// .csrf(Customizer.withDefaults())
// // 开启跨域资源共享
// .cors(Customizer.withDefaults());return http.build();}@Beanpublic UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) {InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();// 创建用户UserDetails admin = User.builder().username("admin").password(passwordEncoder.encode("123456"))// 设置用户角色为ROOT.roles("ROOT").build();UserDetails user = User.builder().username("user").password(passwordEncoder.encode("123456"))// 设置用户角色为USER.roles("USER").build();// 将用户添加到内存中manager.createUser(admin);manager.createUser(user);return manager;}@Beanpublic PasswordEncoder passwordEncoder() {// 使用 BCrypt 进行密码加密return new BCryptPasswordEncoder();}
}
代码说明
authorizeHttpRequests()
:用于定义 URL 路径的访问权限。
requestMatchers("/admin/**").hasRole("ROOT")
:指定 /admin/** 下的所有路径都只有 ADMIN 角色的用户可以访问。
requestMatchers("/user/**").hasAnyRole("USER", "ROOT")
:允许 USER 和 ROOT 角色访问 /user/** 下的资源。
anyRequest().authenticated()
:表示系统中的其他请求都需要用户登录后才可以访问。
在 Spring Security 中,角色是权限的一种特殊形式。实际上,hasRole() 是基于 hasAuthority() 实现的。当我们定义角色时,Spring Security 会自动为角色加上前缀
ROLE_
,所以hasRole("ADMIN")
实际上是hasAuthority("ROLE_ADMIN")
。
基于注解的授权控制
除了在配置类中定义访问策略,Spring Security 还支持使用注解来控制方法的访问权限。常见的注解包括 @PreAuthorize
和 @Secured
。
- 使用 @PreAuthorize 注解
@PreAuthorize 注解可以用于方法级别的权限控制。它可以在方法执行之前检查用户的权限。
@Slf4j
@RestController
public class AdminController {@GetMapping("/admin/info")@PreAuthorize("hasRole('ROOT')") // 只有 ADMIN 角色才能访问public User adminInfo() {// 获取当前登录的用户信息User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();log.info("当前登录的用户信息:{}", user.toString());return user;}
}
@Slf4j
@RestController
public class UserController {@GetMapping("/user/info")public User getUserInfo() {User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();log.info("当前登录的用户信息:{}", user.toString());return user;}@GetMapping("/user/info2")@PreAuthorize("hasRole('USER')") // 只有 USER 角色才能访问public User getUserInfo2() {User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();log.info("当前登录的用户信息:{}", user.toString());return user;}
}
使用 user 用户访问 /admin/info
时提示无权限,使用 admin 访问则正常打印用户信息。
- 使用 @Secured 注解
@Secured 注解也可以实现类似的功能,限制方法访问的权限。
注意:使用
@Secured
注解时,需要再 SecurityConfig 文件中添加@EnableMethodSecurity(securedEnabled = true) // 开启方法级别的权限控制
,EnableMethodSecurity源码中看出@Secured
默认时关闭状态。
创建一个SecuredController
,写一个@Secured("ROLE_USER")
才能访问的接口。
@Slf4j
@RestController
public class SecuredController {/*** 使用 `@Secured`注解时,需要再 SecurityConfig 文件中添加`@EnableMethodSecurity(securedEnabled = true) // 开启方法级别的权限控制`* 访问 /secured 需要有 ROLE_USER 权限*/@GetMapping(value = "/secured")@Secured("ROLE_USER")public User hello() {User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();log.info("当前登录的用户信息:{}", user.toString());return user;}
}
自定义权限决策
在某些场景中,我们可能需要更加灵活的权限控制。在Spring Security中,@PreAuthorize、@PostAuthorize等注解支持SpEL表达式。如果要在表达式中调用其他对象的方法,需要在方法名前加上对象名。例如,@ss.hasPermission('monitor:operlog:list')
,其中ss是Spring容器中的一个对象名,hasPermission则是该对象中的方法
- 可以通过定义一个自定义的
PermissionService
类,并在其中实现权限验证逻辑。
@Service("ss")
public class PermissionService {public Boolean hasPermission(String... permissions) {if (StringUtils.isEmpty(permissions)) {return false;}// 获取当前用户的所有权限List<String> perms = SecurityUtils.getUserDetails().getAuthorities().stream().map(GrantedAuthority::getAuthority).toList();// 判断当前用户的所有权限是否包含接口上定义的权限return perms.contains(CommonConstant.ALL_PERMISSION) || Arrays.stream(permissions).anyMatch(perms::contains);}}
调用方法:
@Operation(summary = "list 分页列表")@GetMapping(value = "/list")@PreAuthorize("@ss.hasPermission('monitor:operlog:list')")public R<IPage<SysOperationLog>> list(Page<SysOperationLog> page, SysOperationLog sysOperationLog) {return R.success(sysOperationLogService.page(page, Wrappers.lambdaQuery(sysOperationLog).orderByDesc(SysOperationLog::getCreateTime)));}
授权是确保系统安全的重要组成部分,它能帮助我们在系统中根据用户的身份和角色对资源访问进行精细化控制。通过 Spring Security 提供的简单配置和注解支持,我们可以非常灵活地实现授权控制。
相关文章:
Spring Boot 3 集成 Spring Security(2)授权
文章目录 授权配置 SecurityFilterChain基于注解的授权控制自定义权限决策 在《Spring Boot 3 集成 Spring Security(1)》中,我们简单实现了 Spring Security 的认证功能,通过实现用户身份验证来确保系统的安全性。Spring Securit…...
【开篇】.NET开源 ORM 框架 SqlSugar 系列
01. 前言 ☘️ 1.1 什么是ORM? 对象-关系映射(Object-Relational Mapping,简称ORM),面向对象的开发方法是当今企业级应用开发环境中的主流开发方法,关系数据库是企业级应用环境中永久存放数据的主流数据存储系统。对…...
参加面试被问到的面试题
1.在程序中如何开启事务? 在Java中,使用JDBC(Java Database Connectivity)与数据库交互时,你可以使用Connection对象的setAutoCommit方法来控制事务。默认情况下,autoCommit是开启的,这意味着每…...
第29天:安全开发-JS应用DOM树加密编码库断点调试逆向分析元素属性操作
时间轴: 演示案例: JS 原生开发-DOM 树-用户交互 DOM:文档操作对象 浏览器提供的一套专门用来操作网页代码内容的功能,实现自主或用户交互动作反馈 安全问题:本身的前端代码通过 DOM 技术实现代码的更新修改ÿ…...
react 的路由功能
1. 安装依赖 pnpm add react-router-dom 2. 基本的路由设置(BrowserRouter) 在 main.tsx 入口文件中使用BrowserRouter组件来包裹整个应用。它会监听浏览器的 URL 变化。 import { StrictMode } from "react";import { createRoot } from …...
SurfaceFlinger学习之一:概览
SurfaceFlinger 是 Android 系统中负责合成和显示屏幕内容的关键系统服务,它运行在一个专用的进程中 (system/bin/surfaceflinger)。它的主要职责是将不同应用程序的绘制内容(即窗口或表面)组合起来,通过硬件抽象层(HA…...
Qt关于窗口一直调用paintEvent的踩坑实录
首先看以下代码: void ItemBlockWidget::paintEvent(QPaintEvent *ev) {// 先调用父类的 paintEvent 以执行默认绘制行为QWidget::paintEvent(ev);qDebug()<<"ItemBlockWidget重绘";QStyleOption opt;opt.initFrom(this);QPainter p(this);style()…...
C++11: STL之bind
C11: STL之bind 引言可调用对象的绑定绑定普通函数绑定静态函数绑定类成员函数绑定仿函数绑定Lambda 占位符std::placeholders的应用嵌套绑定参数重排序结合 STL 算法占位符传递到嵌套函数混合占位符与默认值复杂占位符组合 std::bind的原理std::bind 的设计思路简化实现示例 B…...
在线音乐播放器 —— 测试报告
自动化脚本源代码:Java: 利用Java解题与实现部分功能及小项目的代码集合 - Gitee.com 目录 前言 一、项目简介 1.项目背景 2.应用技术 (1)后端开发 (2)前端开发 (3)数据库 二、项目功能…...
等保测评讲解:安全管理中心
在数字化转型的背景下,网络安全的重要性愈发凸显,而作为中国边疆大省的黑龙江,其网络安全建设更是不可忽视。等保测评,即信息安全等级保护测评,是确保信息系统安全的关键环节。本文将详细讲解黑龙江等保测评中的安全管…...
vue3表单输入相关修饰符使用
在 Vue 3 中,.lazy、.number 和 .trim 是用于 v-model 指令的修饰符,它们可以帮助你在双向绑定时进行特定的处理。 1. .lazy 修饰符 .lazy 修饰符表示只在 input 事件之后触发更新,即输入框的内容发生变化后,只有在用户**失去焦…...
CSS笔记(二)类名复用
这里我通过两张不同位置的卡片来实现效果 代码 <!DOCTYPE html> <html><head><style>/*设置画布*/body{/* 方便排列与对齐*/display: flex; /*画布布满整个窗口*/height: 100vh;/*水平居中*/justify-content: center;/*垂直居中*/align-items: cente…...
TCP三次握手与四次挥手(TCP重传机制,2MSL)超详细!!!计算机网络
本篇是关于3次握手和四次挥手的详细解释~ 如果对你有帮助,请点个免费的赞吧,谢谢汪。(点个关注也可以!) 如果以下内容需要补充和修改,请大家在评论区多多交流~。 目录 1. TCP头部: 2. 三次握手…...
LCR 006. 两数之和 II - 输入有序数组
一.题目: LCR 006. 两数之和 II - 输入有序数组 - 力扣(LeetCode) 二.我的原始解法-暴力解法超时: class Solution: def twoSum(self, numbers: List[int], target: int) -> List[int]: # 暴力解法 result [] for i in rang…...
网络安全在现代企业中的重要作用
网络安全是这个数字时代最令人担忧的事情之一。对技术的依赖性越来越强,使其同时面临多种网络威胁。其声誉和法律后果的大幅下降可能归因于一次妥协。 这使得良好的网络安全成为所有企业的选择和必需品。本文介绍了网络安全的重要性、企业中常见的网络威胁以及公司…...
关于 EKS Bottlerocket AMI 版本与 Karpenter 配置的说明
问题1: Bottlerocket AMI 版本问题 之前,后端团队发现在使用 Bottlerocket v1.26.2 AMI 版本时,存在某些问题。经过 Bottlerocket 团队调查,此行为是罕见的 race condition 导致的结果。 我们在环境中重现了此状况,并且关注到由于 kubelet device manager 的启动时间晚于 NVI…...
Python实现人生重开模拟器
目录 人生重开模拟器介绍 代码实现 打印初始界面 设置初始属性 设置角色性别 设置角色出生点 针对每一岁,生成人生经历 完整代码 人生重开模拟器介绍 人生重开模拟器 是之前比较火的一个小游戏,我们这里使用 Python 实现一个简化版的 人生重开模…...
java——Spring Boot的配置加载顺序和优先级
Spring Boot的配置加载顺序和优先级是确定应用程序如何读取和应用配置的关键。以下是对Spring Boot配置加载顺序和优先级的详细解释: 一、配置加载顺序 命令行参数: Spring Boot会首先加载命令行中指定的参数。这些参数可以通过在命令行中使用--keyval…...
【21-30期】Java技术深度剖析:从分库分表到微服务的核心问题解析
🚀 作者 :“码上有前” 🚀 文章简介 :Java 🚀 欢迎小伙伴们 点赞👍、收藏⭐、留言💬 文章题目:Java技术深度剖析:从分库分表到微服务的核心问题解析 摘要: 本…...
CSS:怎么把网站都变成灰色
当大家看到全站的内容都变成了灰色,包括按钮、图片等等。这时候我们可能会好奇这是怎么做到的呢? 有人会以为所有的内容都统一换了一个 CSS 样式,图片也全换成灰色的了,按钮等样式也统一换成了灰色样式。但你想想这个成本也太高了…...
开发一个基于MACOS M1/2芯片的Android 12的模拟器
产品需求:MuMu模拟器Pro_率先适配Apple M系列芯片的安卓模拟器 苹果M芯片专属:产品专为苹果M系列芯片设计,意味着它需要能够充分利用M系列芯片的性能优势。 安卓模拟器:产品是一个安卓模拟器,允许用户在Mac设备上运行…...
Flink 中 JDBC Connector 使用详解
1. 背景 在实时计算或离线任务中,往往需要与关系型数据库交互,例如 MySQL、PostgreSQL 等。Apache Flink 提供了 JDBC Connector,可以方便地将流式数据写入或读取数据库。 本文将介绍 Flink JDBC Connector 的基础用法、配置方法以及注意事…...
【Linux打怪升级记 | 报错02】-bash: 警告:setlocale: LC_TIME: 无法改变区域选项 (zh_CN.UTF-8)
🗺️博客地图 📍1、报错发现 📍2、原因分析 📍3、解决办法 📍4、测试结果 1、报错发现 装好了CentOS操作系统,使用ssh远程登陆CentOS,出现如下告警信息: bash: 警告:setlocale…...
未来已来?AI技术革新改变我们的生活
在21世纪的今天,人工智能(AI)不再是一个遥远的概念,而是逐渐渗透到我们生活的方方面面。从智能家居到自动驾驶汽车,从个性化推荐系统到医疗诊断辅助,AI技术正在以惊人的速度发展,并深刻地影响着…...
【Linux】进程的生命之旅——诞生、消逝与守候(fork/exit/wait)
🎬 个人主页:谁在夜里看海. 📖 个人专栏:《C系列》《Linux系列》《算法系列》 ⛰️ 一念既出,万山无阻 目录 📖一、进程创建 1.fork函数 📚高层封装特性 📚fork返回值 2.写时拷…...
使用vcpkg自动链接tinyxml2时莫名链接其他库(例如boost)
使用vcpkg自动链接tinyxml2时莫名链接其他库(例如boost) vcpkg的自动链接功能非常方便,但在某些情况下会出现过度链接的问题。 链接错误症状 以tinyxml2为例,程序中调用tinyxml2的函数后,若vcpkg中同时存在opencv和…...
【去毛刺】OpenCV图像处理基础:腐蚀与膨胀操作入门
在数字图像处理中,形态学操作是一种常用的技术,用于提取图像中的特定形状或特征。其中,腐蚀(Erosion)和膨胀(Dilation)是两种基本的形态学运算。本文将通过一个简单的例子来演示如何使用Python中…...
道可云人工智能元宇宙每日资讯|第三届京西地区发展论坛成功召开
道可云元宇宙每日简报(2024年11月27日)讯,今日元宇宙新鲜事有: 工信部等十二部门印发《5G规模化应用“扬帆”行动升级方案》 11月25日,工业和信息化部等十二部门印发《5G规模化应用“扬帆”行动升级方案》。《方案》…...
若依框架部署在网站一个子目录下(/admin)问题(
部署在子目录下首先修改vue.config.js文件: 问题一:登陆之后跳转到了404页面问题,解决办法如下: src/router/index.js 把404页面直接变成了首页(大佬有啥优雅的解决办法求告知) 问题二:退出登录…...
【ue5】UE5运行时下载视频/UE5 runtime download video(MP4)
插件还是老朋友。 节点的content type要打对。 (参照表:MIME 类型(MIME Type)完整对照表 - 免费在线工具) 结果展示:...
现在个人都在哪个网站做外贸/营销策划方案ppt
转自:http://www.matrix67.com/blog/archives/105 总结 P:能用多项式时间求解的问题NP:能用多项式时间验证的问题(但不知道能不能用多项式时间求解)。存在不属于NP类的问题,如:是否不存在哈密顿…...
织梦如何做网站/百度站长平台网页版
很多学校流行一种比较的习惯。老师们很喜欢询问,从某某到某某当中,分数最高的是多少。 这让很多学生很反感。 不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问。当然&…...
深圳营销型网站建设服务费用/百度账号购买网站
很多人说2017年是人工智能的元年,很多人工智能的产品、应用都在陆续落地。之所以人工智能兴起,是因为在这个网络飞速发展时代,数据量在发生着巨大的变化,从而计算速度也随之变化。只有有足够的数据量,才能将数据进行提…...
南宁网站设计图/扬州整站seo
从一个异常探索spring autowired 的原理参考文章: (1)从一个异常探索spring autowired 的原理 (2)https://www.cnblogs.com/FlyAway2013/p/7819091.html 备忘一下。...
制作动态网站用什么软件/南宁seo外包要求
修改uni-app 或者 小程序 的复选框和单选框的大小 在写表单的时候 总会遇到使用单选框或者复选框的时候 不管是uni-app 还是小程序 自带的总是太大了 对此我们可以修改其的css属性 修改其大小 1. 原始大小 复选框太大 页面整体不协调 2. 添加css 修改其大小 .size {transform:…...
做任务领佣金的网站源码/网站排名工具
目录 B树 树 二叉搜索树 红黑树(二叉搜索树的改进) B树(多叉搜索树的改进) B树 扩展 为什么存储用B树而不是红黑树 为什么说B树比B树更适合做操作系统的数据库索引和文件索引? B树的操作图解和代码 摘抄自&a…...