Spring security之授权

前言

本篇为大家带来Spring security的授权,首先要理解一些概念,有关于:权限、角色、安全上下文、访问控制表达式、方法级安全性、访问决策管理器

一.授权的基本介绍

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

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

  • 基于资源的授权:以资源为基础进行授权,如 URL、方法等,通过定义资源所需的权限,来控制对该资源的访问权限。

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

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

二.修改User配置角色和权限

方法一.

使用SQL语句的方式查询该角色的权限,并且可以对它进行修改

根据用户id查询出对应的角色信息

 SELECT*FROMsys_user a,sys_user_role b,sys_role_module c,sys_module dWHERE a.id = b.user_id andb.role_id=c.role_id andc.module_id = d.id anda.id=#{id}

 

根据用户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

但是并不推荐使用这种方法,当我们在实际开发中,要考虑到不同的数据表可能来自不同的库中,使用SQL查询时就会出现链表查询不同库的表的情况,所以,更多的时候我们会使用Java利用不同的操作对表进行依次查询作为条件最终得到结果

方法二.利用Java对表单一查询然后作为查询条件,最终查询出结果

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService, UserDetailsService {@Autowiredprivate IUserRoleService userRoleService;@Autowiredprivate IRoleService roleService;@Autowiredprivate IRoleModuleService roleModuleService;@Autowiredprivate IModuleService moduleService;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {User user = getOne(new QueryWrapper<User>().eq("username", username));if(user==null){throw new UsernameNotFoundException("用户名无效");}//查询出身份//map遍历所有对象,返回新的数据放到新的集合中//filter 过滤流中的内容//collect将流中的元素变成一个集合List<Integer> role_ids = userRoleService.list(new QueryWrapper<UserRole>().eq("user_id", user.getId())).stream().map(UserRole::getRoleId).collect(Collectors.toList());//根据身份字段查询身份对应的名字字段List<String> roles = roleService.list(new QueryWrapper<Role>()).stream().map(Role::getRoleName).collect(Collectors.toList());//根据身份id查询具备的权限idList<Integer> module_ids = roleModuleService.list(new QueryWrapper<RoleModule>().in("role_id", role_ids)).stream().map(RoleModule::getModuleId).collect(Collectors.toList());//根据权限id查询对应的权限List<String> modules = moduleService.list(new QueryWrapper<Module>().in("id", module_ids)).stream().map(Module::getUrl).collect(Collectors.toList());// 将权限字段加到身份中roles.addAll(modules);//将当前集合内容加到权限字段中List<SimpleGrantedAuthority> authorities = roles.stream().map(SimpleGrantedAuthority::new).filter(Objects::nonNull).collect(Collectors.toList());user.setAuthorities(authorities);return user;}
}

三.SpringSecurity配置类

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

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

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig {@Autowiredprivate UserServiceImpl userDetailsService;@Autowiredprivate ObjectMapper objectMapper;@Autowiredprivate MyAuthenticationFailureHandler myAuthenticationFailureHandler;@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Beanpublic AuthenticationManager authenticationManager() throws Exception {//创建DaoAuthenticationProviderDaoAuthenticationProvider provider = new DaoAuthenticationProvider();//设置userDetailsService,基于数据库方式进行身份认证provider.setUserDetailsService(userDetailsService);//配置密码编码器provider.setPasswordEncoder(passwordEncoder());return new ProviderManager(provider);}@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {http.authorizeRequests()//antMatchers 匹配对应的路径//permitAll 允许.antMatchers("/").permitAll()//anyRequest 其余所有请求//authenticated 登录.anyRequest().authenticated().and().formLogin()//loginPage 登录页面.loginPage("/")//设置处理登录请求的接口.loginProcessingUrl("/userLogin")//用户的数据的参数.usernameParameter("username").passwordParameter("password")//登录成功.successHandler((req, resp, auth) -> {Object user = auth.getPrincipal();objectMapper.writeValue(resp.getOutputStream(), JsonResponseBody.success(user));})//登录失败.failureHandler(myAuthenticationFailureHandler).and().exceptionHandling()//权限不足.accessDeniedHandler((req, resp, ex) -> {objectMapper.writeValue(resp.getOutputStream(), JsonResponseBody.other(JsonResponseStatus.NO_ACCESS));})//没有认证.authenticationEntryPoint((req, resp, ex) -> {objectMapper.writeValue(resp.getOutputStream(), JsonResponseBody.other(JsonResponseStatus.NO_LOGIN));}).and().logout().logoutUrl("/logout").logoutSuccessUrl("/");http.csrf().disable();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标准的注解之一,用于在方法执行之前对访问进行权限验证

 四.管理控制Controller层的权限

@Controller
public class IndexController {@RequestMapping("/")public String toLogin() {return "login";}@RequestMapping("/userLogin")public String userLogin() {return "index";}@RequestMapping("/index")public String toIndex() {return "index";}@RequestMapping("/noAccess")public String noAccess() {return "accessDenied";}@ResponseBody@RequestMapping("/order_add")@PreAuthorize("hasAuthority('order:manager:add')")public String order_add() {return "订单新增";}@ResponseBody@PreAuthorize("hasAuthority('book:manager:add')")@RequestMapping("/book_add")public String book_add() {return "书本新增";}}

在当前登录的用户必须拥有当前的权限字段才能进行访问,例如:book:manager:add

五.异常处理

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

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

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

package com.yu.security.resp;import lombok.Getter;@Getter
public enum JsonResponseStatus {OK(200, "OK"),UN_KNOWN(500, "未知错误"),RESULT_EMPTY(1000, "查询结果为空"),NO_ACCESS(3001, "没有权限"),NO_LOGIN(4001, "没有登录"),LOGIN_FAILURE(5001, "登录失败"),;private final Integer code;private final String msg;JsonResponseStatus(Integer code, String msg) {this.code = code;this.msg = msg;}}

单独写一个接口进行实现,并将出现异常后的操作在里面实现

package com.yu.security.config;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yu.security.pojo.User;
import com.yu.security.resp.JsonResponseBody;
import com.yu.security.resp.JsonResponseStatus;
import com.yu.security.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@Component
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {@Autowiredprivate ObjectMapper objectMapper;// 在redis中定义一个键当登录失败是就对那个键的值进行加一//如果大于三就锁住@Autowiredprivate IUserService userService;@Overridepublic void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {if(1==2){User user = userService.getOne(new QueryWrapper<User>().eq("username", request.getParameter("username")));user.setAccountNonLocked(false);userService.updateById(user);}objectMapper.writeValue(response.getOutputStream(), JsonResponseBody.other(JsonResponseStatus.LOGIN_FAILURE));}}

在当前例子中:我们通过在配置类引入当前接口,并实现当前接口,在实现类中,对登录失败进行 对应的操作,在Redis中定义一个键当登录失败是就对那个键的值进行加一,如果大于三就对当前账号进行冻结

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

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

相关文章

Nacos单机安装

采用的版本是Nacos Release 2.3.0 (Nov 30, 2023) alibaba/nacos GitHub 依赖于jdk&#xff0c;要先安装好jdk1.8。 修改配置 下载解压后&#xff0c;修改配置文件&#xff1a;conf/application.properties。 nacos.core.auth.plugin.nacos.token.secret.key 官方文档Na…

5分钟学会用pytest进行自动化测试

Pytest作为广泛使用的Python测试框架之一&#xff0c;可以用于单元测试、功能测试、性能测试等场合。自动化测试是功能测试的一种形式&#xff0c;可以使用Pytest编写并管理自动化测试用例&#xff0c;再执行相应的自动化测试。 功能测试通常包括接口测试和Web测试两种类型&am…

低代码如何助力企业数字化转型?

目录 一、低代码开发是什么&#xff1f; 二、低代码与企业数字化转型 1&#xff09;集成化 2&#xff09;智能化 3&#xff09;定制化 三、低代码开发平台对于企业数字化转型的优势 01、提供源码 02、私有化部署 03、敏捷开发 04、拓展能力 四、低代码带来的效益 以…

2023年12月GESP Python五级编程题真题解析

【五级编程题1】 【试题名称】&#xff1a;小杨的幸运数 【问题描述】 小杨认为&#xff0c;所有大于等于a的完全平方数都是他的超级幸运数。 小杨还认为&#xff0c;所有超级幸运数的倍数都是他的幸运数。自然地&#xff0c;小杨的所有超级幸运数也都是幸运数。 对于一个…

WebGL开发三维解剖学应用

开发基于 WebGL 的三维解剖学应用通常涉及以下步骤。这些步骤包括创建三维模型、整合交互性、优化性能等&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1.三维模型创建&#xff1a; 首先&#xff0…

抖店定好品类赛道之后,怎么选品和快速出单?相关教程分享如下!

我是王路飞。 之前分享抖店流程相关内容时&#xff0c;我说过&#xff0c;类目选择大于一切&#xff0c;且要优于、重于选品。 至于定类目的标准&#xff0c;我之前也给你们说过&#xff0c;不要以自己个人喜好为标准去判断市场&#xff0c;也不要凭借自己以往认知和经验确定…

Weblogic Server工具WLST的使用

1.Weblogic脚本工具WLST介绍 可以用命令行来操作 Weblogic scripting tools 2.Weblogic WLST三种工作模式 2.1 wlst.sh tips:weblogic的T3 协议与HTTP/HTTPS 协议 操作如下&#xff1a;wlst在 common目录下 weblogic14c/wlserver/common/bin/ [weblogicfysedu32 weblogic]$…

【Amazon 实验①】使用 Amazon CloudFront加速Web内容分发

文章目录 实验架构图1. 准备实验环境2. 创建CloudFront分配、配置动、静态资源分发2.1 创建CloudFront分配&#xff0c;添加S3作为静态资源源站2.2 为CloudFront分配添加动态源站 在本实验——使用CloudFront进行全站加速中&#xff0c;将了解与学习Amazon CloudFront服务&…

【SpringBoot】Spring data JPA整合ShardingSphere-JDBC静态读写分离实现

大佬栽树&#xff0c;我乘凉 许大仙老师&#xff1a;【yuque.com/fairy-era/yg511q/ud9uli67b6gxgdh7】 开整 数据库准备 一主两从 数据库脚本 CREATE DATABASE IF NOT EXISTS dbtest CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE dbtest; -- 创建表 CREATE TA…

论文查重率高如何快速降重 papergpt

大家好&#xff0c;今天来聊聊论文查重率高如何快速降重&#xff0c;希望能给大家提供一点参考。 以下是针对论文重复率高的情况&#xff0c;提供一些修改建议和技巧&#xff0c;可以借助此类工具&#xff1a; 论文查重率高如何快速降重 当论文查重率过高时&#xff0c;需要快…

骑砍战团MOD开发(24)-module_particle_system粒子系统

一.粒子实现方式 创建2D平面模型作为粒子基本单元,系统预制平面在particle_meshes.brf文件中,通过particle_blend着色器实现粒子透明度和着色效果. #雨点粒子平面 prtcl_rain #雪粒子平面 prtcl_snow #烟尘粒子平面(马匹奔跑时产生) prtcl_dust_a prtcl_dust_b #火焰粒子平面 …

汽车级EEPROM 存储器 M24C64-DRMN3TP/K是电可擦除可编程只读存储器?它的功能特性有哪些?

M24C64-DRMN3TP/K是一款64 Kbit串行EEPROM汽车级设备&#xff0c;工作温度高达125C。符合汽车标准AEC-Q100 1级规定的极高可靠性。 该设备可通过一个高达1MHz的简单串行I2C兼容接口访问。 存储器阵列基于先进的真EEPROM技术&#xff08;电可擦除可编程存储器&#xff09;。M2…