SpringSecurity深度学习

 SpringSecurity简介

spring Security是什么?

Spring Security 是一个强大且高度可定制的身份验证和访问控制框架,用于保护基于Spring的应用程序。它是Spring项目的一部分,旨在为企业级系统提供全面的安全性解决方案。

一个简单的授权和校验流程

检验流程

总流程 

SpringSecurity使用

认证 

对应依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency>

在自定义检验的时候,主要就是实现UserDetailsService接口,重写loadUserByUserName方法,在该方法中就是去检验账号和密码的准确性。(一般都是进行数据库的查询校验,默认的密码格式就是 ·{}密码·)

前后端分离项目登录流程

1.在springSecurity中我们的需要设置密文的配置,在项目中大多都是使 BCryptPasswordEncoder类来做密码的加密。

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}}

2.创建对应的login接口和service

Controller 

@RestController
@RequestMapping("/user")
public class LoginController {@AutowiredLoginService loginService;@PostMapping("/login")public ResponseResult login(@RequestBody User user) {return loginService.login(user);}
}

Service

@Service
public class LoginServiceImpl implements LoginService {@Autowiredprivate AuthenticationManager authenticationManager;@AutowiredRedisCache redisCache;@Overridepublic ResponseResult login(User user) {//authenticationManager authenticate进行用户验证UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserName(), user.getPassword());Authentication authenticate = authenticationManager.authenticate(authenticationToken);//执行我们对饮的认证方法,在该方法中会返回LoginUser类型的数据//如果没有通过通过直接抛异常if(ObjectUtil.isEmpty(authenticate)) {throw new RuntimeException("登录失败");}//如果成功直接生成token,将其也map返回LoginUser loginUser = (LoginUser)authenticate.getPrincipal();String jwt = JwtUtil.createJWT(loginUser.getUser().getId().toString());Map<String, String> data = new HashMap<>();data.put("token", jwt);redisCache.setCacheObject(loginUser.getUser().getId().toString(), user);//返回tokenreturn new ResponseResult(200, "登录成功", data);}
}

因为AuthenticationManager默认不在ioc中,我们需要将其配置到ioc中,并且配置对应的校验规则。在里面就包括 无效校验的接口(比如:登录接口)和其他一些前后端分离的配置。

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}//将AuthenticationManager配置到ioc中@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}//配置权限规则,主要就睡要放行登录接口,不然登录接口都会被了解,以及其他不要的前后端分离的配置@Overrideprotected void configure(HttpSecurity http) throws Exception {http//由于是前后端分离项目,所以要关闭csrf.csrf().disable()//由于是前后端分离项目,所以session是失效的,我们就不通过Session获取SecurityContext.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()//指定让spring security放行登录接口的规则.authorizeRequests()// 对于登录接口 anonymous表示允许匿名访问.antMatchers("/user/login").anonymous()// 除上面外的所有请求全部需要鉴权认证.anyRequest().authenticated();}
}

进行测试,校验成功。

前后端分离项目校验流程

1.创建一个校验过滤器

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {@AutowiredRedisCache redisCache;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {//获取token,token会存在header中String token = request.getHeader("token");if(StrUtil.isEmpty(token)) {//由后续的拦截器进行拦截filterChain.doFilter(request, response);//后续会返回回来,需要return,不然会执行下面的语句return ;}//解析tokenString userId;try {Claims claims = JwtUtil.parseJWT(token);userId = claims.getSubject();if(StringUtil.isNullOrEmpty(userId)) {throw new RuntimeException("token解析失败");}} catch (Exception e) {throw new RuntimeException(e);}//从redis中获取用户的信息LoginUser loginUser = redisCache.getCacheObject(userId);if(ObjectUtil.isEmpty(loginUser)) {throw new RuntimeException("Redis中没有用户信息");}//将数据存储到SecurityContextHolderUsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, null);SecurityContextHolder.getContext().setAuthentication(authenticationToken);//放行filterChain.doFilter(request, response);}
}

使用三个参数的UsernamePasswordAuthenticationToken的构造器,该构造器会设置授权成功。

2.将过滤器设置到用户验证过滤器之前

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@AutowiredJwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;//设置加密方式@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}//将AuthenticationManager配置到ioc中@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}//配置权限规则,主要就睡要放行登录接口,不然登录接口都会被了解,以及其他不要的前后端分离的配置@Overrideprotected void configure(HttpSecurity http) throws Exception {http//由于是前后端分离项目,所以要关闭csrf.csrf().disable()//由于是前后端分离项目,所以session是失效的,我们就不通过Session获取SecurityContext.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()//指定让spring security放行登录接口的规则.authorizeRequests()// 对于登录接口 anonymous表示允许匿名访问.antMatchers("/user/login").anonymous()// 除上面外的所有请求全部需要鉴权认证.anyRequest().authenticated();//将过滤器添加到用户登录处理器之前http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);}
}

