【SpringSecurity】认证授权框架——SpringSecurity使用方法
【SpringSecurity】认证授权框架——SpringSecurity使用方法
文章目录
- 【SpringSecurity】认证授权框架——SpringSecurity使用方法
- 1. 概述
- 2. 准备工作
- 2.1 引依赖
- 2.2 测试
- 3. 认证
- 3.1 认证流程
- 3.2 登录校验问题
- 3.3 实现
- 3.3.1 实现UserDetailsService接口
- 3.3.2 密码存储和校验
- 3.3.3 自定义登录接口
- 3.3.3.1 配置
- 3.3.3.2 定义登录方法
- 3.3.4 自定义认证过滤器
- 3.3.4.1 确定过滤器顺序
- 3.3.5 自定义退出登录接口
- 4. 授权
- 4.1 授权流程
- 4.2 实现
- 4.2.1 开启全局权限功能
- 4.2.2 封装权限信息
- 4.3 自定义权限校验方法
- 4.4 基于配置的权限控制
- 5. 自定义失败处理
- 5.1 认证失败处理器
- 5.2 权限不足处理器
- 5.3 配置
- 6. 跨域问题
1. 概述
Spring Security是一个框架,提供 认证(authentication)、授权(authorization)和保护,以抵御常见的攻击。它对保护命令式和响应式应用程序有一流的支持,是保护基于Spring的应用程序的事实标准。它还提供了与其他库的集成,以简化其使用。
SpringSecurity的详细使用方法可见:Spring Security 中文文档 :: Spring Security Reference (springdoc.cn)
写这篇文章主要是为了复习SpringSecurity的相关知识,在这里也向大家推荐b站up主 三更草堂
,他讲的SpringSecurity课程非常棒!
2. 准备工作
2.1 引依赖
创建springboot工程中引入这些依赖:
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.0</version>
</parent>
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!--主要是这个依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency>
</dependencies>
2.2 测试
引入好依赖之后就可以启动应用了,我们访问应用的任何一个接口都会跳转到SpringSecurity的一个默认登录页面(如下所示):
SpringSecurity提供了一个默认的登录接口 /login
和退出接口 /logout
。登录接口的默认用户名为 user
,而密码则打印在了应用的控制台:
使用默认的用户名和控制台上的密码就能够登录系统访问接口了。在正常情况下我们需要禁用这个接口,使用我们自定义的接口。
3. 认证
SpringSecurity的认证机制有很多,比如:
- Username and Password:使用用户名/密码进行认证
- OAauth 2.0 Login:使用OpenID Connect 和非标准的OAuth 2.0登录(即GitHub)的OAuth 2.0登录。
我们主要了解第一种方式。SpringSecurity认证通过过滤器链实现:
SpringSecurity的过滤器链包含15个过滤器,上图只展示了较为核心的过滤器。
- SecurityContextPersistenceFilter:过滤器链的入口和出口,保存和清除
SecurityContextHolder
中的SecurityContext
。 - UsernamePasswordAuthenticationFilter:负责收集我们在登陆页面输入的用户名和密码并封装成Authentication对象。
- ExceptionTranslationFilter:只处理过滤器链中抛出的任何AccessDeniedException和AuthenticationException ,其他异常继续抛出。
- FilterSecurityInterceptor:负责权限校验的过滤器。
3.1 认证流程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ailkTJHA-1680426554649)(null)]
注释:
- Authentication:是一个接口,它的实现类表示当前访问系统的用户,封装了用户相关信息。
- AuthenticationManager:也是一个接口,声明了认证Authentication的方法
- UserDetailsService:还是一个接口,加载用户特定数据的核心接口。里面定义了一个根据用户名查询用户信息的方法。
- UserDetails:接口,提供核心用户信息。通过UserDetailsService根据用户名获取处理的用户信息要封装成UserDetails对象返回。然后将这些信息封装到Authentication对象中。
3.2 登录校验问题
登录流程:
-
自定义登录接口替代原有登录接口。
-
自定义实现UserDetailService接口的类A,替代原有实现类。
-
在类A中中查询数据库进行认证校验。
-
校验通过则使用jwt工具类生成token,token生成规则有两种:
4.1 使用用户id生成token,其余用户信息存入redis。
4.2 使用用户基本信息的json串(脱敏)生成token,服务端不必存储用户信息。
校验流程:
-
自定义jwt认证过滤器。
-
解析token。
2.1 解析获得用户id,根据用户id从redis中获得用户信息,存入SecurityContextHolder。
2.2 解析获得用户信息json串,将其反序列化为用户对象,存入SecurityContextHolder。
在这里我们采用第一种方案,使用redis。
3.3 实现
3.3.1 实现UserDetailsService接口
创建UserDetailsService接口的实现类,在其中对用户进行认证和授权。
@Service
public class UserDetailServiceImpl implements UserDetailsService {@Autowiredprivate UserMapper userMapper;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//认证LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(StringUtils.isNotBlank(username), User::getUserName, username);User user = userMapper.selectOne(queryWrapper);if (Objects.isNull(user)) {throw new RuntimeException("用户名或密码错误");}//todo 查询对应的权限信息//把数据封装成UserDetails返回UserDetails userDetails = org.springframework.security.core.userdetails.User.withUsername(user.getUserName()).password(user.getPassword()).authorities(new String[]{}).build();return userDetails;}
}
除了使用security提供的生成UserDetails对象的方法外,我们还可以选择自定义。
我们新创建一个类 LoginUser
实现 UserDetails
接口。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class LoginUser implements UserDetails {private User user;@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return null;}@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;}
}
使用我们自定义的类去创建UserDetails对象。
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//认证LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(StringUtils.isNotBlank(username), User::getUserName, username);User user = userMapper.selectOne(queryWrapper);if (Objects.isNull(user)) {throw new RuntimeException("用户名或密码错误");}//todo 查询对应的权限信息//把数据封装成UserDetails返回return new LoginUser(user);
}
3.3.2 密码存储和校验
我们不会在数据库中使用明文的方式存储密码,我们需要存储的是加密之后的密码。
SpringSecurity默认使用的PasswordEncoder要求数据库中的密码格式为:{id}password 。它会根据id去判断密码的加密方式。这种方式不太行,所以我们需要使用BCryptPasswordEncoder去替代原来的PasswordEncoder。
我们只需要定义一个SpringSecurity的配置类,并且让这个类继承 WebSecurityConfigurerAdapter
。
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {//创建 BCryptPasswordEncoder 对象并注入容器@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}
}
3.3.3 自定义登录接口
创建一个控制器 LoginController
,在其中定义一个登录接口:
@RestController
public class LoginController {@Autowiredprivate UserService userService;@PostMapping("/user/login")public ResponseResult login(@RequestBody User user) {return userService.login(user);}
}
3.3.3.1 配置
我们需要让SpringSecurity对自定义的接口放行,让用户不用登陆也可以访问。然后在 login(user)
中调用AuthenticationManager的authenticate方法来进行用户认证,所以需要在SpringSecurity配置类中进行以下两点配置:
- 对自定义登录接口放行
- 把
AuthenticationManager
对象注入容器
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {//创建 BCryptPasswordEncoder 对象并注入容器@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}//注入AuthenticationManager对象@Override@Beanpublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}//对登录接口放行@Overrideprotected void configure(HttpSecurity http) throws Exception {http//关闭csrf.csrf().disable()//不通过Session获取SecurityContext.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()// 对于登录接口 允许匿名访问(未登录时可以访问,登陆后不能访问).antMatchers("/user/login").anonymous()// 除上面外的所有请求全部需要鉴权认证.anyRequest().authenticated();}
}
3.3.3.2 定义登录方法
在用户服务接口的实现类中定义 login(user)
方法:
@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Autowiredprivate AuthenticationManager authenticationManager;@Overridepublic ResponseResult login(User user) {//调用 AuthenticationManager 对象的 authenticate() 方法进行用户认证UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserName(), user.getPassword());Authentication authenticate = null;try {authenticate = authenticationManager.authenticate(authenticationToken);} catch (Exception e) {throw new RuntimeException(e.getMessage());}if (authenticate == null) {throw new RuntimeException("登陆失败");}//如果认证未通过,则给出对应提示//通过,则使用userid生成一个jwt,jwt存入ResponseResultLoginUser loginUser = (LoginUser) authenticate.getPrincipal();String userId = loginUser.getUser().getId().toString();String jwt = JwtUtil.createJWT(userId);Map<String, String> map = new HashMap<>();map.put("token", jwt);//把用户信息存入redisstringRedisTemplate.opsForValue().set("login:" + userId, JSON.toJSONString(loginUser));return new ResponseResult(200, "登录成功", map);}
}
3.3.4 自定义认证过滤器
我们需要一个认证过滤器,作用是取出每次请求的请求头,看它是否携带 token
。再对 token
进行校验,判断用户的登录状态。
@Component
public class JwtAuthenticactionTokenFilter extends OncePerRequestFilter {@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {//获取tokenString token = request.getHeader("token");if (StringUtils.isBlank(token)) {//没有token//放行,让后面的认证过滤器去拒绝filterChain.doFilter(request, response);return;}//解析tokenString userId;try {Claims claims = JwtUtil.parseJWT(token);userId = claims.getSubject();} catch (Exception e) {e.printStackTrace();throw new RuntimeException("token非法");}//拼接redis的keyString key = "login:" + userId;String userJson = stringRedisTemplate.opsForValue().get(key);if (StringUtils.isBlank(userJson)) {throw new RuntimeException("用户未登录");}LoginUser loginUser = JSON.parseObject(userJson, LoginUser.class);//存入SecurityContextHolder//todo 还未授权UsernamePasswordAuthenticationToken authenticationToken =new UsernamePasswordAuthenticationToken(loginUser, null, null);SecurityContextHolder.getContext().setAuthentication(authenticationToken);//放行filterChain.doFilter(request, response);}
}
3.3.4.1 确定过滤器顺序
定义了认证过滤器后,我们还需要确定过滤器的执行顺序,我们必须保证这个过滤器的执行在Security的认证过滤器之前,所以我们把他放在 UsernamePasswordAuthenticationFilter
之前比较合适。
找到之前的配置类,从容器中取出自定义的 JwtAuthenticactionTokenFilter
过滤器并在 configure()
方法中加入最后一行代码。
@Autowired
private JwtAuthenticactionTokenFilter jwtAuthenticactionTokenFilter;protected void configure(HttpSecurity http) throws Exception {http//关闭csrf.csrf().disable()//不通过Session获取SecurityContext.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()// 对于登录接口 允许匿名访问(未登录时可以访问,登陆后不能访问).antMatchers("/user/login").anonymous()// 除上面外的所有请求全部需要鉴权认证.anyRequest().authenticated();//把自定义认证过滤器放在 UsernamePasswordAuthenticationFilter 过滤波器前面http.addFilterBefore(jwtAuthenticactionTokenFilter, UsernamePasswordAuthenticationFilter.class);
}
3.3.5 自定义退出登录接口
退出流程:
- 通过
SecurityContextHolder
获得用户id - 利用用户id凭借redis的key值
- 通过key值把redis中的用户信息删除
首先定义一个退出接口:
@RequestMapping("/user/logout")
public ResponseResult logout() {return userService.logout();
}
在实现类中定义 logout()
方法:
@Override
public ResponseResult logout() {//获取SecurityContextHolder中的用户idAuthentication authentication = SecurityContextHolder.getContext().getAuthentication();LoginUser loginUser = (LoginUser) authentication.getPrincipal();Long id = loginUser.getUser().getId();//删除redis中的值stringRedisTemplate.delete("login:" + id);return new ResponseResult(200, "退出成功");
}
4. 授权
4.1 授权流程
在SpringSecurity中,会使用默认的FilterSecurityInterceptor来进行权限校验。在FilterSecurityInterceptor中会从SecurityContextHolder获取其中的Authentication,然后获取其中的权限信息。当前用户是否拥有访问当前资源所需的权限。
4.2 实现
4.2.1 开启全局权限功能
@EnableGlobalMethodSecurity(prePostEnabled = true)
开启功能之后,我们就可以在接口方法上面加上 @PreAuthorize
注解了。
@RequestMapping("/hello")
@PreAuthorize("hasAuthority('test')")
public String hello() {return "hello";
}
4.2.2 封装权限信息
权限的封装是在登录流程时发生的,所以我们在登录方法中把权限信息封装进入 UserDetails
的实现类中:
@Data
@NoArgsConstructor
public class LoginUser implements UserDetails {private User user;//权限字符串集合private List<String> permissions;//权限集合,不用序列化到redis@JSONField(serialize = false)private Set<SimpleGrantedAuthority> authorities;public LoginUser(User user, List<String> permissions) {this.user = user;this.permissions = permissions;}//将权限字符串集合封装成权限集合@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {if (authorities == null) {authorities = permissions.stream().map(item -> new SimpleGrantedAuthority(item)).collect(Collectors.toSet());}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;}
}
修改完毕,我们先在登录校验方法 loadUserByUsername(String username)
中查询数据库得到权限字符串集合:
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//认证LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(StringUtils.isNotBlank(username), User::getUserName, username);User user = userMapper.selectOne(queryWrapper);if (Objects.isNull(user)) {throw new RuntimeException("用户名或密码错误!");}//查询对应的权限信息List<String> list = menuMapper.selectPermsByUserId(user.getId());return new LoginUser(user, list);
}
然后在自定义过滤器中补充权限设置:
UsernamePasswordAuthenticationToken authenticationToken =new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
4.3 自定义权限校验方法
Security提供的权限校验方法比较单一,且不灵活。所以我们可以自定义权限校验方法并且在注解中使用我们的方法。
1)自定义权限校验方法
创建一个类并注入容器中,在其中编写我们的校验方法:
@Component(value = "ex")
public class ExpressionRoot {public boolean hasAuthority(String authority) {//获取当前用户的权限Authentication authentication = SecurityContextHolder.getContext().getAuthentication();LoginUser loginUser = (LoginUser) authentication.getPrincipal();List<String> permissions = loginUser.getPermissions();//判断用户是否拥有访问权限return permissions.contains(authority);}
}
2)在注解中使用我们的方法
@RequestMapping("/hello")
//@PreAuthorize("hasAuthority('system:dept:list')")
@PreAuthorize("@ex.hasAuthority('system:dept:list')")
public String hello() {return "hello";
}
4.4 基于配置的权限控制
我们上面的示例都是基于注解的权限控制,我们也可以通过配置来进行权限的控制,如下所示:
http.authorizeRequests()// 对于登录接口 允许匿名访问.antMatchers("/user/login").anonymous()//基于配置的权限控制.antMatchers("/testCors").hasAuthority("system:dept:list222")// 除上面外的所有请求全部需要鉴权认证.anyRequest().authenticated();
5. 自定义失败处理
我们还希望在认证失败或者是授权失败的情况下也能和我们的接口一样返回相同结构的json,这样可以让前端能对响应进行统一的处理。要实现这个功能我们需要知道SpringSecurity的异常处理机制。
在SpringSecurity中,如果我们在认证或者授权的过程中出现了异常会被ExceptionTranslationFilter捕获到。在ExceptionTranslationFilter中会去判断是认证失败还是授权失败出现的异常。
如果是认证过程中出现的异常会被封装成AuthenticationException然后调用AuthenticationEntryPoint对象的方法去进行异常处理。
如果是授权过程中出现的异常会被封装成AccessDeniedException然后调用AccessDeniedHandler对象的方法去进行异常处理。
所以如果我们需要自定义异常处理,我们只需要自定义AuthenticationEntryPoint和AccessDeniedHandler然后配置给SpringSecurity即可。
5.1 认证失败处理器
自定义认证失败处理器:
@Component
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {@Overridepublic void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {ResponseResult result = new ResponseResult(HttpStatus.UNAUTHORIZED.value(), "用户认证失败请重新登录");String json = JSON.toJSONString(result);//处理异常WebUtils.renderString(httpServletResponse, json);}
}
在 WebUtils
工具类中对响应进行封装,具体方法如下:
public static String renderString(HttpServletResponse response, String string) {try{response.setStatus(200);response.setContentType("application/json");response.setCharacterEncoding("utf-8");response.getWriter().print(string);}catch (IOException e){e.printStackTrace();}return null;
}
5.2 权限不足处理器
自定义权限不足处理器:
@Component
public class AccessDeniedHandlerImpl implements AccessDeniedHandler {@Overridepublic void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {ResponseResult result = new ResponseResult(HttpStatus.FORBIDDEN.value(), "权限不足");String json = JSON.toJSONString(result);//处理异常WebUtils.renderString(httpServletResponse, json);}
}
5.3 配置
我们将这两个处理器注入容器,再将其配置到Security中:
@Autowired
private AuthenticationEntryPoint authenticationEntryPoint;@Autowired
private AccessDeniedHandler accessDeniedHandler;//对登录接口放行
@Override
protected void configure(HttpSecurity http) throws Exception {//省略其他配置......//配置异常处理器http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)//认证失败处理器.accessDeniedHandler(accessDeniedHandler);//授权失败处理器
}
6. 跨域问题
只有浏览器和服务端的之间的请求有跨域问题,服务端和服务端之间是不存在跨域问题的。
我们首先在我们的springboot项目中进行跨域配置:
@Configuration
public class CorsConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {// 设置允许跨域的路径registry.addMapping("/**")// 设置允许跨域请求的域名.allowedOriginPatterns("*")// 是否允许cookie.allowCredentials(true)// 设置允许的请求方式.allowedMethods("GET", "POST", "DELETE", "PUT")// 设置允许的header属性.allowedHeaders("*")// 跨域允许时间.maxAge(3600);}
}
由于我们的资源都会收到SpringSecurity的保护,所以想要跨域访问还要让SpringSecurity运行跨域访问。
然后在security的配置类中添加跨域配置:
@Override
protected void configure(HttpSecurity http) throws Exception {//省略其他配置......//允许跨域http.cors();
}
相关文章:

【SpringSecurity】认证授权框架——SpringSecurity使用方法
【SpringSecurity】认证授权框架——SpringSecurity使用方法 文章目录【SpringSecurity】认证授权框架——SpringSecurity使用方法1. 概述2. 准备工作2.1 引依赖2.2 测试3. 认证3.1 认证流程3.2 登录校验问题3.3 实现3.3.1 实现UserDetailsService接口3.3.2 密码存储和校验3.3.…...

java的Lambda表达式与方法引用详解
1. 定义 Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。 Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。 使用 Lambda 表达式可以使代码变的更加简洁紧凑。 1.1 通用定义 lambda 表达…...

JUnit5用户手册~并行执行
两种运行模式 SAME_THREAD:默认的,测试方法在同一个线程CONCURRENT:并行执行,除非有资源锁junit-platform.properties配置参数配置所有测试方法都并行 junit.jupiter.execution.parallel.enabled true junit.jupiter.execution.…...
【从零开始学习 UVM】3.3、UVM TestBench架构 —— UVM Environment [uvm_env]
文章目录 什么是UVM Environment?为什么验证组件不应该直接放置在test class中?创建UVM环境的步骤UVM环境示例Examples环境重用示例什么是UVM Environment? 一个UVM环境包含多个可重用的验证组件,并根据应用程序要求定义它们的默认配置。例如,一个UVM环境可能有多个agent…...

Vue的简单介绍
一、简介 Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面。无论是简单还是复杂的界面,…...

我给Chat GPT写了个记忆系统
ChatGPT-LifeTime OpenAI 的模型有一个固定的 Token 限制,例如 GPT-3 的 Davinci 模型最多可以处理2049 个 Token,大约 1500 个英文单词。最新 Turbo 模型大约是 4,096 个 Token,大约是 3000 个英文单词,也就是意味着Chat GPT它会…...

哈希表题目:砖墙
文章目录题目标题和出处难度题目描述要求示例数据范围解法思路和算法代码复杂度分析题目 标题和出处 标题:砖墙 出处:554. 砖墙 难度 5 级 题目描述 要求 你的面前有一堵矩形的、由 n\texttt{n}n 行砖块组成的砖墙。这些砖块高度相同(…...

【程序环境详解】
每个源程序(.c文件)都需要经过编译链接形成 .exe的可执行文件。 在ANSI C的任何一种实现中,存在两个不同的环境 第一种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。第二种是执行环境,它用于实际执行代码…...

栈(Stack)
目录 1.1 概念 1.2 栈的使用 1.3 栈的模拟实现 1.4 栈的应用场景 1. 改变元素的序列 2. 将递归转化为循环 1.1 概念 栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为…...

【计算机网络】2、网络编程模型理论
文章目录一、网络基本概念1.1 网段1.2 子网掩码 netmask1.3 子网 subnet1.4 网络地址 network1.5 实战 192.168.0.1/27 的含义二、socket2.1 sockaddr 格式2.1.1 IPv4 sockaddr 格式2.1.2 IPv6 sockaddr 格式2.1.3 本地 sockaddr 格式2.2 http 与 websocket三、TCP 编程3.1 ser…...

jmeter接口测试及详细步骤以及项目实战教程
如果看完这篇文章还是不太明白的话,可以看看下面这个视频 2023年B站最新Jmeter接口测试实战教程,精通接口自动化测试只需要这一套视频_哔哩哔哩_bilibili2023年B站最新Jmeter接口测试实战教程,精通接口自动化测试只需要这一套视频共计16条视…...
抖音进攻,B站退守
“爱优腾芒”等长视频平台的崛起,在一定层面上丰富了人们的日常生活,而抖音、快手等短视频平台的出现,则在很大程度上改变了用户观看视频的方式。只不过,近几年,随着流量增长逐渐遭遇瓶颈,各视频平台便纷纷…...

2022国赛E题完整成品文章数据代码模型--小批量物料的生产安排
基于LSTM循环神经网络的小批量物料生产安排分析 摘要 某电子产品制造企业面临以下问题:在多品种小批量的物料生产中,事先无法知道物料的 实际需求量。企业希望运用数学方法,分析已有的历史数据,建立数学模型,帮助企业…...

学生党,快来 Azure 一起学习 OpenAI (一):注册 Azure 和申请 OpenAI
大家好我是微软学生大使 Jambo , 在刚结束的微软学生开发者峰会 2023中我们了解到微软为学生提供了 Azure for Student 大礼包,通过 Azure for Student 除了学习和部署云原生的应用外,还可以申请使用 Microsoft OpenAI Service 。在这个 AIGC 火热的年代…...

深入理解【正则化的L1-lasso回归和L2-岭回归】以及相关代码复现
正则化--L1-lasso回归和L2-岭回归1- 过拟合 欠拟合 模型选择2- 正则L1与L23- L2正则代码复现3-1 底层逻辑实现3-2 简洁实现1- 过拟合 欠拟合 模型选择 1-1 欠拟合: 在训练集和测试集上都不能很好的拟合数据【模型过于简单】 原因: 学习到的数据特征过少 …...

入侵检测——如何实现反弹shell检测?
反弹shell的本质:就是控制端监听在某TCP/UDP端口,被控端发起请求到该端口,并将其命令行的输入输出转到控制端。reverse shell与telnet,ssh等标准shell对应,本质上是网络概念的客户端与服务端的角色反转。 反弹shell的结…...

Python常用语句学习
人生苦短,我用Python。 ——吉多范罗苏姆 文章目录前言一、判断语句(一)if语句1. 作用2. 构成3. 语法4. 样例5.说明(二)if嵌套二、循环语句(一)while循环1. 作用2. 语法3. 样例4. 说明ÿ…...

测试3年还不如应届生,领导一句点醒:“公司不是只雇你来点点点的”
你的身边,是否有这样的景象? A:写了几年代码,写不下去了,听说测试很好上手,先来做几年测试 。 B:小文员一枚,想入行 IT,听说测试入门简单,请问怎么入行 。 …...

华为网络设备之路由策略,前缀列表(使用,规则)
华为网络之路由策略 前言:在企业网络的设备通信中,常面临一些非法流量访问的安全性及流量路径不优等问题,故为保证数据访问的安全性、提高链路带宽利用率,就需要对网络中的流量行为进行控制,如控制网络流量可达性、调…...
白噪音简介与实现
一、简介: 白噪音(White Noise)是一种具有平均功率频谱密度的噪音信号,其功率在所有频率上均匀分布。白噪音是一种随机信号,其包含所有频率成分的等幅随机振荡。因此,白噪音看起来像是一种随机的“嘈杂声”…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...

简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...

Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...

沙箱虚拟化技术虚拟机容器之间的关系详解
问题 沙箱、虚拟化、容器三者分开一一介绍的话我知道他们各自都是什么东西,但是如果把三者放在一起,它们之间到底什么关系?又有什么联系呢?我不是很明白!!! 就比如说: 沙箱&#…...

goreplay
1.github地址 https://github.com/buger/goreplay 2.简单介绍 GoReplay 是一个开源的网络监控工具,可以记录用户的实时流量并将其用于镜像、负载测试、监控和详细分析。 3.出现背景 随着应用程序的增长,测试它所需的工作量也会呈指数级增长。GoRepl…...

智警杯备赛--excel模块
数据透视与图表制作 创建步骤 创建 1.在Excel的插入或者数据标签页下找到数据透视表的按钮 2.将数据放进“请选择单元格区域“中,点击确定 这是最终结果,但是由于环境启不了,这里用的是自己的excel,真实的环境中的excel根据实训…...