SpringSecurity中文文档(Servlet Session Management)

Authentication Persistence and Session Management

一旦您拥有了正在对请求进行身份验证的应用程序,就必须考虑如何在将来的请求中持久化和恢复结果身份验证。

默认情况下,这是自动完成的,因此不需要额外的代码,尽管了解 requireExplicitSave在 HttpSecurity 中的含义非常重要。

如果您愿意,您可以关于 RequureExplicSave 正在做什么 requireExplicitSave is doing 或者为什么它很重要why it’s important的内容。否则,在大多数情况下您将完成本节。

但是在离开之前,考虑一下这些用例是否适合您的应用程序:

  • 我想了解会话管理的组成部分(I want to Understand Session Management’s components)
  • 我想限制用户可以同时登录的次数(I want to restrict the number of times a user can be logged in concurrently)
  • 我想自己直接存储身份验证,而不是由 Spring Security 代劳(I want to store the authentication directly myself instead of Spring Security doing it for me)
  • 我正在手动存储身份验证,我想删除它(I am storing the authentication manually and I want to remove it)
  • 我正在使用 SessionManagementFilter,我需要远离它的指导(I am using SessionManagementFilter and I need guidance on moving away from that)
  • 我希望将身份验证存储在会话之外的其他内容中(I want to store the authentication in something other than the session)
  • 我正在使用无状态身份验证,但是我仍然希望将其存储在会话中(I am using a stateless authentication, but I’d still like to store it in the session)
  • 我正在使用 SessionCreationPolicy.Never,但是应用程序仍然在创建会话。(I am using SessionCreationPolicy.NEVER but the application is still creating sessions.)

Understanding Session Management’s Components

会话管理支持由几个组件组成,它们共同提供功能。

这些组件是 SecurityContextHolderFilterSecurityContextPersistenceFilterSessionManagementFilter

在 SpringSecurity6中,默认情况下不设置 SecurityContextPersisenceFilter 和 SessionManagementFilter。除此之外,任何应用程序都应该只设置 SecurityContextHolderFilter 或 SecurityContextPersisenceFilter,而不能同时设置两者。

The SessionManagementFilter

SessionManagementFilter 根据 SecurityContextHolder 的当前内容检查 SecurityContextRepository 的内容,以确定用户在当前请求期间是否已被身份验证,通常是通过非交互式身份验证机制,如预先身份验证或 remember-me [1]。如果存储库包含安全上下文,则filter不执行任何操作。如果没有,并且线程本地的 SecurityContext 包含一个(非匿名的) Authentication 对象,则筛选器假定它们已经通过堆栈中以前的筛选器进行了身份验证。然后它将调用配置的 SessionAuthenticationStrategy。

如果用户当前没有经过身份验证,filter 将检查是否请求了无效的会话 ID (例如,由于超时) ,并在设置了一个会话 ID 的情况下调用配置的 InvalidSessionStrategy。最常见的行为就是重定向到一个固定的 URL,这封装在标准实现 SimpleRedirectInvalidSessionStrategy 中。如前所述,在通过命名空间配置无效的会话 URL 时也使用后者。

Moving Away From SessionManagementFilter

在 Spring Security 5中,默认配置依赖于 SessionManagementFilter 来检测用户是否刚刚通过身份验证并调用 SessionAuthenticationStrategy。这样做的问题在于,它意味着在典型的设置中,必须为每个请求读取 HttpSession。

在 SpringSecurity6中,默认情况是身份验证机制本身必须调用 SessionAuthenticationStrategy。这意味着不需要检测身份验证何时完成,因此不需要为每个请求读取 HttpSession。

Things To Consider When Moving Away From SessionManagementFilter

在 Spring Security 6中,默认情况下不使用 SessionManagementFilter,因此,来自 sessionManagement DSL 的一些方法不会产生任何效果。

MethodReplacement
sessionAuthenticationErrorUrlConfigure an AuthenticationFailureHandler in your authentication mechanism
sessionAuthenticationFailureHandlerConfigure an AuthenticationFailureHandler in your authentication mechanism
sessionAuthenticationStrategyConfigure an SessionAuthenticationStrategy in your authentication mechanism as discussed above

如果尝试使用这些方法中的任何一种,将引发异常。

Customizing Where the Authentication Is Stored

默认情况下,SpringSecurity 在 HTTP 会话中为您存储安全上下文。然而,这里有几个你可能需要自定义的原因:

  • 您可能希望在 HttpSessionSecurityContextRepository 实例上调用个别的setters
  • 您可能希望将安全上下文存储在缓存或数据库中,以启用水平伸缩