进行测试,将成功的token放入header中,进行校验。最终校验成功。

退出登录流程

1.编写退出登录接口

@RestController
@RequestMapping("/user")
public class LoginController {@AutowiredLoginService loginService;@RequestMapping("/logout")public ResponseResult logout() {return loginService.logout();}
}

2.编写service实现类,删除redis中用户信息的数据,即可完成退出登录操作。在解析的时候redis中的数据不存在就会直接被拦截。

@Service
public class LoginServiceImpl implements LoginService {@Autowiredprivate AuthenticationManager authenticationManager;@AutowiredRedisCache redisCache;@Overridepublic ResponseResult logout() {//在进入此接口时会先进行解析,成功之后才会执行logout,此时SecurityContextHolder中是有用户信息的UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();LoginUser loginUser = (LoginUser) authentication.getPrincipal();if(ObjectUtil.isEmpty(loginUser)) {throw new RuntimeException("LoginUser不存在");}//把redis中的数据删除之后,下次解析的时候就会直接报错,在解析中我们对redis的数据做了判空的操作redisCache.deleteObject(loginUser.getUser().getId().toString());return new ResponseResult(200, "退出登录成功", null);}
}

进行测试,最终成功。

授权

1.开启授权功能,在对应的security的配置类中添加对应的注解。

@EnableGlobalMethodSecurity(prePostEnabled = true) //开启授权

2.为接口设置对应的权限需求

@RestController
public class baseController {@RequestMapping("/hello")//拥有text倾向才能访问@PreAuthorize("hasAuthority('text')")public String hello() {return "hello!";}
}

3.在用户进行认证的时候查询用户拥有的权限集合,并设置到 authenticationToken中。

  • 在返回类型中设置权限集合属性和重写获取权限集合方法。
@Data
@NoArgsConstructor
public class LoginUser implements UserDetails {private User user;private List<String> authorities2String;public LoginUser(User user, List<String> authorities2String) {this.user = user;this.authorities2String = authorities2String;}@JSONField(serialize = false)private List<GrantedAuthority> authorities;@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {if(CollUtil.isEmpty(authorities)) {return authorities2String.stream().map(item -> new SimpleGrantedAuthority(item)).collect(Collectors.toList());}return authorities;}@Overridepublic String getPassword() {return user.getPassword();}@Overridepublic String getUsername() {return user.getUserName();}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return true;}
}
  • 在校验Service中查询对应的权限列表。
