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) { // 2
    UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken.unauthenticated(
        loginRequest.getUsername(), loginRequest.getPassword()); // 3 
    Authentication authentication = authenticationManager.authenticate(token); // 4 
    SecurityContext context = securityContextHolderStrategy.createEmptyContext();
    context.setAuthentication(authentication); // 5
    securityContextHolderStrategy.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>() {
                @Override
                public <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 {

    @Autowired
    private MockMvc mvc;

    @Test
    void 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 login
        this.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 {

    @Autowired
    private MockMvc mvc;

    @Test
    void 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 prevented
        this.mvc.perform(formLogin()).andExpect(unauthenticated());

        // first session is still valid
        this.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(); // 1
        context.setAuthentication(authentication);// 2
        this.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.mfbz.cn/a/765564.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

百事可乐推出具有视频屏幕和人工智能技术的智能罐头

在最近于法国戛纳举行的国际创意节上&#xff0c;百事公司推出了创新的智能罐头。这些罐头不同于传统产品&#xff0c;它们采用了环绕式3D屏幕&#xff0c;能够展示高清视频内容&#xff0c;为品牌宣传和促销带来了全新的视角。经过两年多的精心研发&#xff0c;这些智能罐成为…

github仓库的基本使用-创建、上传文件、删除

1.第一步 先点击左侧菜单栏的远程仓库 2.点击NEW 3.创建仓库 然后点击右下角的 CREATE 4.点击code 点击SSH,然后我出现了You don’t have any public SSH keys in your GitHub account. You can add a new public key, or try cloning this repository via HTTPS. 1&#xff…

《大海》这歌为何经久不衰?你看歌词写的多美妙!

《大海》这歌为何经久不衰&#xff1f;你看歌词写的多美妙&#xff01; 《大海》是一首由陈大力作词&#xff0c;陈大力、陈秀男作曲&#xff0c;Ricky Ho编曲&#xff0c;张雨生演唱的国语流行歌曲。该曲收录在张雨生1992年11月30日由飞碟唱片发行的同名专辑《大海》中。 作为…

Python特征工程 — 1.2 特征分箱

目录 1 什么是特征分箱 2 分箱的重要性及其优势 3 有监督分箱 3.1卡方分箱原理 3.2 决策树分箱 4 无监督分箱 4.1 等距分箱 4.2 等频分箱 4.3 分位数分箱 实验数据&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1yT1ct_ZM5uFLgcYsaBxnHg?pwdczum 提取码&…

CM-UNet: Hybrid CNN-Mamba UNet for Remote Sensing Image Semantic Segmentation

论文&#xff1a;CM-UNet: Hybrid &#xff1a;CNN-Mamba UNet for Remote Sensing Image Semantic Segmentation 代码&#xff1a;https://github.com/XiaoBuL/CM-UNet Abstrcat: 由于大规模图像尺寸和对象变化&#xff0c;当前基于 CNN 和 Transformer 的遥感图像语义分割方…

TongRDS2214手动部署版指引(by lqw+sy)

文章目录 前言准备工作单机版集群版哨兵版多个中心节点配置 前言 由于一些特殊原因&#xff08;例如服务器没有联网&#xff0c;没有办法直接更新和下载unzip指令&#xff0c;从而导致控制台版本安装节点之后&#xff0c;会报file not found的错误&#xff0c;或者使用不了rds…

【Flutter】列表流畅性优化

前言 在日常APP的开发中&#xff0c;列表是使用频率最高的&#xff0c;这里讲述在Flutter中优化列表的滑动速度与流畅度&#xff0c;以来提高用户的体验。 方案 1、使用ListView.builder代替ListView ListView.builder在创建列表的时候要比ListView更高效&#xff0c;因为L…

Pyramid 中混合认证策略

1. 问题背景 在一个使用 Pyramid 框架开发的应用程序中&#xff0c;需要同时处理 HTML 内容的显示和 JSON API 的请求。对于 HTML 内容&#xff0c;使用了 AuthTktAuthenticationPolicy 进行身份验证和 ACLAuthorizationPolicy 进行授权。当用户成功登录后&#xff0c;会在浏览…

sql拉链表

1、定义&#xff1a;维护历史状态以及最新数据的一种表 2、使用场景 1、有一些表的数据量很大&#xff0c;比如一张用户表&#xff0c;大约1亿条记录&#xff0c;50个字段&#xff0c;这种表 2.表中的部分字段会被update更新操作&#xff0c;如用户联系方式&#xff0c;产品的…

【哈尔滨二级等保测评需要测哪些指标】

为了保证系统的安全性、稳定性和遵从性&#xff0c;哈尔滨二级等保评估要求对评估指标进行全面的评估。下面就是对哈尔滨等保二级考核所需要的考核指标的具体说明&#xff0c;并按各个维度分点表达与总结&#xff1a; 一、物理安全要求 物理安全是信息系统的根本&#xff0c;…

kubeadm kubectl kubelet区别

kubeadm kubeadm 是一个方便易用的 Kubernetes 工具&#xff0c;能够部署生产级别的 Kubernetes 集群kubeadm 还具有了和 minikube 一样的易用性&#xff0c;只要很少的几条命令&#xff0c;如 init、join、upgrade、reset 就能够完成 Kubernetes 集群的管理维护工作&#xff…

简述设计模式-工厂模式

概述 工厂模式是为了提供创建对象的方式&#xff0c;无需制定要创建的具体类。 举个例子&#xff0c;假如我是甲方需要制造一辆车&#xff0c;我可以要油车&#xff0c;可以要电车&#xff0c;也可以油电混动车&#xff0c;如果没有工厂&#xff0c;我需要自己找到对应的制造…

免费可视化工具如何提升智慧物流管理效率

在现代智慧物流中&#xff0c;免费可视化工具正扮演着越来越重要的角色。这些工具通过数据的可视化展示&#xff0c;使物流管理更加高效、透明和智能化。免费可视化工具可以将复杂的物流数据转换为直观的图表和图形&#xff0c;帮助管理者实时监控和分析物流运作情况&#xff0…

贪心+后缀和,CF 1903C - Theofanis‘ Nightmare

一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 1903C - Theofanis Nightmare 二、解题报告 1、思路分析 我们任意一种分组其实都是若干个后缀和相加 比如我们分成了三组&#xff0c;第一组的数被加了一次&#xff0c;第二组的数被加了两次&#xff0c;第…

解锁IDEA中Git/SVN Issue Navigation功能:80%程序员都不懂的秘密武器~

文章目录 前言什么是 Git Issue Navigation&#xff1f;配置 Git Issue Navigation1. 打开设置2. 导航到 Issue Navigation 设置3. 添加新的 Issue Navigation 规则具体示例配置 使用 Git Issue Navigation在提交信息中使用 Issue ID实际导航到连接 优点1. 快速定位问题2. 提高…

消防认证-防火卷帘

一、消防认证 消防认证是指消防产品符合国家相关技术要求和标准&#xff0c;且通过了国家认证认可监督管理委员会审批&#xff0c;获得消防认证资质的认证机构颁发的证书&#xff0c;消防产品具有完好的防火功能&#xff0c;是住房和城乡建设领域验收的重要指标。 二、认证依据…

【UE 网络】专用服务器和多个客户端加入游戏会话的过程,以及GameMode、PlayerController、Pawn的创建流程

目录 0 引言1 多人游戏会话1.1 Why&#xff1f;为什么要有这个1.2 How&#xff1f;怎么使用&#xff1f; 2 加入游戏会话的流程总结 &#x1f64b;‍♂️ 作者&#xff1a;海码007&#x1f4dc; 专栏&#xff1a;UE虚幻引擎专栏&#x1f4a5; 标题&#xff1a;【UE 网络】在网络…

西南交通大学【算法分析与设计实验1】

实验1.4 有向图拓扑排序 实验目的 &#xff08;1&#xff09;掌握算法的自然语言描述法&#xff0c;流程图绘制方法以及伪代码描述方法。 &#xff08;2&#xff09;理解算法的执行过程。 &#xff08;3&#xff09;掌握算法的编程实现方法、调试方法及测试方法。 实验任务…

AcWing 1256:扩展二叉树

【题目来源】https://www.acwing.com/problem/content/1258/【题目描述】 由于先序、中序和后序序列中的任一个都不能唯一确定一棵二叉树&#xff0c;所以对二叉树做如下处理&#xff0c;将二叉树的空结点用 补齐&#xff0c;如图所示。 我们把这样处理后的二叉树称为原二叉树…

智谱AI: ChatGLM API的使用

一、获取API 1、打开网址&#xff1a;智谱AI开放平台 注册账号登录 2、登录&#xff0c;查看API key (注册后赠送100万token&#xff0c;实名认证后多赠送400万, 有效期一个) 二、安装及调用 安装质谱SDK pip install zhipuai调用方式 流式调用 from zhipuai import ZhipuA…