SpringSecurity6 | 核心过滤器

2023-11-08 11:12

本文主要是介绍SpringSecurity6 | 核心过滤器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在这里插入图片描述

✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉
🍎个人主页:Leo的博客
💞当前专栏: Java从入门到精通
✨特色专栏: MySQL学习
🥭本文内容:SpringSecurity6 | 核心过滤器
🖥️个人小站 :个人博客,欢迎大家访问
📚个人知识库: Leo知识库,欢迎大家访问

文章目录

    • 1.前言
    • 2.前提知识
    • 3.核心过滤器
      • 3.1DisableEncodeUrlFilter
      • 3.2WebAsyncManagerIntegrationFilter
      • 3.3HeaderWriterFilter
      • 3.4CsrfFilter
      • 3.5SecurityContextHolderFilter
      • 3.6LogoutFilter
      • 3.7UsernamePasswordAuthenticationFilter
      • 3.8DefaultLoginPageGeneratingFilter
      • 3.9DefaultLogoutPageGeneratingFilter
      • 3.10BasicAuthenticationFilter
      • 3.11RequestCacheAwareFilter
      • 3.12SecurityContextHolderAwareRequestFilter
      • 3.13AnonymousAuthenticationFilter
      • 3.14ExceptionTranslationFilter
      • 3.15AuthorizationFilter
    • 4.流程分析
    • 5.参考文献
    • 6.总结

学习参考 :

  • 讲师:孙帅老师
  • 课程:孙哥说SpringSecurity6

image-20231030235443828

1.前言

大家好,我是Leo哥🫣🫣🫣,上一节我们通过源码剖析以及图文分析,了解了关于委派筛选器代理过滤器链代理的原理和作用。这节课我们接着学习SpringSecurity的过滤器,了解SpringSecurity中都有哪些核心过滤器。好了,话不多说让我们开始吧😎😎😎。

2.前提知识

上一节中我们详细的剖析了委派筛选器代理—>DelegatingFilterProxy,它的作用就是:实现把Servlet容器中的 Filter 同 Spring 容器中的 bean 关联起来,DelegatingFilterProxy实现了Filter接口,Servlet容器启动就会加载好这个类。借助他可以实现普通的Filter拦截到的Http请求交由FilterChainProxy。

FilterChainProxy顶层管理者,统一管理 SecurityFilter和 SecurityFllterChain过滤器链

当请求到达 FilterChainProxy 时,会根据当前请求匹配SecurityFilterChain,然后将请求依次转发给 SecurityFilterChain 中的 SecurityFilter中。

回到我们上一张分析图。

image-20231107204747766

大家可以再次梳理一下当一个Http请求发出直到获取Web资源的整个过程。

3.核心过滤器

接下来我们主要介绍Spring Security中默认的15个过滤器相关作用。

这个时候有人问啦,Leo哥,你怎么知道SpringSecurity默认是15个核心过滤器呢,为啥不是14个。

哈哈哈,这个问题问得好,既然我敢这么说,那一定是有把握啦,下面我们启动IDEA看看。

打开IDEA,搜索WebSecurityConfiguration这个总配置类

image-20231107235513951

并在这里打一个断点,之后重启IDEA,记得以DEBUG方式运行。

image-20231107235650717

我们鼠标放在这一行进行查看,确实是项目已启动就加载了这个15个过滤器。嘿嘿。

3.1DisableEncodeUrlFilter

该过滤器用于禁用对URL进行编码的功能。它的作用是阻止Spring Security对URL进行自动编码,从而使得URL可以保持原始状态。

在某些情况下,用户可能希望禁用Spring Security对URL的编码,例如在特定的代理服务器或反向代理服务器上,因为这些代理服务器可能会自己处理URL的编码。此时就可以使用 DisableEncodeUrlFilter 来禁用Spring Security对URL的编码。

当你在Spring Security配置中加入 DisableEncodeUrlFilter 时,它将会在过滤器链中起作用,禁止Spring Security对URL进行编码。具体来说,它会覆盖默认的 DefaultSecurityFilterChain 配置,以确保 URL 编码被禁用。

在XML配置中如下所示:

<beans:bean id="disableUrlEncodingFilter" class="org.springframework.security.web.servletapi.DisableEncodeUrlFilter"/>
<http><intercept-url pattern="/somepattern" access="permitAll" /><custom-filter ref="disableUrlEncodingFilter" before="SECURITY_CONTEXT_FILTER" />
</http>

在Java配置中,如下所示:

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {return http.authorizeRequests().antMatchers("/somepattern").permitAll()// 添加 DisableEncodeUrlFilter 到过滤器链中.and().addFilterBefore(new DisableEncodeUrlFilter(), SecurityContextPersistenceFilter.class);
}

这个过滤器有什么用? 首先实现Session会话,可以通过以下两种方式

  • Cookie:浏览器设置,每次请求自动携带给服务端
  • URL重写Cookie被禁用时,后端响应将sessionId拼接在URL后进行重写,传递给页面

DisableEncodeUrlFilter禁用HttpServletResponseURL进行编码重写,以防止将sessionIdHTTP访问日志等内容中泄露。