首先,您需要创建 SecurityContextRepository 的实现,或者使用类似 HttpSessionSecurityContextRepository 的现有实现,然后您可以在 HttpSecurity 中设置它。

Customizing the SecurityContextRepository

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {SecurityContextRepository repo = new MyCustomSecurityContextRepository();http// ....securityContext((context) -> context.securityContextRepository(repo));return http.build();
}

上述配置设置 SecurityContextHolderFilter 上的 SecurityContextRepository 和参与身份验证过滤器,如 UsernamePasswordAuthenticationFilter。要在无状态筛选器中设置它,请参阅如何自定义 SecurityContextRepository for Statless Authentication。

如果使用自定义身份验证机制,则可能希望自己存储身份验证。

Storing the Authentication manually

例如,在某些情况下,您可能需要手动验证用户,而不是依赖于 Spring Security filters。您可以使用自定义过滤器或 Spring MVC 控制器端点来完成这项工作。如果要在请求之间保存身份验证,例如,在 HttpSession 中,必须这样做:

private SecurityContextRepository securityContextRepository =new HttpSessionSecurityContextRepository(); // 1@PostMapping("/login")
public void login(@RequestBody LoginRequest loginRequest, HttpServletRequest request, HttpServletResponse response) { // 2UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken.unauthenticated(loginRequest.getUsername(), loginRequest.getPassword()); // 3 Authentication authentication = authenticationManager.authenticate(token); // 4 SecurityContext context = securityContextHolderStrategy.createEmptyContext();context.setAuthentication(authentication); // 5securityContextHolderStrategy.setContext(context);securityContextRepository.saveContext(context, request, response); // 6
}class LoginRequest {private String username;private String password;// getters and setters
}
  1. 将 SecurityContextRepository 添加到控制器
  2. 注入 HttpServletRequest 和 HttpServletResponse 以保存 SecurityContext
  3. 使用提供的凭据创建未经身份验证的 UsernamePasswordAuthenticationToken
  4. 调用 AuthenticationManager # authenticate 对用户进行身份验证
  5. 创建 SecurityContext 并在其中设置身份验证
  6. 在 SecurityContextRepository 中保存 SecurityContext

就是这样。如果您不确定上面示例中的 securityContextHolderStrategy 是什么,可以在使用 SecurityContextStrategy 部分了解更多信息。

Properly Clearing an Authentication

如果您正在使用 Spring Security 的 Logout Support,那么它将为您处理许多事情,包括清除和保存上下文。但是,假设您需要手动将用户从应用程序中注销。在这种情况下,您需要确保正确地清除和保存上下文。

Configuring Persistence for Stateless Authentication

例如,有时不需要创建和维护 HttpSession,以便跨请求持久化身份验证。某些身份验证机制(如 HTTPBasic)是无状态的,因此会在每个请求上重新验证用户。

如果您不希望创建会话,可以使用 SessionCreationPolicy. STATELSS,如下所示:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {http// ....sessionManagement((session) -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));return http.build();
}

上述配置正在将 SecurityContextRepository 配置为使用 NullSecurityContextRepository,并且还阻止将请求保存到会话中。

如果您使用的是 SessionCreationPolicy. NEVER,您可能会注意到应用程序仍然在创建 HttpSession。在大多数情况下,发生这种情况是因为请求被保存在会话中,以便在身份验证成功后再次请求经过身份验证的资源。为了避免这种情况,请参考如何防止请求被保存 how to prevent the request of being saved 节。

Storing Stateless Authentication in the Session

如果出于某种原因,您正在使用无状态身份验证机制,但仍然希望在会话中存储身份验证,则可以使用 HttpSessionSecurityContextRepository 而不是 NullSecurityContextRepository。

对于 HTTP Basic,可以添加一个 ObjectPostProcessor,用于更改 BasicAuthenticationFilter 使用的 SecurityContextRepository:

Store HTTP Basic authentication in the HttpSession

@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {http// ....httpBasic((basic) -> basic.addObjectPostProcessor(new ObjectPostProcessor<BasicAuthenticationFilter>() {@Overridepublic <O extends BasicAuthenticationFilter> O postProcess(O filter) {filter.setSecurityContextRepository(new HttpSessionSecurityContextRepository());return filter;}}));return http.build();
}

