【SpringSecurity】之授权的使用案例

一、引言

1、什么是SpringSecurity授权

Spring Security授权是指基于Spring Security框架的访问控制过程。授权是指根据系统提前设置好的规则,给用户分配可以访问某一个资源的权限,用户根据自己所具有的权限,去执行相应操作。在Spring Security中,授权通常与身份验证一起使用,以确保只有经过身份验证的用户才能访问特定的资源。

Spring Security授权的核心概念包括:

  1. 认证:身份认证,即判断一个用户是否为合法用户的处理过程。Spring Security支持多种不同方式的认证,但无论使用哪种方式,都不会影响授权功能的使用。因为Spring Security很好地做到了认证和授权的解耦。
  2. 授权:访问控制,即控制谁能访问哪些资源。简单的理解就是根据系统提前设置好的规则,给用户分配可以访问某一个资源的权限,用户根据自己所具有的权限,去执行相应操作。

在Spring Security中,授权通常通过安全配置类来实现。这个类定义了哪些URL需要授权以及如何处理安全相关的异常。它使用过滤器链来拦截请求并检查用户的权限。如果用户通过了身份验证并且具有访问特定资源的权限,他们就可以成功访问该资源。

2、授权介绍

Spring Security 中的授权分为两种类型:

  • 基于角色的授权:以用户所属角色为基础进行授权,如管理员、普通用户等,通过为用户分配角色来控制其对资源的访问权限。
  • 基于资源的授权:以资源为基础进行授权,如 URL、方法等,通过定义资源所需的权限,来控制对该资源的访问权限。

Spring Security 提供了多种实现授权的机制,最常用的是使用基于注解的方式,建立起访问资源权限之间的映射关系。

其中最常用的两个注解是 @Secured@PreAuthorize@Secured 注解是更早的注解,基于角色的授权比较适用,@PreAuthorize 基于 SpEL 表达式的方式,可灵活定义所需的权限,通常用于基于资源的授权。

二、SpringSecurity授权

根据 【Spring Security】认证之案例的使用、MD5加密、CSRF防御中表设计进行加强

1、修改User配置角色和权限

定义SQL语句,根据用户ID查询角色和角色对应的权限。

  • 根据用户ID查询出用户对应的角色信息。
SELECTr.rolename	
FROMsys_user u,sys_user_role ur,sys_role r
whereu.id=ur.userid and ur.roleid=r.roleid and u.id=#{userid}
  • 根据用户ID查询出角色对应的权限信息。
selectm.url
fromsys_user u,sys_user_role ur,sys_role r,sys_role_module rm,sys_module m
whereu.id=ur.userid and ur.roleid=r.roleid andr.roleid=rm.roleid and rm.moduleid=m.id andu.id=#{userid} and url is not null

修改User实体类,添加角色和权限集合,并完成角色和权限的数据填充。

@Getter
@Setter
@Accessors(chain = true)
@TableName("sys_user")
public class User implements Serializable, UserDetails {private static final long serialVersionUID = 1L;/*** 主键*/@TableId(value = "id", type = IdType.AUTO)private Integer id;/*** 用户名*/@TableField("username")private String username;/*** 密码*/@TableField("password")private String password;/*** 真实姓名*/@TableField("real_name")private String realName;/*** 是否过期*/@TableField("account_non_expired")private boolean accountNonExpired;/*** 权限*/@TableField(exist = false)private List<? extends GrantedAuthority> authorities;/*** 是否锁定*/@TableField("account_non_locked")private boolean accountNonLocked;/*** 是否过期*/@TableField("credentials_non_expired")private boolean credentialsNonExpired;/*** 是否启用*/@TableField("enabled")private boolean enabled;}

2、修改loadUserByUsername方法

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>implements UserService,UserDetailsService {@Autowiredprivate RoleMapper roleMapper;@Autowiredprivate RoleModuleMapper roleModuleMapper;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//根据用户名查询数据库中用户信息User user = this.getOne(new QueryWrapper<User>().eq("username", username));//判断用户是否存在if(Objects.isNull(user))throw new UsernameNotFoundException("用户不存在");//权限校验TODO,后续讲解List<String> roles = roleMapper.queryRolesByUid(user.getId());List<String> permission = roleModuleMapper.queryRoleModuleByUid(user.getId());user.setRoles(roles);user.setPermissions(permission);return user;}   
}