DisableEncodeUrlResponseWrapper,我们来简单来一下他的源码:

    private static final class DisableEncodeUrlResponseWrapper extends HttpServletResponseWrapper {private DisableEncodeUrlResponseWrapper(HttpServletResponse response) {super(response);}// 直接返回,不重写public String encodeRedirectURL(String url) {return url;}// 直接返回,不重写public String encodeURL(String url) {return url;}}

需要注意的是,虽然禁用URL编码可能在特定的情况下很有用,但这也可能会导致一些安全性问题,因为URL编码通常是为了防止跨站脚本(XSS)攻击等安全问题。因此,禁用URL编码应该慎重考虑,并且需要在充分了解其潜在风险的情况下使用。

3.2WebAsyncManagerIntegrationFilter

WebAsyncManagerIntegrationFilter用于集成Web异步管理器(WebAsyncManager)。它在处理异步请求时起着重要的作用,并确保在异步处理过程中正确地管理安全上下文。

WebAsyncManagerIntegrationFilter是第二个执行的过滤器,从名字上可以知道和异常请求有关。

具体来说,WebAsyncManagerIntegrationFilter负责在异步处理过程中同步安全上下文,以确保安全上下文能够正确传播到异步执行的线程中。这对于处理异步请求非常重要,因为在异步处理中,线程可能会发生切换,而安全上下文的正确传递对于安全操作至关重要。

在实际应用中,WebAsyncManagerIntegrationFilter通常与Spring MVC的异步请求处理机制一起使用,确保在使用CallableDeferredResult等异步处理方式时,安全上下文能够正确传播。

默认情况下,Spring Security 经过认证后,认证信息会存储在当前线程ThreadLocal(不是InheritableThreadLocal)中,如果是异步,主线程已经执行完毕,子线程执行过程中则无法获取当前认证信息。

Spring 中的异步通过WebAsyncManager管理异步请求,异步请求交由TaskExecutor线程池去处理,WebAsyncManager提供了一个拦截器机制,可以用拦截器将主线程中的数据传递到子线程中。

下面是一个简单的示例,演示了如何在SpringSecurity配置中使用WebAsyncManagerIntegrationFilter:

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {return http// ...其他配置.addFilter(new WebAsyncManagerIntegrationFilter()) // 添加WebAsyncManagerIntegrationFilter到过滤器链中// ...其他配置
}

需要注意的是,WebAsyncManagerIntegrationFilter通常不需要显式地在配置中添加,因为它通常会由Spring Security自动添加到过滤器链中。但是,如果你有特殊的需求或者定制化的异步处理方式,你可能需要显式地添加WebAsyncManagerIntegrationFilter。

总之,WebAsyncManagerIntegrationFilter在SpringSecurity中扮演着确保安全上下文正确传播到异步处理过程中的重要角色,它是保证异步请求处理安全性的关键组成部分。

3.3HeaderWriterFilter

HeaderWriterFilter字面理解为请求头写入过滤器,他的作用是将某些头信息添加到响应中,添加某些启用浏览器保护的头信息非常有用,如X-Frame-OptionsX-XSS-ProtectionX-Content-Type-Options等,增加一些安全性。

逻辑也比较简单,就是添加头部信息:

    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {// shouldWriteHeadersEagerly 直接添加if (this.shouldWriteHeadersEagerly) {this.doHeadersBefore(request, response, filterChain);} else {this.doHeadersAfter(request, response, filterChain);}}

具体来说,SecurityContextHolderFilter 通过 SecurityContextHolder 来管理安全上下文。SecurityContextHolder 是 Spring Security 提供的一个持有安全上下文的地方,它使用 ThreadLocal 来确保在同一线程内安全上下文的传递。

在请求到达后端应用程序时,SecurityContextHolderFilter 将当前的安全上下文信息从 HTTP 请求中获取,并存储在 SecurityContextHolder 中。这样,在请求的任何地方,都可以通过 SecurityContextHolder 来获取当前用户的身份、权限等安全信息。

SpringSecurity 配置中,通常会自动包含 SecurityContextHolderFilter,因此在大多数情况下不需要显式地配置该过滤器。例如,在基于 Java 的配置中,你通常只需要通过 @EnableWebSecurity 注解启用 Spring Security,并进行相应的配置即可。

下面是一个简单的示例,演示了如何在 Spring Security 中进行基本的配置:

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {return http// ...其他配置.authorizeRequests().anyRequest().authenticated().and().formLogin().and().httpBasic();
}

在这个配置中,虽然没有显式地添加 SecurityContextHolderFilter,但它会被自动包含在 Spring Security 的过滤器链中。

总之,SecurityContextHolderFilter 在 Spring Security 中扮演着确保安全上下文正确传播和管理的重要角色,它是整个安全框架中的关键组成部分。

3.4CsrfFilter

CsrfFilter 是SpringSecurity 中用于防止 **CSRF(跨站请求伪造)**攻击的过滤器。CSRF 攻击是一种利用用户在其他网站上已经登录的身份信息,来发起对目标网站的恶意请求的攻击方式。为了防止这种攻击,SpringSecurity 提供了 CsrfFilter 来加强应用程序的安全性。

CsrfFilter 的主要作用是验证每个非安全 HTTP 请求(例如 POST、PUT、DELETE 等)中是否包含有效的 CSRF 令牌。如果请求中缺少有效的 CSRF 令牌,CsrfFilter 将拒绝该请求,并返回相应的错误信息。

在 Spring Security 中,默认情况下,CsrfFilter 是自动启用的,它会在请求中自动添加 CSRF 令牌,并验证每个非安全请求中的令牌是否有效。同时,Spring Security 还提供了一些配置选项,以便开发人员可以根据应用程序的需求进行定制化的 CSRF 防护策略。

下面是一个简单的示例,演示了如何在 SpringSecurity 中进行基本的 CSRF 配置:

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {return http// ...其他配置.csrf().disable(); // 禁用 CSRF 防护
}

在这个配置中,通过禁用CSRF防护,CsrfFilter 将不再生效,从而允许非安全请求不携带 CSRF 令牌。

总之,CsrfFilter 在 SpringSecurity 中扮演着加强应用程序安全性的重要角色,它是保护应用程序免受 CSRF 攻击的关键组成部分。通过合理地配置和使用 CsrfFilter,可以有效地提高应用程序的安全性。

3.5SecurityContextHolderFilter

SecurityContextHolderFilter是第五个过滤器,直接继承自GenericFilterBean,声明了两个成员属性:

	// 请求之间持久化	 SecurityContextprivate final SecurityContextRepository securityContextRepository;// 一种针对线程存储 SecurityContext 策略。private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder.getContextHolderStrategy();

不难看出,该过滤器的作用就是将持久化的SecurityContext设置到当前线程中,比如登录成功后,在HttpSession中保存了SecurityContext,那么该过滤器可以直接将SecurityContext设置到请求线程中。

	private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)throws ServletException, IOException {// 1. 获取属性 SecurityContextHolderFilter.class.getName() + ".APPLIED"// 存在说明当前请求已执行该过滤器if (request.getAttribute(FILTER_APPLIED) != null) {chain.doFilter(request, response);return;}// 2. 设置属性request.setAttribute(FILTER_APPLIED, Boolean.TRUE);// 3. 存储中加载 SecurityContextSupplier<SecurityContext> deferredContext = this.securityContextRepository.loadDeferredContext(request);try {// 4. 将SecurityContext 设置到ContextHolder中this.securityContextHolderStrategy.setDeferredContext(deferredContext);chain.doFilter(request, response);}finally {// 完成后,清理上下文,移除属性this.securityContextHolderStrategy.clearContext();request.removeAttribute(FILTER_APPLIED);}}

SecurityContextHolderFilter 负责在请求处理过程中管理安全上下文。安全上下文是指存储了当前用户的认证信息(如身份、权限等)的对象,在整个请求处理过程中需要被使用。

具体来说,SecurityContextHolderFilter 主要完成以下几个任务:

  1. 从请求中获取安全上下文:当请求到达后端应用程序时,SecurityContextHolderFilter 会尝试从请求中提取安全相关的信息,例如认证凭证、权限信息等。
  2. 将安全上下文与当前线程绑定:获取到安全上下文后,SecurityContextHolderFilter 会将其绑定到当前线程中。Spring Security 使用 ThreadLocal 来实现线程本地变量存储,确保在同一线程内安全上下文的传递。
  3. 允许在请求处理过程中访问安全上下文:一旦安全上下文与当前线程绑定成功,整个请求处理过程中的代码均可通过 SecurityContextHolder 来获取当前用户的安全信息,而无需显式地传递安全上下文。

在典型的SpringSecurity 配置中,SecurityContextHolderFilter 通常作为过滤器链中的第一个过滤器,以确保在请求进入应用程序时,安全上下文已经准备就绪。

以下是一个简单的示例,展示了如何在SpringSecurity 中进行基本的配置,并演示了 SecurityContextHolderFilter 的使用:

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {return http// ...其他配置.addFilterBefore(new SecurityContextHolderFilter(), UsernamePasswordAuthenticationFilter.class).authorizeRequests().anyRequest().authenticated().and().formLogin();
}

在这个配置中,我们通过 addFilterBefore 方法将自定义的 SecurityContextHolderFilter 添加到了过滤器链中,以确保在请求进入应用程序时能够正确处理安全上下文。

总之,SecurityContextHolderFilter 在 Spring Security 中扮演着确保安全上下文正确传播和管理的重要角色,它是整个安全框架中的关键组成部分。通过合理地配置和使用 SecurityContextHolderFilter,可以确保安全上下文在请求处理过程中得到正确管理和传递,从而实现应用程序的安全防护。

3.6LogoutFilter

LogoutFilter 是 SpringSecurity 框架中的一个关键过滤器,用于处理用户注销(logout)操作。用户注销是指用户主动终止当前会话并退出登录状态的操作,而 LogoutFilter 负责在用户发起注销请求时执行相应的处理逻辑。

具体来说,LogoutFilter 主要完成以下几个任务:

  1. 监听注销请求:当用户发起注销请求时,LogoutFilter 会拦截该请求,并进行相应的处理。通常情况下,注销请求会使用 HTTP 的 GET 或 POST 方法,并以特定的 URL 地址表示。
  2. 执行注销逻辑:一旦捕获到注销请求,LogoutFilter 将执行相应的注销逻辑,包括清除用户的认证信息、使当前会话失效、清空安全上下文等操作。
  3. 重定向或返回响应:在执行完注销逻辑后,LogoutFilter 可能会将用户重定向到指定的页面,或者直接返回注销成功的响应。

在典型的 Spring Security 配置中,LogoutFilter 通常作为过滤器链中的最后一个过滤器,以确保在请求处理结束后能够正确处理用户的注销请求。

	private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)throws IOException, ServletException {// 1. 查看当前请求路径是否登出,默认登出路径为/logoutif (requiresLogout(request, response)) {// 2. 获取线程中的认证信息Authentication auth = this.securityContextHolderStrategy.getContext().getAuthentication();if (this.logger.isDebugEnabled()) {this.logger.debug(LogMessage.format("Logging out [%s]", auth));}// 3. 调用登出处理器处理this.handler.logout(request, response, auth);// 4. 登出成功处理器,跳转到指定页面this.logoutSuccessHandler.onLogoutSuccess(request, response, auth);return;}chain.doFilter(request, response);}

以下是一个简单的示例,展示了如何在 Spring Security 中进行基本的注销配置,并演示了 LogoutFilter 的使用:

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {return http// ...其他配置.logout().logoutUrl("/custom-logout") // 自定义注销 URL.logoutSuccessUrl("/logout-success") // 注销成功后的跳转页面.addLogoutHandler(new CustomLogoutHandler()) // 添加自定义的注销处理器.invalidateHttpSession(true) // 使当前会话失效.deleteCookies("JSESSIONID") // 删除指定的 Cookie.permitAll().and()// ...其他配置
}

在这个配置中,我们通过 .logout() 方法配置了注销相关的信息,包括注销 URL、注销成功后的跳转页面、自定义的注销处理器、是否使当前会话失效以及需要删除的 Cookie 等。

LogoutFilterSpringSecurity 中扮演着处理用户注销请求的重要角色,它是实现用户注销功能的关键组成部分。通过合理地配置和使用 LogoutFilter,可以确保用户的注销操作得到正确处理,从而提升应用程序的用户体验和安全性。

3.7UsernamePasswordAuthenticationFilter

UsernamePasswordAuthenticationFilter 是 SpringSecurity 框架中的一个核心过滤器,用于处理基于用户名密码的身份认证请求。它是实现用户登录验证的关键组件之一,负责从用户提交的用户名密码信息进行认证,并在认证成功后生成相应的认证信息。

具体来说,UsernamePasswordAuthenticationFilter 主要完成以下几个任务:

  1. 监听认证请求:当用户提交用户名密码等认证信息时,UsernamePasswordAuthenticationFilter 会拦截该请求,并进行身份认证处理。
  2. 提取认证信息:从用户提交的请求中提取用户名密码等身份认证信息。
  3. 执行认证逻辑:使用提取到的用户名密码信息进行实际的身份认证过程,通常包括验证用户名密码的正确性、获取用户的权限信息等操作。
  4. 认证成功:如果认证成功,UsernamePasswordAuthenticationFilter 将生成相应的认证信息,包括用户的主体(Principal)、权限信息等,并将其存储到安全上下文中。
  5. 认证失败:如果认证失败,UsernamePasswordAuthenticationFilter 可能会返回相应的认证失败信息,并阻止用户继续访问受保护的资源。
	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)throws AuthenticationException {// 1. 校验请求方式if (this.postOnly && !request.getMethod().equals("POST")) {throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());}// 2. 获取请求参数中的用户名、密码String username = obtainUsername(request);username = (username != null) ? username.trim() : "";String password = obtainPassword(request);password = (password != null) ? password : "";// 3. 创建认证令牌UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(username,password);// Allow subclasses to set the "details" propertysetDetails(request, authRequest);// 4. 认证管理器进行认证return this.getAuthenticationManager().authenticate(authRequest);}

SpringSecurity 配置中,UsernamePasswordAuthenticationFilter 被默认配置为过滤器链中的第一个过滤器,以确保在用户登录请求到达后端应用程序时能够正确处理身份认证逻辑。

以下是一个简单的示例,展示了如何在SpringSecurity 中进行基本的身份认证配置,并演示了 UsernamePasswordAuthenticationFilter 的使用:

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {return http.authorizeRequests().anyRequest().authenticated().and().formLogin().loginPage("/login") // 自定义登录页面.permitAll().and().addFilterBefore(new UsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}

在这个配置中,我们通过 .formLogin() 方法配置了登录相关的信息,包括自定义的登录页面和允许所有用户访问登录页面。同时,我们通过 addFilterBefore 方法将自定义的 UsernamePasswordAuthenticationFilter 添加到了过滤器链中,以确保在请求进入应用程序时能够正确处理身份认证逻辑。

UsernamePasswordAuthenticationFilter 在 Spring Security 中扮演着处理用户身份认证请求的重要角色,它是确保用户身份得到正确验证并生成相应认证信息的关键组件。通过合理地配置和使用 UsernamePasswordAuthenticationFilter,可以实现应用程序的安全认证功能,保护系统不受未经授权的访问。

3.8DefaultLoginPageGeneratingFilter

DefaultLoginPageGeneratingFilter 是 Spring Security框架中的一个过滤器,用于生成默认的登录页面。当应用程序需要用户登录但未配置自定义的登录页面时,DefaultLoginPageGeneratingFilter 将负责生成一个简单的默认登录页面,并在用户访问未授权资源时引导用户进行登录。

具体来说,DefaultLoginPageGeneratingFilter 主要完成以下几个任务:

  1. 监听未授权请求:当用户尝试访问受保护的资源但未进行登录认证时,DefaultLoginPageGeneratingFilter 会拦截该请求,并进行处理。
  2. 生成默认登录页面:如果应用程序未配置自定义的登录页面,DefaultLoginPageGeneratingFilter 将生成一个简单的默认登录页面,包括用户名密码输入框、登录按钮等基本元素。
  3. 引导用户进行登录:将生成的默认登录页面返回给用户,以引导用户进行身份认证操作。
	private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)throws IOException, ServletException {boolean loginError = isErrorPage(request); // 是否登录错误 /login?errorboolean logoutSuccess = isLogoutSuccess(request); // 是否登录成功 /login?logoutif (isLoginUrlRequest(request) || loginError || logoutSuccess) {//1.  /login?error、/login?logout、/login 三种请求URL中的任意一种会进入该方法//2. 生成登录页String loginPageHtml = generateLoginPageHtml(request, loginError, logoutSuccess);response.setContentType("text/html;charset=UTF-8");response.setContentLength(loginPageHtml.getBytes(StandardCharsets.UTF_8).length);//3. 直接写出,并结束response.getWriter().write(loginPageHtml);return;}chain.doFilter(request, response);}

在典型的 SpringSecurity 配置中,DefaultLoginPageGeneratingFilter 通常作为过滤器链中的其中一个过滤器存在,以便在用户访问受保护资源但未进行登录认证时,能够正确生成默认的登录页面并引导用户进行登录操作。

image-20231107232222152

generateLoginPageHtml方法中,我们可以看到直接使用字符串拼接了一个HTML登录页面,也就是我们最开始引入SpringSecurity依赖之后的那个默认登录页面。

下面通过一个示例,展示了如何在SpringSecurity 中进行基本的身份认证配置,并演示了 DefaultLoginPageGeneratingFilter 的使用:

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {return http.authorizeRequests().anyRequest().authenticated().and().formLogin().and().addFilterBefore(new DefaultLoginPageGeneratingFilter(), UsernamePasswordAuthenticationFilter.class);
}

在这个配置中,我们通过 .formLogin() 方法配置了登录相关的信息,但未指定自定义的登录页面,因此 DefaultLoginPageGeneratingFilter 将会被触发以生成默认的登录页面。同时,我们通过 addFilterBefore 方法将 DefaultLoginPageGeneratingFilter 添加到了过滤器链中。

DefaultLoginPageGeneratingFilter 在 Spring Security 中起着生成默认登录页面,引导用户进行登录的重要作用。当应用程序需要一个简单的登录页面来引导用户进行身份认证时,可以借助 DefaultLoginPageGeneratingFilter 来快速实现这一功能,从而提升系统的用户友好性和安全性。

3.9DefaultLogoutPageGeneratingFilter

DefaultLogoutPageGeneratingFilter和上面一样,如果请求URL/logout,直接生成一个确认退出页面。

image-20231107232600856

3.10BasicAuthenticationFilter

BasicAuthenticationFilter处理BASIC认证(请求头中携带BASIC +特殊格式用户名密码),除表单登录的另一种登录方式,但是目前用的很少,和表单登录逻辑类似:

@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)throws IOException, ServletException {try {UsernamePasswordAuthenticationToken authRequest = this.authenticationConverter.convert(request);if (authRequest == null) {this.logger.trace("Did not process authentication request since failed to find "+ "username and password in Basic Authorization header");chain.doFilter(request, response);return;}String username = authRequest.getName();this.logger.trace(LogMessage.format("Found username '%s' in Basic Authorization header", username));if (authenticationIsRequired(username)) {Authentication authResult = this.authenticationManager.authenticate(authRequest);SecurityContext context = this.securityContextHolderStrategy.createEmptyContext();context.setAuthentication(authResult);this.securityContextHolderStrategy.setContext(context);if (this.logger.isDebugEnabled()) {this.logger.debug(LogMessage.format("Set SecurityContextHolder to %s", authResult));}this.rememberMeServices.loginSuccess(request, response, authResult);this.securityContextRepository.saveContext(context, request, response);onSuccessfulAuthentication(request, response, authResult);}}catch (AuthenticationException ex) {this.securityContextHolderStrategy.clearContext();this.logger.debug("Failed to process authentication request", ex);this.rememberMeServices.loginFail(request, response);onUnsuccessfulAuthentication(request, response, ex);if (this.ignoreFailure) {chain.doFilter(request, response);}else {this.authenticationEntryPoint.commence(request, response, ex);}return;}chain.doFilter(request, response);}

具体来说,BasicAuthenticationFilter 主要完成以下几个任务:

  1. 提取认证信息:在每个请求处理之前,BasicAuthenticationFilter 会从请求头中提取 Base64 编码的用户名和密码信息,用于后续的身份验证。
  2. 执行身份验证:BasicAuthenticationFilter 会将提取到的用户名和密码信息传递给认证管理器(AuthenticationManager),由认证管理器来进行实际的身份验证操作。
  3. 处理身份验证结果:根据身份验证的结果,BasicAuthenticationFilter 会在安全上下文中设置相应的认证信息,并根据认证结果决定是否允许请求继续处理。
  4. 错误处理:当身份验证失败时,BasicAuthenticationFilter 负责返回适当的身份验证失败响应,要求客户端重新发起身份验证。

通过合理配置 BasicAuthenticationFilter,可以实现对基本认证的请求进行身份验证,并根据验证结果决定是否允许请求继续处理。

以下是一个简单的示例,展示了如何在 SpringSecurity 中配置 BasicAuthenticationFilter

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {return http// ... 其他配置.addFilterBefore(new RequestCacheAwareFilter(), UsernamePasswordAuthenticationFilter.class);
}

在这个配置中,我们通过 .addFilterBefore(new BasicAuthenticationFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class)BasicAuthenticationFilter 添加到了过滤器链中,并传入了认证管理器以进行实际的身份验证操作。

BasicAuthenticationFilter 在 Spring Security 中扮演着处理基本认证相关逻辑的重要角色,通过它的配置可以实现对基本认证的请求进行身份验证,提高系统的安全性和访问控制能力。

3.11RequestCacheAwareFilter

RequestCacheAwareFilter缓存被登录打断的请求,例如访问某个URL,会调转到登录页面,登录成功后,会从当前缓存中获取之前访问的URL,直接跳转到原来的请求:

	@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {// 1. 获取缓存请求HttpServletRequest wrappedSavedRequest = this.requestCache.getMatchingRequest((HttpServletRequest) request,(HttpServletResponse) response);// 2. 存在则传递之前缓存的请求对象chain.doFilter((wrappedSavedRequest != null) ? wrappedSavedRequest : request, response);}

具体来说,RequestCacheAwareFilter 主要完成以下几个任务:

  1. 请求缓存:在用户完成身份验证前,RequestCacheAwareFilter 会将原始的请求信息保存到请求缓存中,这样用户完成身份验证后就可以获取到这些原始请求信息。
  2. 请求信息的恢复:当用户完成身份验证后,RequestCacheAwareFilter 会根据请求缓存中的信息,将用户原始的请求信息(如请求 URL、请求参数等)恢复,从而让用户能够继续之前被中断的请求处理流程。
  3. 与其他安全组件的协作:RequestCacheAwareFilter 通常与其他安全组件(如身份验证过滤器、访问控制过滤器等)协同工作,确保在用户完成身份验证后能够正确地恢复原始的请求信息。

通过合理配置 RequestCacheAwareFilter,可以实现用户完成身份验证后能够无缝地继续之前的请求处理流程,提高系统的用户体验和功能完整性。

以下是一个简单的示例,展示了如何在 SpringSecurity 中配置 RequestCacheAwareFilter

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {return http// ... 其他配置.addFilterBefore(new RequestCacheAwareFilter(), UsernamePasswordAuthenticationFilter.class);
}

在这个配置中,我们通过 .addFilterBefore(new RequestCacheAwareFilter(), UsernamePasswordAuthenticationFilter.class)RequestCacheAwareFilter 添加到了过滤器链中。

RequestCacheAwareFilter 在 Spring Security 中扮演着保存和恢复用户原始请求信息的重要角色,通过它的配置可以实现用户完成身份验证后能够无缝地继续之前的请求处理流程,提高系统的用户体验和功能完整性。

3.12SecurityContextHolderAwareRequestFilter

SecurityContextHolderAwareRequestFilter 将请求包装为Servlet3SecurityContextHolderAwareRequestWrapper

具体来说,SecurityContextHolderAwareRequestFilter 主要完成以下几个任务:

  1. 将安全上下文信息与请求关联:在每个请求处理之前,SecurityContextHolderAwareRequestFilter 会将当前的安全上下文信息绑定到当前的 HTTP 请求上下文中,这样在请求处理过程中可以方便地获取和操作安全上下文信息。
  2. 提供方便的安全上下文访问方式:通过 SecurityContextHolderAwareRequestFilter,可以在请求处理过程中以一种方便的方式获取当前的认证信息、权限信息等安全上下文相关的信息,而不需要显式地从 SecurityContextHolder 中获取。
  3. 与其他安全组件的协作:SecurityContextHolderAwareRequestFilter 通常与其他安全组件(如身份验证过滤器、访问控制过滤器等)协同工作,确保安全上下文信息能够在整个请求处理过程中得到正确的传递和使用。

通过合理配置 SecurityContextHolderAwareRequestFilter,可以实现安全上下文信息与 HTTP 请求的有效关联,提高系统对安全信息的处理效率和便利性。

以下是一个简单的示例,展示了如何在 SpringSecurity 中配置 SecurityContextHolderAwareRequestFilter

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {return http// ... 其他配置.addFilterBefore(new SecurityContextHolderAwareRequestFilter(), UsernamePasswordAuthenticationFilter.class);
}

在这个配置中,我们通过 .addFilterBefore(new SecurityContextHolderAwareRequestFilter(), UsernamePasswordAuthenticationFilter.class)SecurityContextHolderAwareRequestFilter 添加到了过滤器链中。

总之,SecurityContextHolderAwareRequestFilter 在 Spring Security 中扮演着将安全上下文信息与 HTTP 请求关联的重要角色,通过它的配置可以实现在请求处理过程中方便地获取和操作安全上下文信息,提高系统的安全性和开发效率。

3.13AnonymousAuthenticationFilter

Anonymous是匿名用户的意思,当之前的过滤器没有发现认证的用户信息时,会在AnonymousAuthenticationFilter过滤器中创建一个匿名用户:

	@Overridepublic void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)throws IOException, ServletException {Supplier<SecurityContext> deferredContext = this.securityContextHolderStrategy.getDeferredContext();this.securityContextHolderStrateg.setDeferredContext(defaultWithAnonymous((HttpServletRequest) req, deferredContext));chain.doFilter(req, res);}

这个匿名身份信息允许匿名用户在系统中进行一定程度的操作,比如访问公开的资源或进行有限制的操作。

具体来说,AnonymousAuthenticationFilter 主要完成以下几个任务:

  1. 匿名身份的创建:当用户尚未进行认证时,AnonymousAuthenticationFilter 负责创建一个匿名的身份信息,并将其绑定到当前的安全上下文中。
  2. 安全上下文的维护:AnonymousAuthenticationFilter 将负责维护当前请求的安全上下文,确保匿名用户在系统中能够得到适当的处理和权限控制。
  3. 与其他身份验证过滤器的协作:AnonymousAuthenticationFilter 通常与其他身份验证过滤器(比如表单登录过滤器、基本认证过滤器等)协同工作,确保在用户未进行认证时能够创建并使用匿名身份信息。

通过合理配置 AnonymousAuthenticationFilter,可以实现对匿名用户的安全管理,确保他们在系统中的合法操作不影响系统的安全性。

以下是一个简单的示例,展示了如何在 Spring Security 中配置 AnonymousAuthenticationFilter

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {return http.authorizeRequests().antMatchers("/public/**").permitAll().anyRequest().authenticated().and().formLogin().and().addFilterBefore(new AnonymousAuthenticationFilter("anonymousUser"), UsernamePasswordAuthenticationFilter.class);
}

在这个配置中,我们通过 .antMatchers("/public/**").permitAll() 配置了对 /public/** 路径下的资源的公开访问权限,并通过 AnonymousAuthenticationFilter 创建了一个名为 anonymousUser 的匿名身份信息,并将其添加到了过滤器链中。

AnonymousAuthenticationFilter 在 Spring Security 中扮演着为匿名用户创建身份信息的重要角色,通过它的配置可以有效管理匿名用户在系统中的操作和权限,从而提高系统的安全性和用户体验。

3.14ExceptionTranslationFilter

ExceptionTranslationFilter是比较重要的一个过滤器,对异常进行转换处理,处理过滤器中的抛出AccessDeniedExceptionAuthenticationException,提供了Java异常和HTTP响应之间的桥梁。

具体来说,ExceptionTranslationFilter 主要完成以下几个任务:

  1. 异常转换:当发生安全相关的异常,比如用户未认证、无权限访问等情况时,ExceptionTranslationFilter 将负责将这些异常转换为特定的响应,比如跳转到登录页面、返回拒绝访问的错误信息等。
  2. 异常处理:针对不同的安全异常,ExceptionTranslationFilter 可以配置相应的异常处理策略,比如跳转到特定页面、返回特定的错误码等。
  3. 与其他过滤器的协作:ExceptionTranslationFilter 通常与其他安全过滤器(比如身份验证过滤器、访问控制过滤器等)协同工作,确保在安全相关的异常发生时能够得到正确处理。

通过合理配置 ExceptionTranslationFilter,可以实现对安全异常的统一处理,提高系统的安全性和用户体验。

	private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)throws IOException, ServletException {try {chain.doFilter(request, response);}catch (IOException ex) {throw ex;}catch (Exception ex) {// 1. 尝试从堆栈中提取 SpringSecurity异常// Try to extract a SpringSecurityException from the stacktraceThrowable[] causeChain = this.throwableAnalyzer.determineCauseChain(ex);// 2. 分析异常是否 AuthenticationExceptionRuntimeException securityException = (AuthenticationException) this.throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class, causeChain);// 3. 没有AuthenticationException,则获取AccessDeniedExceptionif (securityException == null) {securityException = (AccessDeniedException) this.throwableAnalyzer.getFirstThrowableOfType(AccessDeniedException.class, causeChain);}// 4. 不是AuthenticationException、AccessDeniedException直接抛出if (securityException == null) {rethrow(ex);}if (response.isCommitted()) {throw new ServletException("Unable to handle the Spring Security Exception "+ "because the response is already committed.", ex);}// 5. 处理异常handleSpringSecurityException(request, response, chain, securityException);}}

以下是一个简单的示例,展示了如何在 SpringSecurity 中配置 ExceptionTranslationFilter

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {return http.authorizeRequests().anyRequest().authenticated().and().formLogin().and().exceptionHandling().accessDeniedPage("/403") // 配置访问拒绝时的页面.and().addFilterBefore(new ExceptionTranslationFilter(), FilterSecurityInterceptor.class);
}

在这个配置中,我们通过 .exceptionHandling() 方法配置了访问拒绝时的处理策略,并将 ExceptionTranslationFilter 添加到了过滤器链中。

ExceptionTranslationFilter 在 Spring Security 中扮演着统一处理安全异常的重要角色,通过它的配置可以实现对各种安全异常的统一处理和响应定制,从而提升系统的安全性和用户体验。

3.15AuthorizationFilter

AuthorizationFilter是我们介绍的最后一个过滤器,Authorization是授权的意思,就是用来检验我们当前的请求是否具有相应的权限。

AuthorizationFilter 并不是一个内置的类或过滤器。也许您在问的是 AuthorizationFilter 的概念或者类似的功能。一般来说,在 Spring Security 中实现权限控制的过滤器是 FilterSecurityInterceptor

FilterSecurityInterceptor 是 Spring Security 中负责进行访问控制的过滤器之一,它主要用于对请求进行权限验证和访问控制。当用户发送请求时,FilterSecurityInterceptor会拦截该请求,并执行以下任务:

  1. 权限验证:根据请求的路径和用户的权限信息,判断用户是否具有访问该资源的权限。
  2. 访问控制决策:根据配置的权限控制规则,决定是否允许用户访问请求的资源。
  3. 异常处理:在权限验证失败或访问被拒绝时,FilterSecurityInterceptor 负责抛出相应的异常或执行其他定义的异常处理逻辑。

通过合理配置 FilterSecurityInterceptor,可以实现对系统中各种资源的权限控制,确保只有具有相应权限的用户才能访问特定的功能或数据。

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws ServletException, IOException {HttpServletRequest request = (HttpServletRequest)servletRequest;HttpServletResponse response = (HttpServletResponse)servletResponse;// 1. 如果设置了监控每一次请求,并且当前过滤器已经执行,则直接跳过if (this.observeOncePerRequest && this.isApplied(request)) {chain.doFilter(request, response);} else if (this.skipDispatch(request)) {// 2. 如果是访问错误页面,则直接跳过chain.doFilter(request, response);} else {// 3. 设置已执行当前过滤器 // org.springframework.security.web.access.intercept.AuthorizationFilter@5707f613.APPLIEDString alreadyFilteredAttributeName = this.getAlreadyFilteredAttributeName();request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);try {// 4. 调用AuthorizationManager 检查当前是否有权限AuthorizationDecision decision = this.authorizationManager.check(this::getAuthentication, request);// 5. 发布授权事件this.eventPublisher.publishAuthorizationEvent(this::getAuthentication, request, decision);// 6. 如果未被授权,抛出 AccessDeniedExceptionif (decision != null && !decision.isGranted()) {throw new AccessDeniedException("Access Denied");}chain.doFilter(request, response);} finally {request.removeAttribute(alreadyFilteredAttributeName);}}}

4.流程分析

上面我们介绍了这么多的过滤器以及进行了简单的分析,但是还有一个问题我们需要注意,既然项目启动初始化后会初识化这些过滤器,那么是谁来进行执行调度他们呢?

之前我们了解过FilterChainProxy SpringSecurity 使用的核心,用于代理SpringSecurity中所有的SecurityFilterChain ,本质上是一个特殊的过滤器,通过DelegatingFilterProxy 进行代理。

FilterChainProxy继承自GenericFilterBean类。

 public FilterChainProxy(List<SecurityFilterChain> filterChains) {// 上下文持有者(当前认证主体一些信息)策略,默认:ThreadLocalthis.securityContextHolderStrategy = SecurityContextHolder.getContextHolderStrategy();// 过滤器链校验this.filterChainValidator = new NullFilterChainValidator();// Http防火墙this.firewall = new StrictHttpFirewall();// 请求被拒绝处理程序this.requestRejectedHandler = new HttpStatusRequestRejectedHandler();// 异常解析器this.throwableAnalyzer = new ThrowableAnalyzer();// 虚拟的过滤器链装饰器this.filterChainDecorator = new VirtualFilterChainDecorator();// Security 过滤器链集合,默认只有一个DefaultSecurityFilterChainthis.filterChains = filterChains;}

那么他们的整个的执行流程是怎么样的呢,我们来简单分析一下。

image-20231108095916877

doFilterInternal方法中Spring Security 防火墙会进行第一步请求校验:

	private void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {// 1. 防火墙校验,将请求和响应进行包装// 1.1 请求方式是否被允许// 1.2 URL 是否规范// 1.3 远程IP是否黑名单// 1.4 拒绝字段名称中的不可打印Ascii字符// 1.5 请求对象是否规范FirewalledRequest firewallRequest = this.firewall.getFirewalledRequest((HttpServletRequest) request);HttpServletResponse firewallResponse = this.firewall.getFirewalledResponse((HttpServletResponse) response);// 取出所有过滤器链中的所有过滤器List<Filter> filters = getFilters(firewallRequest);FilterChain reset = (req, res) -> {if (logger.isDebugEnabled()) {logger.debug(LogMessage.of(() -> "Secured " + requestLine(firewallRequest)));}// Deactivate path stripping as we exit the security filter chainfirewallRequest.reset();chain.doFilter(req, res);};// 对过滤器链进行装饰,并调用装饰类的doFilter 方法this.filterChainDecorator.decorate(reset, filters).doFilter(firewallRequest, firewallResponse);}

在装饰过滤器链VirtualFilterChain中,开始正式调用Spring Security 中的过滤器:

		public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {// 1. 当前被调用过滤器的位置(初始值为0)是否等于过滤器数量(默认15)if (this.currentPosition == this.size) {// 位置变为过滤器数量大小时,说明全部执行完毕,调用过滤器链执行过滤器(不再是Spring Security 中的过滤器了)this.originalChain.doFilter(request, response);return;}// 2. 位置加1this.currentPosition++;// 3. 获取当前过滤器Filter nextFilter = this.additionalFilters.get(this.currentPosition - 1);if (logger.isTraceEnabled()) {String name = nextFilter.getClass().getSimpleName();logger.trace(LogMessage.format("Invoking %s (%d/%d)", name, this.currentPosition, this.size));}// 4. 执行过滤器nextFilter.doFilter(request, response, this);}

可以看到,SpringSecurity 中的过滤器执行,是严格按照顺序被调用的。每个过滤器有序执行,完成各自的功能,所有的过滤器都通过后,进入Servlet,控制层接收到请求进行业务逻辑处理,最终响应对象又经过每一个过滤器,返回给客户端。

5.参考文献

  • https://learn.lianglianglee.com/%E4%B8%93%E6%A0%8F/Spring%20Security%20%E8%AF%A6%E8%A7%A3%E4%B8%8E%E5%AE%9E%E6%93%8D/08%20%20%E7%AE%A1%E9%81%93%E8%BF%87%E6%BB%A4%EF%BC%9A%E5%A6%82%E4%BD%95%E5%9F%BA%E4%BA%8E%20Spring%20Security%20%E8%BF%87%E6%BB%A4%E5%99%A8%E6%89%A9%E5%B1%95%E5%AE%89%E5%85%A8%E6%80%A7%EF%BC%9F.md
  • https://www.processon.com/diagraming/6547a0f554338f0b199d353c
  • https://springdoc.cn/spring-security/servlet/architecture.html

6.总结

以上便是本文的全部内容,本人才疏学浅,文章有什么错误的地方,欢迎大佬们批评指正!我是Leo,一个在互联网行业的小白,立志成为更好的自己。

如果你想了解更多关于Leo,可以关注公众号-程序员Leo,后面文章会首先同步至公众号。

这篇关于SpringSecurity6 | 核心过滤器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/369471

相关文章

Andrej Karpathy最新采访:认知核心模型10亿参数就够了,AI会打破教育不公的僵局

夕小瑶科技说 原创  作者 | 海野 AI圈子的红人,AI大神Andrej Karpathy,曾是OpenAI联合创始人之一,特斯拉AI总监。上一次的动态是官宣创办一家名为 Eureka Labs 的人工智能+教育公司 ,宣布将长期致力于AI原生教育。 近日,Andrej Karpathy接受了No Priors(投资博客)的采访,与硅谷知名投资人 Sara Guo 和 Elad G

PostgreSQL核心功能特性与使用领域及场景分析

PostgreSQL有什么优点? 开源和免费 PostgreSQL是一个开源的数据库管理系统,可以免费使用和修改。这降低了企业的成本,并为开发者提供了一个活跃的社区和丰富的资源。 高度兼容 PostgreSQL支持多种操作系统(如Linux、Windows、macOS等)和编程语言(如C、C++、Java、Python、Ruby等),并提供了多种接口(如JDBC、ODBC、ADO.NET等

Redis中使用布隆过滤器解决缓存穿透问题

一、缓存穿透(失效)问题 缓存穿透是指查询一个一定不存在的数据,由于缓存中没有命中,会去数据库中查询,而数据库中也没有该数据,并且每次查询都不会命中缓存,从而每次请求都直接打到了数据库上,这会给数据库带来巨大压力。 二、布隆过滤器原理 布隆过滤器(Bloom Filter)是一种空间效率很高的随机数据结构,它利用多个不同的哈希函数将一个元素映射到一个位数组中的多个位置,并将这些位置的值置

深入解析秒杀业务中的核心问题 —— 从并发控制到事务管理

深入解析秒杀业务中的核心问题 —— 从并发控制到事务管理 秒杀系统是应对高并发、高压力下的典型业务场景,涉及到并发控制、库存管理、事务管理等多个关键技术点。本文将深入剖析秒杀商品业务中常见的几个核心问题,包括 AOP 事务管理、同步锁机制、乐观锁、CAS 操作,以及用户限购策略。通过这些技术的结合,确保秒杀系统在高并发场景下的稳定性和一致性。 1. AOP 代理对象与事务管理 在秒杀商品

布隆过滤器的详解与应用

一、什么是Bloom Filter Bloom Filter是一种空间效率很高的随机数据结构,它的原理是,当一个元素被加入集合时,通过K个Hash函数将这个元素映射成一个位阵列(Bit array)中的K个点,把它们置为1。检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没有它了:如果这些点有任何一个0,则被检索元素一定不在;如果都是1,则被检索元素很可能在。这就是布隆过滤器的基本思

文章解读与仿真程序复现思路——电力自动化设备EI\CSCD\北大核心《考虑燃料电池和电解槽虚拟惯量支撑的电力系统优化调度方法》

本专栏栏目提供文章与程序复现思路,具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源程序擅长文章解读,论文与完整源程序,等方面的知识,电网论文源程序关注python

请解释Java Web应用中的前后端分离是什么?它有哪些好处?什么是Java Web中的Servlet过滤器?它有什么作用?

请解释Java Web应用中的前后端分离是什么?它有哪些好处? Java Web应用中的前后端分离 在Java Web应用中,前后端分离是一种开发模式,它将传统Web开发中紧密耦合的前端(用户界面)和后端(服务器端逻辑)代码进行分离,使得它们能够独立开发、测试、部署和维护。在这种模式下,前端通常通过HTTP请求与后端进行数据交换,后端则负责业务逻辑处理、数据库交互以及向前端提供RESTful

.NET 自定义过滤器 - ActionFilterAttribute

这个代码片段定义了一个自定义的 ASP.NET Core 过滤器(GuardModelStateAttribute),用于在控制器动作执行之前验证模型状态(ModelState)。如果模型状态无效,则构造一个 ProblemDetails 对象来描述错误,并返回一个 BadRequest 响应。 代码片段: /// <summary>/// 验证 ModelState 是否有效/// </

JAVA初级掌握的J2SE知识(二)和Java核心的API

/** 这篇文章送给所有学习java的同学,请大家检验一下自己,不要自满,你们正在学习java的路上,你们要加油,蜕变是个痛苦的过程,忍受过后,才会蜕变! */ Java的核心API是非常庞大的,这给开发者来说带来了很大的方便,经常人有评论,java让程序员变傻。 但是一些内容我认为是必须掌握的,否则不可以熟练运用java,也不会使用就很难办了。 1、java.lang包下的80%以上的类

JVM、JRE和 JDK:理解Java开发的三大核心组件

Java是一门跨平台的编程语言,它的成功离不开背后强大的运行环境与开发工具的支持。在Java的生态中,JVM(Java虚拟机)、JRE(Java运行时环境)和JDK(Java开发工具包)是三个至关重要的核心组件。本文将探讨JVM、JDK和JRE的区别,帮助你更好地理解Java的运行机制。 1. JVM:Java虚拟机(Java Virtual Machine) 什么是JVM? JVM,即