上述方法也适用于其他身份验证机制,如承载令牌身份验证。

在 Spring Security 5中,默认行为是使用 SecurityContextPersisenceFilter 将 SecurityContext 自动保存到 SecurityContextRepository。必须在提交 HttpServletResponse 之前和 SecurityContextPersisenceFilter 之前保存。不幸的是,SecurityContext 的自动持久化在请求完成之前(即在提交 HttpServletResponse 之前)完成时可能会让用户感到惊讶。跟踪状态以确定是否需要保存,从而导致有时不必要地写入 SecurityContextRepository (即 HttpSession)也很复杂。

由于这些原因,不推荐使用 SecurityContextHolderFilter 替换 SecurityContextPersisenceFilter。在 Spring Security 6中,默认行为是 SecurityContextHolderFilter 将只从 SecurityContextRepository 读取 SecurityContext 并在 SecurityContextHolder 中填充它。用户现在必须使用 SecurityContextRepository 显式地保存 SecurityContext,如果他们希望 SecurityContext 在请求之间保持的话。这样可以消除模糊性,并在必要时只需要写入 SecurityContextRepository (即 HttpSession) ,从而提高性能。

How it works

总而言之,如果 requireExplicitSave 为 true,Spring Security 将设置 SecurityContextHolderFilter 而不是 SecurityContextPersisenceFilter

Configuring Concurrent Session Control

如果您希望限制单个用户登录到您的应用程序的能力,Spring Security 通过以下简单的添加支持开箱即用。首先,您需要将以下侦听器添加到您的配置中,以保持 Spring Security 对会话生命周期事件的更新:

@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {return new HttpSessionEventPublisher();
}

然后在安全配置中添加以下代码行:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {http.sessionManagement(session -> session.maximumSessions(1));return http.build();
}

这将阻止用户多次登录——第二次登录将导致第一次登录失效。