3、修改SpringSecurity配置类

当我们想要开启spring方法级安全时,只需要在任何 @Configuration实例上使用@EnableGlobalMethodSecurity 注解就能达到此目的。同时这个注解为我们提供了prePostEnabledsecuredEnabledjsr250Enabled 三种不同的机制来实现同一种功能。

修改WebSecurityConfig配置类,开启基于方法的安全认证机制,也就是说在web层的controller启用注解机制的安全确认。

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig {//@Autowired 注解用于标注在需要进行依赖注入的属性或方法上@Autowiredprivate MyUserDetailsService userDetailsService;@Autowiredprivate ObjectMapper objectMapper;@Autowiredprivate MyAuthenticationFailureHandler myAuthenticationFailureHandler;@Bean//@Bean 注解用于标注在需要进行依赖注入的属性或方法上public PasswordEncoder passwordEncoder() {//BCryptPasswordEncoder 用于对密码进行编码return new BCryptPasswordEncoder();}@Beanpublic AuthenticationManager authenticationManager() throws Exception {// 创建一个DaoAuthenticationProvider对象DaoAuthenticationProvider provider = new DaoAuthenticationProvider();// 设置用户详情服务和密码编码器provider.setUserDetailsService(userDetailsService);provider.setPasswordEncoder(passwordEncoder());// 返回一个ProviderManager对象return new ProviderManager(provider);}@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {http.authorizeRequests()// 允许所有用户访问根路径.antMatchers("/").permitAll()// 允许管理员访问管理员路径.antMatchers("/admin/**").hasRole("ADMIN")// 允许管理员和用户访问用户路径.antMatchers("/user/**").hasAnyRole("ADMIN", "USER")// 需要身份认证 anyRequest 其余所有请求 & authenticated 登录.anyRequest().authenticated().and().formLogin()//loginPage 登录页面.loginPage("/")//设置处理登录请求的接口.loginProcessingUrl("/userLogin")//用户的数据的参数.usernameParameter("username").passwordParameter("password")//登录成功.successHandler((req, resp, auth) -> {//获取用户信息Object user = auth.getPrincipal();//返回json格式的用户信息objectMapper.writeValue(resp.getOutputStream(), JsonResponseBody.success(user));})//登录失败.failureHandler(myAuthenticationFailureHandler).and().exceptionHandling()//权限不足.accessDeniedHandler((req, resp, ex) -> {//返回json格式的无权限信息objectMapper.writeValue(resp.getOutputStream(), JsonResponseBody.other(JsonResponseStatus.NO_ACCESS));})//没有认证.authenticationEntryPoint((req, resp, ex) -> {//返回json格式的未登录信息objectMapper.writeValue(resp.getOutputStream(), JsonResponseBody.other(JsonResponseStatus.NO_LOGIN));}).and().logout()//设置登出url.logoutUrl("/logout")//设置登出成功url.logoutSuccessUrl("/");//禁用csrfhttp.csrf().disable();//返回http实例return http.build();}}

@EnableGlobalMethodSecurity是Spring Security提供的一个注解,用于启用方法级别的安全性。它可以在任何@Configuration类上使用,以启用Spring Security的方法级别的安全性功能。它接受一个或多个参数,用于指定要使用的安全注解类型和其他选项。以下是一些常用的参数:

  • prePostEnabled:如果设置为true,则启用@PreAuthorize@PostAuthorize注解。默认值为false
  • securedEnabled:如果设置为true,则启用@Secured注解。默认值为false
  • jsr250Enabled:如果设置为true,则启用@RolesAllowed注解。默认值为false
  • proxyTargetClass:如果设置为true,则使用CGLIB代理而不是标准的JDK动态代理。默认值为false

使用@EnableGlobalMethodSecurity注解后,可以在应用程序中使用Spring Security提供的各种注解来保护方法,例如@Secured@PreAuthorize@PostAuthorize@RolesAllowed。这些注解允许您在方法级别上定义安全规则,以控制哪些用户可以访问哪些方法。

注解介绍:

注解说明
@PreAuthorize用于在方法执行之前对访问进行权限验证
@PostAuthorize用于在方法执行之后对返回结果进行权限验证
@Secured用于在方法执行之前对访问进行权限验证
@RolesAllowed是Java标准的注解之一,用于在方法执行之前对访问进行权限验证

4、控制Controller层接口权限

@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate RoleService roleService;@Autowiredprivate ModuleService moduleService;@RequestMapping("/userLogin")public String userLogin(User user){return "login";}@PreAuthorize("hasAuthority('order:manager:list')")@GetMapping("/queryRoles")public JsonResponseBody<List<Role>> queryRoles(){List<Role> list = roleService.list();return new JsonResponseBody<>(list);}@PreAuthorize("hasAuthority('book:manager:list')")@GetMapping("/queryModules")public JsonResponseBody<List<Module>> queryModules(){List<Module> list = moduleService.list();return new JsonResponseBody<>(list);}@PreAuthorize("hasAuthority('管理员')")@GetMapping("/queryTest")public JsonResponseBody<?> queryTest(){return new JsonResponseBody<>("你好,我是管理员!");}
}

