SpringSecurity——基于角色权限控制和资源权限控制

目录

基于角色权限控制

1.1 自定义 UserDetailsService

1.2 加载用户角色

1.3. 给角色配置能访问的资源(使用切面拦截,使用注解)

总结

资源权限控制

2.2. 需要有一个用户;(从数据库查询用户)

2.2 基于权限标识符的资源控制

自定义无权限页面:


基于角色权限控制

1.1 自定义 UserDetailsService

在 Spring Security 中,用户信息通常需要实现 UserDetails 接口。这里,我们定义了一个自定义的 TUser 类,并实现了 UserDetails 接口。

/*** 用户表* t_user*/
@Data
public class TUser implements UserDetails, Serializable {/*** 主键,自动增长,用户ID*/private Integer id;/*** 登录账号*/private String loginAct;/*** 登录密码*/private String loginPwd;/*** 用户姓名*/private String name;/*** 用户手机*/private String phone;/*** 用户邮箱*/private String email;/*** 账户是否没有过期,0已过期 1正常*/private Integer accountNoExpired;/*** 密码是否没有过期,0已过期 1正常*/private Integer credentialsNoExpired;/*** 账号是否没有锁定,0已锁定 1正常*/private Integer accountNoLocked;/*** 账号是否启用,0禁用 1启用*/private Integer accountEnabled;/*** 创建时间*/private Date createTime;/*** 创建人*/private Integer createBy;/*** 编辑时间*/private Date editTime;/*** 编辑人*/private Integer editBy;/*** 最近登录时间*/private Date lastLoginTime;private static final long serialVersionUID = 1L;/*** 用户的角色list*/@JsonIgnoreprivate List<TRole> tRoleList;/*** 用户的权限标识符*/@JsonIgnoreprivate List<TPermission> tPermissionsList;//-----------------实现UserDetails当中相关的方法(7个)--------------------@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {Collection<GrantedAuthority>  authorities = new ArrayList<>();// 角色权限控制for (TRole tRole : this.tRoleList) {// 角色的名称必须以ROLE_开头authorities.add(new SimpleGrantedAuthority("ROLE_"+tRole.getRole()));}return authorities;}@JsonIgnore@Overridepublic String getPassword() {return this.loginPwd;}@Overridepublic String getUsername() {return this.loginAct;}@Overridepublic boolean isAccountNonExpired() {return this.accountNoExpired == 1;}@Overridepublic boolean isEnabled() {return this.accountEnabled == 1;}@Overridepublic boolean isCredentialsNonExpired() {return this.credentialsNoExpired == 1;}@Overridepublic boolean isAccountNonLocked() {return this.accountNoLocked == 1;}
}

通过自定义的 CustomUserDetailsService,我们可以在用户登录时,从数据库中加载用户信息:

@Service
public class CustomUserDetailsService implements UserDetailsService {@Autowiredprivate UserRepository userRepository;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {// 从数据库查询用户TUser user = userRepository.findByUsername(username);if (user == null) {throw new UsernameNotFoundException("User not found");}// 返回自定义的 UserDetails 对象return user;}
}

说明:此处的 TUser 类需要实现 Spring Security 的 UserDetails 接口,并重写其中的方法,其中最关键的便是 getAuthorities() 方法。 

1.2 加载用户角色

用户的角色通常保存在数据库中(例如通过 t_rolet_user_rolet_user 三个表的多对多关系实现)。在用户成功认证后,我们需要为其加载角色信息,并在 TUser 对象中设置角色列表(例如 tRoleList)。

SQL 查询语句如下:

SELECT tr.*
FROM t_role tr
LEFT JOIN t_user_role tur ON tr.id = tur.role_id
LEFT JOIN t_user tu ON tu.id = tur.user_id
WHERE tu.id = #{userId}

在获取角色列表后,需要重写 getAuthorities() 方法,将角色转换为 Spring Security 的 GrantedAuthority 对象由于 Spring Security 要求角色名称以 "ROLE_" 为前缀,我们在转换时进行拼接:

// TUser类继承了UserDetails
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {Collection<GrantedAuthority> authorities = new ArrayList<>();for (TRole tRole : this.tRoleList) {// 角色名称必须以 "ROLE_" 为前缀authorities.add(new SimpleGrantedAuthority("ROLE_" + tRole.getRole()));}return authorities;
}

在这里,我们通过 SimpleGrantedAuthority 将每个角色的名称转化为 Spring Security 所要求的权限标识。 SimpleGrantedAuthority 是GrantedAuthority的一个实现类)

在下面的示例中,我们进一步展示了如何在用户登录时加载角色并返回完整的用户信

@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {private final TUserMapper userMapper;private final TRoleMapper tRoleMapper;/*** 该方法会在 Spring Security 框架登录时调用* @param username* @return* @throws UsernameNotFoundException*/@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {// 通过用户名查询数据库TUser user = userMapper.selectByLoginAct(username);if (user == null){throw new UsernameNotFoundException("用户不存在");}// 查询该用户的角色列表(一个用户可能有多个角色)List<TRole> tRoleList = tRoleMapper.selectByUserId(user.getId());user.setTRoleList(tRoleList);return user; // TUser 实现了 UserDetails 接口,包含所有必须字段}
}

当你调用了user.setTRoleList(tRoleList)之后,其实只是将查询到的角色列表赋值给了TUser对象的属性tRoleList。而在getAuthorities()方法中,Spring Security会调用此方法来获取该用户所拥有的权限。具体过程如下:

  1. 赋值角色列表
    当调用setTRoleList(tRoleList)后,TUser对象内部的tRoleList属性中保存了所有该用户对应的角色信息(例如:角色名、角色标识等)。

  2. 转换为GrantedAuthority
    getAuthorities()方法中,通过遍历tRoleList中的每一个TRole对象,并使用new SimpleGrantedAuthority(tRole.getRole())将每个角色转换成一个GrantedAuthority对象。这里的SimpleGrantedAuthority是Spring Security中用于表示权限的一个简单实现。

  3. 返回权限集合
    最后将所有转换后的GrantedAuthority对象添加到一个集合中,并返回这个集合。Spring Security在后续的认证和授权过程中,会根据这个集合来判断用户是否具备相应的访问权限。

这个转换一般发生在用户成功认证后,Spring Security 构建认证对象(例如 UsernamePasswordAuthenticationToken)的时候。在这个过程中:

  • 认证阶段:当用户通过 loadUserByUsername 方法加载用户信息后,返回的 TUser 对象中包含了角色列表。
  • 构建 Authentication 对象:Spring Security 在构造认证对象时会调用 getAuthorities() 方法,从而将用户的角色转换为权限集合。
  • 授权检查时:在后续的请求处理中,系统会根据这个权限集合进行授权判断,决定是否允许访问特定资源

1.3. 给角色配置能访问的资源(使用切面拦截,使用注解)

在 Spring Security 中,角色权限控制常通过注解来实现。我们可以在方法上使用 @PreAuthorize@PostAuthorize 注解来进行权限控制:

  • @PreAuthorize:在方法调用前进行权限验证,常用。
  • @PostAuthorize:在方法调用后进行权限验证,较少使用。

首先,确保启用方法级安全性。在 Spring Boot 配置类中添加 @EnableMethodSecurity 注解。

@Configuration
@EnableMethodSecurity(prePostEnabled = true)
public class SecurityConfig {// 配置其他安全设置
}

然后,你可以使用 @PreAuthorize@PostAuthorize 来控制方法的访问:


@RestController
public class ClueController {@RequestMapping("/api/clue/index")public String index(){return "index";}@RequestMapping("/api/clue/menu")@PreAuthorize(value = "hasRole('saler')")public String clueMenu(){return "clueMenu";}@RequestMapping("/api/clue/child")@PreAuthorize(value = "hasRole('saler')")public String clueMenuChild(){return "clueMenuChild";}@RequestMapping("/api/clue/del")@PreAuthorize(value = "hasRole('admin')")public String clueDel(){return "clueDel";}/*** 'admin','manager' 其中任意一个角色都可以访问* @return*/@RequestMapping("/api/clue/export")@PreAuthorize(value = "hasAnyRole('admin','manager')")public String clueExport(){return "clueExport";}
}

在方法上添加这些注解后,Spring Security 会自动根据当前用户的角色来进行验证,确保只有符合条件的用户能够访问指定的资源。

总结

  • 查询用户:通过自定义 UserDetailsService 从数据库加载用户信息。
  • 配置用户角色:通过 SQL 查询联合 t_rolet_user_rolet_user 表来获取用户的角色。
  • 配置资源访问权限:使用 @PreAuthorize@PostAuthorize 注解来控制方法访问权限。

通过以上步骤,你可以实现基于角色的权限控制,从而确保不同角色的用户能够访问他们有权限访问的资源。

资源权限控制

资源是什么?

资源就是我们的controller的http接口;

2.2. 需要有一个用户;(从数据库查询用户)

TUser user =  userMapper.selectByLoginAct(username);

2.2 基于权限标识符的资源控制

除了角色控制之外,还可以通过权限标识符(例如 clue:listclue:add 等)来实现更细粒度的资源控制。具体实现步骤如下:

扩展用户信息:在 TUser 类中增加权限列表属性,例如:

private List<TPermission> tPermissionsList;

加载用户权限:通过 SQL 查询语句,从关联的权限表中获取用户的权限标识符。示例 SQL 如下:

  <select id="selectByUserId" resultType="com.gege.codepermission.entity.TPermission"parameterType="java.lang.Integer">select tp.*from t_permission tpleft join  t_role_permission trp on tp.id = trp.permission_idleft join t_role tr on tr.id = trp.role_idleft join t_user_role tur on tur.role_id = tr.idleft join t_user tu on tu.id = tur.user_idwhere tu.id = #{userId} and tp.type = 'button'</select>

基于权限标识符配置资源访问

使用 @PreAuthorize 和 @PostAuthorize 注解

首先,在 Spring Boot 配置类中开启方法级安全控制:

@Configuration
@EnableMethodSecurity(prePostEnabled = true)
public class SecurityConfig {// 其他安全配置
}

通过 @PreAuthorize 注解检查用户是否具备某一权限:

@RestController
public class ClueController {/*** 资源权限控制:访问线索列表需要具备权限标识符 clue:list* 权限标识符通常采用 “模块名:功能名” 的格式*/@RequestMapping("/api/clue/list")@PreAuthorize("hasAuthority('clue:list')")public String clueList(){return "clueList";}/*** 资源权限控制:访问添加线索页面需要具备权限标识符 clue:add*/@RequestMapping("/api/clue/input")@PreAuthorize("hasAuthority('clue:add')")public String clueInput(){return "clueInput";}/*** 资源权限控制:删除线索需要具备权限标识符 clue:del*/@RequestMapping("/api/clue/del")@PreAuthorize("hasAuthority('clue:del')")public String clueDel(){return "clueDel";}/*** 资源权限控制:导出线索时,具备任意一个权限即可,例如:* - clue:export* - clue:download*/@RequestMapping("/api/clue/export")@PreAuthorize("hasAnyAuthority('clue:export','clue:download')")public String clueExport(){return "clueExport";}
}

注意hasRole 不同,hasAuthority 不会自动添加前缀,因此权限标识符应与数据库中配置的保持一致。

自定义无权限页面:

直接在resources/static/error下面配置页面即可

Spring Boot 内置了一个默认的错误处理机制。当应用返回错误状态码(例如 403)时,Spring Boot 会自动查找与该状态码匹配的错误页面。如果在 resources/static/error 下存在对应名称(如 403.html)的页面,系统就会直接返回该静态页面,而无需额外配置或编写代码。这种设计符合 Spring Boot “约定优于配置” 的理念,简化了错误处理的配置过程。

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

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

相关文章

【MySQL】表的约束

目录 零、前言一、空属性二、默认值三、列描述四、zerofill五、主键六、自增长七、唯一键八、外键结尾 零、前言 表中一定要有各种约束&#xff0c;通过约束来让用户未来插入的数据是符合要求的。约束的本质就是通过计算反过来要求用户插入正确的数据。所以站在MySQL的角度上来…

SQLMesh系列教程:SQLMesh虚拟数据环境

各种工具都已将软件工程实践引入到数据工程中&#xff0c;但仍有差距存在&#xff0c;尤其是在测试和工作流等领域。SQLMesh 的目标是在这些领域开辟新的天地&#xff0c;解决像 dbt 这样的竞争产品尚未提供强大解决方案的难题。在这篇文章中&#xff0c;我将对 SQLMesh 进行简…

基于Babylon.js的Shader入门之五:让Shader支持法线贴图

如果一个比较平坦的物体表面要添加更多的凹凸细节&#xff0c;但是我们又不想通过建模实现&#xff0c;这时候法线贴图就派上用场了。法线贴图是通过与灯光的交互来让一个平坦表面造成凹凸效果假象的&#xff0c;在基于Babylon.js的Shader入门之四&#xff1a;让Shader支持基础…

活码在实际操作中的具体场景有哪些?怎么应用?

当传统二维码因“内容固定、无法追踪、流量拥堵”等问题逐渐失效时&#xff0c;活码正在成为企业破解运营痛点的关键工具。 无论是需要实时更新内容的线下物料&#xff0c;还是面临用户分流压力的线上客服&#xff0c;动态二维码都能通过“一码多用、灵活配置”的特性&#xf…

极空间NAS部署gitea教程

极空间NAS部署gitea步骤教程 背景1. 准备镜像1.1 极空间官方1.2 Win系统docker再上传1.3 镜像转录 2. MySql配置2.1 容器配置2.2 命令行配置 3. gitea配置3.1 容器配置3.2 打开网页3.3 网页配置安装 参考资料 背景 极空间Nas和别的Nas不同的地方就在于&#xff0c;他不是那种标…

Wireshark:在 显示过滤器中“加入条件”过滤后,出现其他类型的数据包,为什么?

一、 在Wireshark中使用“tcp协议”过滤后&#xff0c;仍出现TLSv1.2协议的数据包&#xff0c;原因如下&#xff1a; 1. ‌协议层次关系‌ ‌TCP是传输层协议‌&#xff0c;而‌TLS属于应用层协议‌&#xff0c;后者直接运行于TCP之上‌28。因此&#xff0c;所有TLS流量&…

【医学影像 AI】大型语言模型生成 ROP 患者信息材料的能力

【医学影像 AI】大型语言模型生成 ROP 患者信息材料的能力 0. 论文简介0.1 基本信息0.2 摘要 1. 引言2. 材料与方法2.1 大语言模型的使用2.2 可读性标准2.3 统计分析 3. 结果3.1 Bezirci-Yılmaz可读性评分3.2 Ateşman可读性评分3.3 全面性评分3.4 准确性评分 4. 讨论4.1 可读…

设计模式(行为型)-策略模式

目录 定义 类图 角色 角色详解 Strategy&#xff08;抽象策略类&#xff09;​ Context&#xff08;环境类 / 上下文类&#xff09;​ ConcreteStrategy&#xff08;具体策略类&#xff09;​ 优缺点 优点​ 缺点​ 使用场景 类行为差异场景​ 动态算法选…

服装零售行业数字化时代的业务与IT转型规划P111(111页PPT)(文末有下载方式)

服装零售行业数字化时代的业务与IT转型规划P111 详细资料请看本解读文章的最后内容。 随着数字化技术的迅猛发展&#xff0c;服装零售行业正经历着前所未有的变革。本文将对《服装零售行业数字化时代的业务与IT转型规划P111》进行详细解读&#xff0c;探讨未来几年内该行业的…

【大语言模型_6】mindie启动模型错误整理

一、启动报 [hccl_runner.cpp:141] AllGatherHcclRunner:0 HcclCommInitRootInfo fa il, error:2, rank:0, rankSize:2 背景&#xff1a;运行DeepSeek-R1-Distill-Qwen-14B模型&#xff0c;在2张300 P卡可以运行&#xff0c;单独一张启动报以上错误。 问题分析&…

STM32F429单片机FMC接口驱动TFT LCD和SDRAM

1、FMC接口介绍 FMC 接口&#xff08;即可变存储控制器&#xff09;是一种用于管理外部存储器的外设接口&#xff0c;支持多种类型的存储器&#xff0c;主要分为三大类&#xff1a;NOR/SRAM/PSRAM设备&#xff08;TFTLCD相当于SRAM&#xff09;、NOR FLASH/NAND FLASH/PC卡设备…

ollama不安装到c盘,安装到其他盘

ollama 安装包默认安装到c盘&#xff0c;安装程序并没有提供选择文件夹安装功能&#xff0c;本来c盘就快满了&#xff0c;下几个模型c盘都快爆了&#xff0c;如何将ollma安装到其他盘呢&#xff1f; ollama 默认安装位置 C:\Users\Admin\.ollama 是 Ollama 用来放大模型的文件夹…

java项目之基于ssm的少儿编程在线培训系统(源码+文档)

项目简介 少儿编程在线培训系统实现了以下功能&#xff1a; 用户信息管理&#xff1a; 用户信息新增 用户信息修改 教师信息管理&#xff1a; 教师信息添加 教师信息删除 教师信息修改 课程信息管理&#xff1a; 课程信息添加 课程信息修改 课程信息删除 课程类型管理&…

Cinema4D安装及基本操作

一、简介 Cinema 4D&#xff08;C4D&#xff09;是德国 Maxon Computer 开发的 3D 软件&#xff0c;具备强大的建模、动画、材质、渲染功能&#xff0c;以易用高效著称&#xff0c;广泛应用于影视、游戏、设计等领域&#xff0c;是行业内主流 3D 创作工具。 二、安装 1.下载安…

为什么TCP需要三次握手?一次不行吗?

文章目录 1. 三次握手的过程2. 为什么需要三次握手&#xff1f;3. 握手过程中每一步的具体作用4. 简单比喻5. 为什么是三次握手&#xff0c;而不是两次或四次&#xff1f;6. 三次握手中的序列号有什么作用&#xff1f;7. 总结 1. 三次握手的过程 三次握手是建立 TCP 连接的过程…

大数据在人力资源管理中的洞察与决策

hello宝子们...我们是艾斯视觉擅长ui设计和前端数字孪生、大数据、三维建模、三维动画10年经验!希望我的分享能帮助到您!如需帮助可以评论关注私信我们一起探讨!致敬感谢感恩! 在数字化转型浪潮中&#xff0c;人力资源管理&#xff08;HRM&#xff09;正经历着前所未有的变革。…

让vscode远程开发也可以图形显示

目录 0. 摘要1. 保存查看2. jupyter内置inline渲染3. jupyter浏览器4. matplot修改后端5. SSH X11转发[※]6. 参考 0. 摘要 vscode登录远程服务器进行开发遇到图形显示需求时&#xff0c;该怎么处理&#xff1f;一般有几种方式&#xff1a; 保存下来查看jupyter内置的inline图…

Blender制作次表面材质

效果: 主要用沃罗诺伊纹理做出云絮感 然后EV开启次表面设置

服务器数据恢复—服务器raid故障导致上层分区不可用的数据恢复案例

服务器数据恢复环境&故障&#xff1a; 一台服务器中有一组由三块SAS硬盘组建的raid阵列。服务器上部署的数据库存储在D分区&#xff0c;数据库备份存储在E分区。 服务器上一块硬盘指示灯显示红色。D分区不可识别。E分区虽然可以识别&#xff0c;但是E分区拷贝文件报错。 管…

PyTorch PINN实战:用深度学习求解微分方程

神经网络技术已在计算机视觉与自然语言处理等多个领域实现了突破性进展。然而在微分方程求解领域&#xff0c;传统神经网络因其依赖大规模标记数据集的特性而表现出明显局限性。物理信息神经网络(Physics-Informed Neural Networks, PINN)通过将物理定律直接整合到学习过程中&a…