使用 Spring Boot,您可以通过以下方式测试上面的配置场景:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class MaximumSessionsTests {@Autowiredprivate MockMvc mvc;@Testvoid loginOnSecondLoginThenFirstSessionTerminated() throws Exception {MvcResult mvcResult = this.mvc.perform(formLogin()).andExpect(authenticated()).andReturn();MockHttpSession firstLoginSession = (MockHttpSession) mvcResult.getRequest().getSession();this.mvc.perform(get("/").session(firstLoginSession)).andExpect(authenticated());this.mvc.perform(formLogin()).andExpect(authenticated());// first session is terminated by second loginthis.mvc.perform(get("/").session(firstLoginSession)).andExpect(unauthenticated());}}

可以使用“最大会话”示例进行尝试。

另外,通常您希望防止第二次登录,在这种情况下,您可以使用:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {http.sessionManagement(session -> session.maximumSessions(1).maxSessionsPreventsLogin(true));return http.build();
}

第二次登录将被拒绝。“拒绝”的意思是,如果使用的是基于表单的登录,那么用户将被发送到身份验证-失败-url。如果第二次身份验证是通过另一种非交互机制进行的,比如“ remember-me”,那么将向客户端发送一个“未授权”(401)错误。如果希望使用错误页面,可以将属性 session-entication-error-url 添加到session-management元素中。

使用 Spring Boot,您可以通过以下方式测试上述配置:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class MaximumSessionsPreventLoginTests {@Autowiredprivate MockMvc mvc;@Testvoid loginOnSecondLoginThenPreventLogin() throws Exception {MvcResult mvcResult = this.mvc.perform(formLogin()).andExpect(authenticated()).andReturn();MockHttpSession firstLoginSession = (MockHttpSession) mvcResult.getRequest().getSession();this.mvc.perform(get("/").session(firstLoginSession)).andExpect(authenticated());// second login is preventedthis.mvc.perform(formLogin()).andExpect(unauthenticated());// first session is still validthis.mvc.perform(get("/").session(firstLoginSession)).andExpect(authenticated());}}

如果对基于表单的登录使用自定义身份验证filter,则必须显式配置并发会话控制支持。您可以使用“最大会话防止登录”示例尝试使用它。

Detecting Timeouts

会话会自行到期,不需要做任何事情来确保删除安全上下文。也就是说,SpringSecurity 可以检测会话何时过期,并采取您指示的特定操作。例如,当用户使用已过期的会话发出请求时,您可能希望重定向到特定的端点。这是通过 HttpSecurity 中的无效 SessionUrl 实现的:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {http.sessionManagement(session -> session.invalidSessionUrl("/invalidSession"));return http.build();
}

请注意,如果使用此机制检测会话超时,则如果用户注销然后在没有关闭浏览器的情况下重新登录,则可能会错误地报告错误。这是因为当您使会话无效时,会话 cookie 不会被清除,即使用户已经登出,它也会被重新提交。如果是这种情况,您可能需要配置注销以清除会话 cookie。

Customizing the Invalid Session Strategy

ValidSessionUrl 是一种方便的方法,用于使用 SimpleRedirectInvalidSessionStrategy 实现设置 InvalidSessionStrategy。如果希望自定义行为,可以实现 InvalidSessionStrategy 接口,并使用 valididSessionStrategy 方法对其进行配置:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {http.sessionManagement(session -> session.invalidSessionStrategy(new MyCustomInvalidSessionStrategy()));return http.build();
}

Clearing Session Cookies on Logout

你可以在注销时显式地删除这个 JSESSIONID cookie,例如在注销处理程序中使用 Clear-Site-Data 头:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {http.logout((logout) -> logout.addLogoutHandler(new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter(COOKIES))));return http.build();
}

这样做的好处是容器不可知,并且适用于任何支持 Clear-Site-Data 报头的容器。

作为替代,您还可以在注销处理程序中使用以下语法:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {http.logout(logout -> logout.deleteCookies("JSESSIONID"));return http.build();
}

不幸的是,这并不能保证在每个 servlet 容器中都能正常工作,因此您需要在您的环境中对其进行测试。

Understanding Session Fixation Attack Protection

会话固定攻击是一种潜在的风险,恶意攻击者可能通过访问一个站点来创建一个会话,然后说服另一个用户使用相同的会话登录(例如,通过向他们发送一个包含会话标识符作为参数的链接)。SpringSecurity 通过创建新会话或在用户登录时更改会话 ID 来自动防止这种情况发生。

Configuring Session Fixation Protection

你可以通过选择三个推荐的选项来控制会话固定保护策略:

  • ChangeSessionId-不要创建新的会话,而是使用 Servlet 容器(HttpServletRequest # changeSessionId ())提供的会话固定保护。此选项仅在 Servlet 3.1(JavaEE7)和更新的容器中可用。在旧容器中指定它将导致异常。这是 Servlet 3.1和更新的容器中的默认值。
  • NewSession-创建一个新的“ clean”会话,不复制现有的会话数据(仍将复制与 Spring Security 相关的属性)。
  • MigateSession-创建一个新会话并将所有现有会话属性复制到新会话。这是 Servlet 3.0或更老的容器中的默认值。

您可以通过以下方法配置会话固定保护:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {http.sessionManagement((session) -> session.sessionFixation((sessionFixation) -> sessionFixation.newSession()));return http.build();
}

当发生会话固定保护时,会导致在应用程序上下文中发布 SessionFixationProtectionEvent。

如果您使用 changeSessionId,这种保护也会导致任何 jakarta.servlet.http.HttpSessionIdListener 正在通知 ,因此如果您的代码同时侦听这两个事件,请谨慎使用。

您还可以将会话固定保护设置为无,以禁用它,但是不建议这样做,因为这会使您的应用程序容易受到攻击。

Using SecurityContextHolderStrategy

考虑以下代码块:

UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword());
Authentication authentication = this.authenticationManager.authenticate(token);
// ...
SecurityContext context = SecurityContextHolder.createEmptyContext(); // 1
context.setAuthentication(authentication);// 2
SecurityContextHolder.setContext(context);// 3
  1. 通过静态访问 SecurityContextHolder 创建一个空的 SecurityContext 实例。
  2. 设置 SecurityContext 实例中的 Authentication 对象。
  3. 静态设置 SecurityContextHolder 中的 SecurityContext 实例。

虽然上面的代码工作得很好,但它可能会产生一些不想要的效果: 当组件通过 SecurityContextHolder 静态访问 SecurityContext 时,当有多个应用程序上下文需要指定 SecurityContextHolderStrategy 时,这可能会创建竞态条件。这是因为在 SecurityContextHolder 中,每个类加载器有一个策略,而不是每个应用程序上下文有一个策略。

为了解决这个问题,组件可以从应用程序上下文连接 SecurityContextHolderStrategy。默认情况下,他们仍然会从 SecurityContextHolder 查找策略。

这些变化很大程度上是内部的,但是它们为应用程序提供了自动连接 SecurityContextHolderStrategy 而不是静态访问 SecurityContext 的机会。为此,应将代码更改为:

public class SomeClass {private final SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder.getContextHolderStrategy();public void someMethod() {UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken.unauthenticated(loginRequest.getUsername(), loginRequest.getPassword());Authentication authentication = this.authenticationManager.authenticate(token);// ...SecurityContext context = this.securityContextHolderStrategy.createEmptyContext(); // 1context.setAuthentication(authentication);// 2this.securityContextHolderStrategy.setContext(context);// 3}}
  1. 使用配置的 SecurityContextHolderStrategy 创建一个空的 SecurityContext 实例。
  2. 设置 SecurityContext 实例中的 Authentication 对象。
  3. 设置 SecurityContextHolderStrategy 中的 SecurityContext 实例。

Forcing Eager Session Creation

有时,急切地创建会话可能很有价值。这可以通过使用 ForceEagerSessionCreationFilter 完成,该过滤器可以使用以下方式配置:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {http.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.ALWAYS));return http.build();
}

延伸阅读

使用 Spring Session的集群Seession

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

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

相关文章

手机歌曲怎么转换成mp3格式,手机电脑都能轻松搞定

不同的手机和音乐应用可能支持不同的音频格式&#xff0c;而MP3作为一种广泛兼容的音频格式&#xff0c;因其体积小、音质相对较好的特点&#xff0c;至今仍被广泛使用。 如果您想将手机中的歌曲转换成MP3格式&#xff0c;以便于在更多设备上播放或节省存储空间&#xff0c;本…

iOS端授权页添加自定义按钮

如何添加自定义控件 基于一键登录的拉起授权页面功能&#xff0c;如果想要在我们的授权页面中添加自定义组件&#xff0c;例如使用其他方式登录的按钮&#xff0c;来实现其他方式登录功能&#xff0c;为用户呈现更多选择登录的方式。本文介绍如何在一键登录授权界面中实现添加…

机器学习之监督学习

整理一下机器学习中监督学习相关内容&#xff0c;争取梳理出一条易于理解和掌握的脉络。下面会有很多相关参考博客和文章&#xff0c;先放到一起&#xff0c;最后再做个整体的梳理。持续更新中。。。。。。 监督学习作为机器学习的核心分支&#xff0c;其理论体系与实践应用都…

C# 警告 warning MSB3884: 无法找到规则集文件“MinimumRecommendedRules.ruleset”

警告 warning MSB3884: 无法找到规则集文件“MinimumRecommendedRules.ruleset” C:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\amd64\Microsoft.CSharp.CurrentVersion.targets(129,9): warning MSB3884: 无法找到规则集文件“MinimumRe…

竞赛选题 python的搜索引擎系统设计与实现

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; python的搜索引擎系统设计与实现 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;5分创新点&#xff1a;3分 该项目较为新颖&#xff…

正则表达式在Java中的应用与实例

正则表达式在Java中的应用与实例 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 正则表达式是一种强大的工具&#xff0c;用于模式匹配和字符串处理。在Java中…

武汉星起航:成功挂牌上股交,引领跨境电商行业进入全新发展阶段

2023年10月30日&#xff0c;武汉星起航电子商务有限公司在上海股权托管交易中心成功挂牌展示&#xff0c;这一里程碑式的事件标志着武汉星起航正式登陆资本市场&#xff0c;开启了公司发展的新篇章。作为亚马逊跨境电商领域的领军企业之一&#xff0c;武汉星起航此次挂牌不仅是…

文件操作详解(C语言)

1.为什么要用到文件&#xff1f;怎样数据才能持久化&#xff1f; 保存在内存中的数不安全&#xff08;一次断电&#xff0c;忘记保存&#xff0c;不用了还给系统&#xff09; 持久化&#xff1a;保存在硬盘上&#xff08;放在文件中&#xff09; 什么是文件&#xff1f;文件…

Hadoop-08-HDFS集群 基础知识 命令行上机实操 hadoop fs 分布式文件系统 读写原理 读流程与写流程 基本语法上传下载拷贝移动文件

章节内容 上一节完成&#xff1a; HDFS的简介内容HDFS基础原理HDFS读文件流程HDFS写文件流程 背景介绍 这里是三台公网云服务器&#xff0c;每台 2C4G&#xff0c;搭建一个Hadoop的学习环境&#xff0c;供我学习。 之前已经在 VM 虚拟机上搭建过一次&#xff0c;但是没留下…

SpringSecurity的执行原理

SpringSecurity的执行原理&#xff1a;当我们服务端接收到请求后&#xff0c;首先通过DelegatingFilterProxy代理对象交互&#xff0c;转发给springsecurity的执行链&#xff0c;由于他自带的执行链有16条&#xff0c;我们将不用的过滤器进行了排除&#xff0c;同时加入了我们自…

如何保护应用?可快速部署的WAF服务器分享

Web应用攻击是安全事件和数据泄露的主要原因。相关统计表明&#xff0c;超过四分之三的网络犯罪直指应用及其漏洞。为保护数量日益增长的应用安全&#xff0c;Web应用防火墙(WAF)因此而生。本文则聚焦于WAF服务器&#xff0c;了解它的性能与具体的实践应用。   新加坡网络安全…

《单片机》期末考试复习-学习笔记总结

题型 问答题(15分)编程题(65分)编程题1(20分)编程题2(45分)设计题(20分)一、问答题 1.1.单片机概念和特点 1.2. 51单片机的中断结构 1.3.主从式多机通讯的概念及其工作原理 多机通信是指两台以上计算机之间的数据传输,主从式多机通信是多机通信系统中最简单的一种,…

PHP电商系统开发指南最佳实践

电子商务系统开发的最佳实践包括&#xff1a;数据库设计&#xff1a;选择适合关系型数据库&#xff0c;优化数据结构&#xff0c;考虑表分区&#xff1b;安全&#xff1a;加密数据&#xff0c;防止 sql 注入&#xff0c;处理会话管理&#xff1b;用户界面&#xff1a;遵循 ux 原…

vue3长列表优化,使用vue-virtual-scroller实现直播间弹幕列表虚拟滚动效果

使用的组件库是&#xff1a;https://github.com/Akryum/vue-virtual-scroller 官方文档&#xff1a;vue-virtual-scroller 安装依赖 npm install --save vue-virtual-scrollernextpnpm install --save vue-virtual-scrollernextyarn add vue-virtual-scrollernext 组件导入…

如何用文章改写ai软件进行改写?5个软件教你快速进行修改文章

如何用文章改写ai软件进行改写&#xff1f;5个软件教你快速进行修改文章 使用AI改写软件可以帮助你快速重写文章&#xff0c;使其更加流畅、符合要求或避免重复。以下是五款优质的AI改写软件&#xff0c;它们能够帮助你快速进行文章修改&#xff1a; 聪明灵犀 这是一款非常简…

数据结构_1.0

一、数据结构概述 1.1 概念 在计算机科学中&#xff0c;数据结构是一种数据组织、管理和存储的格式 。它是相互之间存在一种或多种特定关系的数据元素的集合。通常情况下&#xff0c;精心选择的数据结构可以带来更高的运行或者存储效率。数据结构往往同高效的检索算法和索引技…

【开源合规】开源许可证基础知识与风险场景引入

文章目录 什么是开源许可证(License)?开源许可证有什么用?开源许可证分类开源许可证分类及描述公共代码 (Public Domain)CC0无License宽松型许可证 (Permissive)MITApache 2.0BSD弱互惠型许可证 (Weak Copyleft)LGPLMPLEPL互惠型许可证 (Reciprocal)GPLEUPL强互惠许可证 (Str…

读-改-写操作

1 什么是读-改-写操作 “读-改-写”&#xff08;Read-Modify-Write&#xff0c;简称RMW&#xff09;是一种常见的操作模式&#xff0c;它通常用于需要更新数据的场景。 这个模式包含三个基本步骤&#xff1a; 1.读&#xff08;Read&#xff09;&#xff1a;首先读取当前的数据…

从0开始学习pyspark--pyspark的数据分析方式[第2节]

PySpark是Apache Spark的Python API&#xff0c;能够在分布式计算环境中处理大规模数据。本文将详细介绍PySpark中不同的数据分析方式&#xff0c;包括它们的使用场景、操作解释以及示例代码。 1. RDD&#xff08;Resilient Distributed Dataset&#xff09;API 概述 RDD是Sp…

Linux——查找文件-find(详细)

查找文件-find 作用 - 按照文件名、大小、时间、权限、类型、所属者、所属组来搜索文件 格式 find 查找路径 查找条件 具体条件 操作 注意 - find命令默认的操作是print输出 - find是检索文件的&#xff0c;grep是过滤文件中字符串 参数 参数 …