更多常见内置表达式见官方文档

5、启动测试

配置完毕之后,重新启动项目。分别使用两个不同的用户(adminzs)登录进行权限测试。
在这里插入图片描述

注意:admin具备所有权限;zs只具备部分权限。

当通过zs用户登录成功之后,点击权限和角色验证进行权限测试。

  • 点击获取用户角色信息,可以成功显示数据:

  • 点击获取角色权限信息,提示403错误:(也就是无权限提示)

6、异常处理

①AccessDeniedHandler

AccessDeniedHandler是Spring Security提供的一个接口,用于处理访问被拒绝的情况。当用户尝试访问受保护资源但没有足够的权限时,Spring Security会调用AccessDeniedHandler来处理这种情况。

AccessDeniedHandler接口只有一个方法handle(),该方法接收HttpServletRequestHttpServletResponseAccessDeniedException三个参数。在handle()方法中,可以自定义响应的内容,例如返回一个自定义的错误页面或JSON响应。

创建AccessDeniedHandlerImpl类并实现AccessDeniedHandler接口,实现自定义的JSON响应。例如:

@Component
public class AccessDeniedHandlerImpl implements AccessDeniedHandler {@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {int code = 500;response.setStatus(200);response.setContentType("application/json;charset=UTF-8");String msg = "权限不足,无法访问系统资源";Map<String, Object> result = new HashMap<>();result.put("msg", msg);result.put("code", code);String s = new ObjectMapper().writeValueAsString(result);response.getWriter().println(s);}
}

然后,将自定义的accessDeniedHandler注入到Spring Security的配置中:

@Autowired
private AccessDeniedHandlerImpl accessDeniedHandler;@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {returnhttp// ....exceptionHandling().accessDeniedHandler(accessDeniedHandler())// ...
}

这样,当访问被拒绝时,Spring Security就会调用自定义AccessDeniedHandler来处理。

②AuthenticationEntryPoint

AuthenticationEntryPoint是Spring Security中的一个接口,用于定义如何处理未经身份验证的请求。当用户尝试访问需要身份验证的资源但未进行身份验证时,AuthenticationEntryPoint将被调用。

在这个接口中,可以自定义如何处理这些未经身份验证的请求,例如重定向到登录页面或返回错误消息。需要注意的是,AuthenticationEntryPoint只处理未经身份验证的请求,已经进行身份验证但权限不足的请求则需要使用AccessDeniedHandler来处理。

创建AuthenticationEntryPointImpl类并实现AuthenticationEntryPoint接口,实现自定义的JSON响应。例如:

@Component
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {response.setStatus(200);int code = 500;String msg = "认证失败,无法访问系统资源";response.setContentType("application/json;charset=UTF-8");Map<String, Object> result = new HashMap<>();result.put("msg", msg);result.put("code", code);String s = new ObjectMapper().writeValueAsString(result);response.getWriter().println(s);}
}

然后,将自定义的authenticationEntryPoint注入到Spring Security的配置中:

@Autowired
private AuthenticationEntryPointImpl authenticationEntryPoint;@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {returnhttp// ....exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)// ...
}

这样,当认证失败时,Spring Security就会调用自定义AuthenticationEntryPoint来处理。

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Redis 核心知识总结

Redis 核心知识总结 认识 Redis 什么是 Redis&#xff1f; Redis 是一个由 C 语言开发并且基于内存的键值型数据库&#xff0c;对数据的读写操作都是在内存中完成&#xff0c;因此读写速度非常快&#xff0c;常用于缓存&#xff0c;消息队列、分布式锁等场景。 有以下几个特…

jQuery-1.7.2存在任意文件读取漏洞

jQuery是一个快速、简洁的JavaScript框架,是一个丰富的JavaScript代码库&#xff0c;其1.7.2版本的sys_dia_data_down模块存在任意文件读取漏洞&#xff0c;攻击者可通过前台读取任意文件。 1.漏洞级别 高危 2.漏洞搜索 fofa body"webui/js/jquerylib/jquery-1.7.2.m…

深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第四节 参数传递对堆栈的影响 1

深入浅出图解C#堆与栈 C# Heaping VS Stacking 第四节 参数传递对堆栈的影响1 [深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第一节 理解堆与栈](https://mp.csdn.net/mdeditor/101021023)[深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第二节 栈基本工作原理](http…

【银行测试】金融银行-理财项目面试/分析总结(二)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 银行理财相关的项…

小波如何让研究人员转换和理解数据?

在日益数据驱动的世界中&#xff0c;被称为小波的数学工具已成为分析和理解信息不可或缺的方法。许多研究人员以连续信号的形式接收他们的数据&#xff0c;这意味着随着时间的推移&#xff0c;信息流不断演变&#xff0c;例如地球物理学家聆听从地下岩层反弹的声波&#xff0c;…

客服软件如何提升企业客户满意度?

互联网的快速发展&#xff0c;越来越多的企业开始关注客户满意度的提升。客户满意度是企业成功的关键因素之一&#xff0c;而客服软件作为提升客户满意度的重要工具&#xff0c;正逐渐受到企业的重视。那么&#xff0c;客服软件如何提升企业客户满意度呢? 一、提高客户服务效率…

stm32项目(17)——基于stm32的温湿度检测protues仿真

1.功能设计 基于stm32单片机&#xff0c;驱动DHT11芯片&#xff0c;检测温度与湿度&#xff0c;并通过串口打印出来。 仿真图如下所示&#xff1a; 2.模块介绍 DHT11模块是一种低成本的数字温湿度传感器模块&#xff0c;常用于测量环境的温度和湿度。它由一个温湿度传感器和一…

MySQL事务、四大原则、执行步骤、四种隔离级别、锁、脏读、脏写等

MySQL事务 MySQL事务1.什么是事务&#xff1f;2.事务的四大原则3.事务执行的步骤4、事务的隔离性5、MySQL中的锁 MySQL事务 模拟一个转账业务&#xff1a; 上图中的sql语句&#xff1a; update from table set money mongey - 100 where name A; update from table set mone…

【Unity自制手册】基于Unity中物体移动相关方法和API集锦(动图详解)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;uni…

python打包项目pyinstaller的使用及问题解决

前言 在使用python编写了一个小程序之后&#xff0c;希望能够将其打包为一个可执行文件&#xff0c;如exe格式&#xff0c;这样就能够在其他电脑上安装使用&#xff0c;因此&#xff0c;打包python项目是一个普遍的需求。 配置 平台&#xff1a;windows10 工具&#xff1a;vi…

像美团一样商家入驻的小程序功能