@Service
public class UserService implements UserDetailsService {@AutowiredUserMapper userMapper;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {QueryWrapper<com.huang.springsecuritydemo.entity.User> userQueryWrapper = new QueryWrapper<>();userQueryWrapper.eq("user_name", username);com.huang.springsecuritydemo.entity.User user = userMapper.selectOne(userQueryWrapper);if(ObjectUtil.isEmpty(user)) {throw new RuntimeException("用户不存在");}//todo 查询并设置对应的权限信息//模拟查到的权限信息List<String> data = Arrays.asList("test", "text");return new LoginUser(user, data);}
}
  • 在JWT认证中向authenticationToken中设置权限集合,最终设置到SecurityContextHolder中。
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {@AutowiredRedisCache redisCache;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {//获取token,token会存在header中String token = request.getHeader("token");if(StrUtil.isEmpty(token)) {//由后续的拦截器进行拦截filterChain.doFilter(request, response);//后续会返回回来,需要return,不然会执行下面的语句return ;}//解析tokenString userId;try {Claims claims = JwtUtil.parseJWT(token);userId = claims.getSubject();if(StringUtil.isNullOrEmpty(userId)) {throw new RuntimeException("token解析失败");}} catch (Exception e) {throw new RuntimeException(e);}//从redis中获取用户的信息LoginUser loginUser = redisCache.getCacheObject(userId);if(ObjectUtil.isEmpty(loginUser)) {throw new RuntimeException("Redis中没有用户信息");}//将数据存储到SecurityContextHolder//todo 设置对应的权限信息UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());SecurityContextHolder.getContext().setAuthentication(authenticationToken);//放行filterChain.doFilter(request, response);}
}

进行测试,授权成功。

RDAB模型例子(基本通用,看进行二次开发)

1.创建五个数据库 用户表,角色表,权限表,用户角色关联表,角色权限关联表。

2.编写SQL语句查询用户的所有权限,并使用 mybatis-plus进行封装为一个函数进行调用。

SELECTDISTINCT m.`perms`FROMsys_user_role urLEFT JOIN `sys_role` r ON ur.`role_id` = r.`id`LEFT JOIN `sys_role_menu` rm ON ur.`role_id` = rm.`role_id`LEFT JOIN `sys_menu` m ON m.`id` = rm.`menu_id`WHEREuser_id = #{id}AND r.`status` = 0AND m.`status` = 0

3.在校验是进行调用,并返回对应的权限集合。

@Service
public class UserService implements UserDetailsService {@AutowiredUserMapper userMapper;@AutowiredMenuMapper menuMapper;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {QueryWrapper<com.huang.springsecuritydemo.entity.User> userQueryWrapper = new QueryWrapper<>();userQueryWrapper.eq("user_name", username);com.huang.springsecuritydemo.entity.User user = userMapper.selectOne(userQueryWrapper);if(ObjectUtil.isEmpty(user)) {throw new RuntimeException("用户不存在");}//todo 查询并设置对应的权限信息List<String> data = menuMapper.selectPermsByUserId(user.getId());return new LoginUser(user, data);}
}

修改接口所需要的权限。

@RestController
public class baseController {@RequestMapping("/hello")//拥有text倾向才能访问@PreAuthorize("hasAuthority('system:test:list')")public String hello() {return "hello!";}
}

进行测试,最终成功。

自定义失败处理

1.自定义授权异常处理器和校验异常处理器。

  • 校验异常处理器
//校验失败异常处理器
@Component
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {//创建统一的返回对象,设置到response中ResponseResult responseResult = new ResponseResult(HttpStatus.HTTP_UNAUTHORIZED, "校验失败!");String json = JSON.toJSONString(responseResult);//将统一的结果设置到Response中,本质就是将对应的数据设置到response中WebUtil.renderString(response, json);}
}
  • 授权异常处理器

//授权失败异常处理器
@Component
public class AccessDeniedHandlerImpl implements AccessDeniedHandler {@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {ResponseResult responseResult = new ResponseResult(HttpStatus.HTTP_UNAUTHORIZED, "授权失败!");String json = JSON.toJSONString(responseResult);WebUtil.renderString(response, json);}
}

对应的webUtil工具类

public class WebUtil {/*** 将字符串渲染到客户端** @param response 渲染对象* @param string 待渲染的字符串* @return null*/public static String renderString(HttpServletResponse response, String string) {try{response.setStatus(200);response.setContentType("application/json");response.setCharacterEncoding("utf-8");//将结果json以流的形式写入response中response.getWriter().print(string);}catch (IOException e){e.printStackTrace();}return null;}
}

2.将自定义的异常处理器进行配置

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {@AutowiredJwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;@AutowiredAuthenticationEntryPoint authenticationEntryPoint;@AutowiredAccessDeniedHandler accessDeniedHandler;@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}//将AuthenticationManager配置到ioc中@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}//配置权限规则,主要就睡要放行登录接口,不然登录接口都会被了解,以及其他不要的前后端分离的配置@Overrideprotected void configure(HttpSecurity http) throws Exception {http//由于是前后端分离项目,所以要关闭csrf.csrf().disable()//由于是前后端分离项目,没有session.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()//指定让spring security放行登录接口的规则.authorizeRequests()// 对于登录接口 anonymous表示允许匿名访问, permitAll就是 登录和没登录都可以访问.antMatchers("/user/login").anonymous() //匿名访问,未登录就可以访问// 除上面外的所有请求全部需要鉴权认证后访问.anyRequest().authenticated();//将过滤器添加到用户登录处理器之前http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);//设置自定义的异常处理器http.exceptionHandling()//校验异常处理器.authenticationEntryPoint(authenticationEntryPoint)//授权异常处理器.accessDeniedHandler(accessDeniedHandler);}
}

进行测试,异常显示成功。

允许跨域

1.开启springboot的允许跨域。

@Configuration
public class CorsConfig implements WebMvcConfigurer {@Override//重写spring提供的WebMvcConfigurer接口的addCorsMappings方法public void addCorsMappings(CorsRegistry registry) {//设置可以跨域的映射地址registry.addMapping("/**")// 设置可以跨域的源.allowedOriginPatterns("*")// 是否允许使用cookie.allowCredentials(true)// 设置允许的请求方式.allowedMethods("GET", "POST", "DELETE", "PUT")// 设置允许的header属性.allowedHeaders("*")// 跨域允许时间.maxAge(3600);}
}

2.开启springsecurity的允许跨域。

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {@AutowiredJwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;@AutowiredAuthenticationEntryPoint authenticationEntryPoint;@AutowiredAccessDeniedHandler accessDeniedHandler;@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}//将AuthenticationManager配置到ioc中@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}//配置权限规则,主要就睡要放行登录接口,不然登录接口都会被了解,以及其他不要的前后端分离的配置@Overrideprotected void configure(HttpSecurity http) throws Exception {http//由于是前后端分离项目,所以要关闭csrf.csrf().disable()//由于是前后端分离项目,没有session.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()//指定让spring security放行登录接口的规则.authorizeRequests()// 对于登录接口 anonymous表示允许匿名访问, permitAll就是 登录和没登录都可以访问.antMatchers("/user/login").anonymous() //匿名访问,未登录就可以访问// 除上面外的所有请求全部需要鉴权认证后访问.anyRequest().authenticated();//将过滤器添加到用户登录处理器之前http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);//设置自定义的异常处理器http.exceptionHandling()//校验异常处理器.authenticationEntryPoint(authenticationEntryPoint)//授权异常处理器.accessDeniedHandler(accessDeniedHandler);//允许跨域http.cors();}
}

最终设置完成。

自定义权限校验方法(比较灵活,可以自定义策略)

1.自定义校验类

@Component("itolen") //设置该类在ioc中的名称
public class ExpressionRoot {//判断权限是否存在public boolean hasAuthority(String authority) {LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();List<String> authorities2String = loginUser.getAuthorities2String();return authorities2String.contains(authority);}
}

2.在对应的接口上调用自定义方法。

@RestController
public class baseController {@RequestMapping("/hello")//拥有text倾向才能访问@PreAuthorize("@itolen.hasAuthority('system:test:list')")public String hello() {return "hello!";}
}

进行测试。

 其他处理器 

  • 认证成功处理器和认证失败处理器
//认证成功处理器实现类
@Component
public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {//认证成功后就会进行该方法System.out.println("认证成功!");}
}
//认证失败处理器实现类
@Component
public class AuthenticationFailureHandlerImpl implements AuthenticationFailureHandler {@Overridepublic void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {//认证失败后执行该方法System.out.println("认证失败!");}
}

 将两个类进行配置。

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate AuthenticationSuccessHandler authenticationSuccessHandler;@Autowiredprivate AuthenticationFailureHandler authenticationFailureHandler;//配置权限规则,主要就睡要放行登录接口,不然登录接口都会被了解,以及其他不要的前后端分离的配置@Overrideprotected void configure(HttpSecurity http) throws Exception {//设置校验成功处理器和校验失败处理器http.formLogin().successHandler(authenticationSuccessHandler).failureHandler(authenticationFailureHandler);}
}
  • 注销成功处理器
@Component
public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler {@Overridepublic void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {//注销成功后执行的方法System.out.println("注销成功!");}
}

将该类进行配置。

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate LogoutSuccessHandler logoutSuccessHandler;//配置权限规则,主要就睡要放行登录接口,不然登录接口都会被了解,以及其他不要的前后端分离的配置@Overrideprotected void configure(HttpSecurity http) throws Exception {//设置注销成功处理器http.logout().logoutSuccessHandler(logoutSuccessHandler);}
}

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

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

相关文章

【算法每日一练]-图论(保姆级教程篇14 )#会议(模板题) #医院设置 #虫洞 #无序字母对 #旅行计划 #最优贸易

目录 今日知识点&#xff1a; 求数的重心先dfs出d[1]和cnt[i]&#xff0c;然后从1进行dp求解所有d[i] 两两点配对的建图方式&#xff0c;检查是否有环 无向图欧拉路径路径输出 topodp求以i为终点的游览城市数 建立分层图转化盈利问题成求最长路 会议&#xff08;模板题&a…

动态路由OSPF实验配置

查看接口配置display ip interface brief <AR1>display ip interface brief *down: administratively down ^down: standby (l): loopback (s): spoofing The number of interface that is UP in Physical is 4 The number of interface that is DOWN in Physical …

【Docker】配置阿里云镜像加速器

默认情况下&#xff0c;将来从docker hub &#xff08;https://hub.docker.com )上下载镜像太慢&#xff0c;所以一般配置镜像加速器。 没有账号的注册一个账号并登录 登录之后点击控制台 查看 cat /etc/docker/daemon.json

7-35 有理数均值 分数 20

每日一言 我们把世界看错&#xff0c;反说它欺骗了我们。 --飞鸟集 题目 本题要求编写程序&#xff0c;计算N个有理数的平均值。 输入格式&#xff1a; 输入第一行给出正整数N&#xff08;≤100&#xff09;&#xff1b;第二行中按照a1/b1 a2/b2 …的格式给出N个分数形式的…

【STM32】STM32学习笔记-TIM输出比较(15)

00. 目录 文章目录 00. 目录01. 输出比较简介02. PWM简介03. 输出比较通道(高级)04. 输出比较通道(通用)05. 输出比较模式06. PWM基本结构07. PWM参数计算08. 舵机简介09. 舵机硬件电路10. 直流电机及驱动简介11. 直流电机硬件电路12. 附录 01. 输出比较简介 OC&#xff08;Ou…

【STM32】STM32学习笔记-ADC单通道 ADC多通道(22)

00. 目录 文章目录 00. 目录01. ADC简介02. ADC相关API2.1 RCC_ADCCLKConfig2.2 ADC_RegularChannelConfig2.3 ADC_Init2.4 ADC_InitTypeDef2.5 ADC_Cmd2.6 ADC_ResetCalibration2.7 ADC_GetResetCalibrationStatus2.8 ADC_StartCalibration2.9 ADC_GetCalibrationStatus2.10 A…

蓝桥杯备赛系列 高精度 acwing版

前言 hello&#xff0c;好久不见。元旦玩过后该收心了&#xff0c;我也倒计时一下蓝桥杯考试时间&#xff0c;大家一起复习&#xff0c;一起登顶。今天讲解高精度算法。 这个算法其实是给学c同学讲的&#xff0c;因为python自带高精度所以不需要&#xff0c;且我讲到所有内容…

Wrk压测发送Post请求的正确姿势

一、Wrk简介 wrk 是一个能够在单个多核 CPU 上产生显著负载的现代 HTTP 基准测试工具。它采用了多线程设计&#xff0c;并使用了像 epoll 和 kqueue 这样的可扩展事件通知机制。此外&#xff0c;用户可以指定 LuaJIT 脚本来完成 HTTP 请求生成、响应处理和自定义报告等功能。 …

频率域滤波图像复原之逆滤波的python实现——数字图像处理

逆滤波原理 逆滤波是一种在频率域进行的图像复原技术&#xff0c;常用于修复由运动模糊等因素引起的图像退化。具体步骤如下&#xff1a; **频率域表示&#xff1a;**首先&#xff0c;将退化的图像通过傅里叶变换从空间域转换到频率域。这使得图像的频率成分变得明显&#xf…

直流稳压电源电路

一、稳压电源的技术指标及对稳压电源的要求 稳压电源的技术指标可以分为两大类&#xff1a;一类是特性指标&#xff0c;如输出电压、输出电滤及电压调节范围;另一类是质量指标&#xff0c;反映一个稳压电源的优劣&#xff0c;包括稳定度、等效内阻&#xff08;输出电阻&#x…

dyld: Library not loaded: /usr/lib/swift/libswiftCoreGraphics.dylib

更新Xcode14后低版本iPhone调试报错 dyld: Library not loaded: /usr/lib/swift/libswiftCoreGraphics.dylib Referenced from: /var/containers/Bundle/Application/…/….app/… Reason: image not found 这是缺少libswiftCoreGraphics库 直接导入libswiftCoreGraphics库即…

软件测试作业‖pytest+po+csv+html报告+cookie+selenium

软件测试作业‖pytestpocsvhtml报告cookieselenium 先用本地部署的系统试了下 或者UFT自动化测试里诺图书管理系统软件测试 # &#xff0c;#测试报告# #性能测试#&#xff0c;#测试用例#&#xff0c; #自动化测试# Selenium 的 Web自动化测试基本要求和注意事项 1.请使用ch…