美团一样的商家入驻小程序可以促进本地化商家的线上线下融合&#xff0c;为本地商家和用户提供更好的服务和体验&#xff0c;是一种数字化转型和创新&#xff0c;想要开发像美团一样的商家入驻小程序&#xff0c;需要具备以下功能&#xff1a; 1、不同行业独立频道 为本地化的…

6、LLaVA

简介 LLaVA官网 LLaVA使用Vicuna(LLaMA-2)作为LLM f ϕ ( ⋅ ) f_\phi() fϕ​(⋅)&#xff0c;使用预训练的CLIP图像编码器 ViT-L/14 g ( X v ) g(X_v) g(Xv​)。 输入图像 X v X_v Xv​&#xff0c;首先获取feature Z v g ( X v ) Z_vg(X_v) Zv​g(Xv​)。考虑到最后一…

4.Python数据序列

Python数据序列 一、作业回顾 1、面试题 有一物,不知其数,三三数之余二,五五数之余三,七七数之余二,问物几何? 白话文:有一个数字,不知道具体是多少,用3去除剩2,用5去除剩3,用7去除剩2个,问这个数是多少?1 ~ 100以内的整数 while循环: # 初始化计数器 i = …

01_软件测试

01_软件测试 学习目标 1、能复述软件测试的定义 2、能说出7种测试分类的区别 3、能说出质量模型的重点5项 4、能说出测试流程的6个步骤 5、能说出测试模板8个要素 认识软件及测试 什么是软件 软件&#xff1a;控制计算机硬件工作的工具 软件的基本组成 软件生产过程 什么是软…

力扣算法-Day14

第202题. 快乐数 编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」 定义为&#xff1a; 对于一个正整数&#xff0c;每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为 1&#xff0c;也可能是 无限循环 但始终变不到 1。如果这个过程 结…

Rocky9 1.28安装kubernetes

1.环境准备 二进制安装比较复杂&#xff0c;但是也比较稳定&#xff0c;适用于线上环境使用。   本笔记参考自&#xff1a;https://github.com/cby-chen/Kubernetes &#xff0c;针对文中内容&#xff0c;有部分镜像无法拉取等&#xff0c;还有一部分有点小问题&#xff0c;…

2024-软件测试工程师面试题,面试前一天刷效果更佳。

bug的定义&#xff0c;bug的周期 软件bug是指软件程序的漏洞和缺陷&#xff0c;测试工程师或用户所发现和提出的软件可改进的细节、或与需求文档存在差异的功能实现等生命周期中缺陷状态&#xff1a;新建-->指派-->已解决-->待验-->关闭 发现BUG-->提交BUG--&g…

如何本地部署Nextcloud结合cpolar搭建专属私有云盘远程访问(内网穿透)

文章目录 摘要1. 环境搭建2. 测试局域网访问3. 内网穿透3.1 ubuntu本地安装cpolar3.2 创建隧道3.3 测试公网访问 4 配置固定http公网地址4.1 保留一个二级子域名4.1 配置固定二级子域名4.3 测试访问公网固定二级子域名 摘要 Nextcloud,它是ownCloud的一个分支,是一个文件共享服…

高智能氛围感知兼具运动与豪华质感 EMEYA开启百万纯电新时代

在纯电动汽车成为刚需的时代&#xff0c;售价百万的纯电轿车应该拥有怎样的体验&#xff1f; 最近&#xff0c;路特斯推出一款百万纯电四门超跑轿车——EMEYA&#xff0c;这款车11月广州车展亮相并开启预定后&#xff0c;3小时内便订单即破300辆。一款百万级的电动汽车为何受到…

51单片机(STC8)-- GPIO输入输出

文章目录 I/O口相关寄存器端口数据寄存器端口模式配置寄存器&#xff08;PxM0&#xff0c;PxM1&#xff09;端口上拉电阻控制寄存器(PxPU)关于I/O的注意事项 配置I/O口I/O设置demoI/O端口模式LED控制&#xff08;I/O输出&#xff09;按键检测&#xff08;I/O输入&#xff09; S…