Spring Security系列之Handler

概述

与Spring、Spring MVC、Spring Boot一样,Spring Security里也有很多Handler接口、可以分为两大类,一类是普通的XxxHandler(见名知意),另一类是对应的ServerXxxHandler(RequestRejectedHandler除外)。

以AuthenticationSuccessHandler为例,Spring Security中用于处理认证成功事件的接口。通常与基于Servlet API的应用程序一起使用,如Spring MVC应用程序。当用户成功认证后,接口的实现类负责处理接下来的操作,如重定向到其他页面、生成认证成功的日志等。主要实现类是SavedRequestAwareAuthenticationSuccessHandler,它会将用户重定向到之前被拦截的原始请求地址。

而对应的ServerAuthenticationSuccessHandler,在Spring Security 5引入的新接口,用于处理WebFlux中的认证成功事件。WebFlux是Spring Framework 5中引入的反应式编程模型,用于构建响应式的、非阻塞的、事件驱动的应用程序。该接口的实现类负责发送响应给客户端,例如返回 JSON 格式的认证成功消息。

Spring Security里定义的Handler接口具体如下:

  • AuthenticationSuccessHandler
  • AuthenticationFailureHandler
  • LogoutHandler
  • LogoutSuccessHandler
  • AccessDeniedHandler
  • CsrfTokenRequestHandler
  • RequestRejectedHandler
  • ServerAuthenticationSuccessHandler
  • ServerAuthenticationFailureHandler
  • ServerLogoutHandler
  • ServerLogoutSuccessHandler
  • ServerAccessDeniedHandler
  • ServerCsrfTokenRequestHandler

AuthenticationSuccessHandler

AuthenticationSuccessHandler接口用来设置验证成功后的处理动作,源码如下:

public interface AuthenticationSuccessHandler {
    default void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) throws IOException, ServletException {
        this.onAuthenticationSuccess(request, response, authentication);
        chain.doFilter(request, response);
    }

    void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException;
}

有两个同名onAuthenticationSuccess方法:default方法,用于处理特定的认证请求AuthenticationFilter;非default方法,则用来处理登录成功的具体事项。目前有3个实现类:

  • ForwardAuthenticationSuccessHandler:实现服务端跳转
  • SimpleUrlAuthenticationSuccessHandler:同时继承AbstractAuthenticationTargetUrlRequestHandler,通过其中的handle方法实现请求重定向
  • SavedRequestAwareAuthenticationSuccessHandler:继承自SimpleUrlAuthenticationSuccessHandler,在其基础上增加请求缓存的功能,可以记录之前请求的地址,进而在登录成功后重定向到一开始访问的地址。

在这里插入图片描述
开发者也可以配置自己的SavedRequestAwareAuthenticationSuccessHandler,方法如下:

SavedRequestAwareAuthenticationSuccessHandler successHandler() {
	SavedRequestAwareAuthenticationSuccessHandler handler = new SavedRequestAwareAuthenticationSuccessHandler;
	handler.setDefaultTargetUrl("/index");
	handler.setTargetUrlParameter("target");
	return handler;
}

ForwardAuthenticationSuccessHandler的onAuthenticationSuccess方法就一行:request.getRequestDispatcher(this.forwardUrl).forward(request, response);,即调用getRequestDispatcher方法进行服务端转发

AuthenticationFailureHandler

AuthenticationFailureHandler接口,用来设置用户验证失败后的处理动作,源码如下:

public interface AuthenticationFailureHandler {
    void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException;
}

实现类有:

  • SimpleUrlAuthenticationFailureHandler:默认,如果指定failureUrl,则跳转到该URL,未指定则返回401错误代码。也可以通过配置forwardToDestination属性将重定向改为服务器端跳转
  • ForwardAuthenticationFailureHandler:不管报哪种AuthenticationException,总是重定向到指定的URL
  • DelegatingAuthenticationFailureHandler:代理类,可根据不同的AuthenticationException类型,设置不同的Handlers
  • ExceptionMappingAuthenticationFailureHandler:可以根据不同的AuthenticationException类型,设置不同的跳转URL
  • AuthenticationEntryPointFailureHandler:可通过AuthenticationEntryPoint来处理登录异常

类继承图
在这里插入图片描述
DelegatingAuthenticationFailureHandler处理方法handle如下:

// 维护一个map,key是具体的异常类型,value是特定的Handler
private final LinkedHashMap<Class<? extends AuthenticationException>, AuthenticationFailureHandler> handlers;

public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
	for (Map.Entry<Class<? extends AuthenticationException>, AuthenticationFailureHandler> entry : this.handlers.entrySet()) {
		Class<? extends AuthenticationException> handlerMappedExceptionClass = entry.getKey();
		if (handlerMappedExceptionClass.isAssignableFrom(exception.getClass())) {
			AuthenticationFailureHandler handler = entry.getValue();
			handler.onAuthenticationFailure(request, response, exception);
			return;
		}
	}
	this.defaultHandler.onAuthenticationFailure(request, response, exception);
}

值得注意的是,Delegating,代理的意思。此实现类里维护一个Map(此Map集合支持通过构造函数的入参这种方式来实例化Handler类),然后在核心方法里对Map里的key进行遍历,与方法入参里的exception对比,比对成功则加以处理。最后使用默认的Handler加以处理。这种思想,在下面的几个Handler里,几乎都是如此。不同的是Map的key不一样,核心方法名不一样(一般都命名为handle()),对比项不一样(有的是对比request)。不再赘述。

LogoutHandler

LogoutHandler接口,设置logout过程中必须处理动作,logout后的重定向建议使用LogoutSuccessHandler,源码如下:

public interface LogoutHandler {
    void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication);
}

有如下几个实现类:

  • AbstractRememberMeServices:
  • CompositeLogoutHandler:
  • CookieClearingLogoutHandler:清除Cookie
  • CsrfLogoutHandler:通过CsrfTokenRepository清除CsrfToken
  • HeaderWriterLogoutHandler:
  • LogoutSuccessEventPublishingLogoutHandler:同时实现ApplicationEventPublisherAware,发布一个事件通知
  • OidcBackChannelLogoutHandler:
  • PersistentTokenBasedRememberMeServices
  • SecurityContextLogoutHandler
  • SpringSessionRememberMeServices
  • TokenBasedRememberMeServices

CompositeLogoutHandler接口源码如下:

private final List<LogoutHandler> logoutHandlers;
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
	for (LogoutHandler handler : this.logoutHandlers) {
		handler.logout(request, response, authentication);
	}
}

分析下来,与Delegating比较类似,不同的是,维护一个List<xxxHandler>,构造函数同样支持传入指定的List<xxxHandler>,然后在具体的handle方法里(此处是logout方法)for循环遍历list,分别使用具体的Handler来一一处理。类似地,下文也有几个CompositeXxxHandler,思想与此非常相似。

LogoutSuccessHandler

LogoutSuccessHandler接口,设置logout完成后需要处理动作,在LogoutHandler后被执行,LogoutHandler完成必要的动作(该过程不应该抛异常),LogoutSuccessHandler定位是处理后续更多的步骤,如重定向等,源码如下:

public interface LogoutSuccessHandler {
    void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException;
}

有如下几个实现类:

  • SimpleUrlLogoutSuccessHandler:和上面的AuthenticationSuccessHandler非常类似,继承AbstractAuthenticationTargetUrlRequestHandler,通过其中的handle方法实现请求重定向
  • DelegatingLogoutSuccessHandler:
  • HttpStatusReturningLogoutSuccessHandler:设置状态码200
  • ForwardLogoutSuccessHandler:通过构造函数传入的目标URL,即targetUrl参数实现转发。

AccessDeniedHandler

AccessDeniedHandler接口,用来设置访问拒绝后的处理动作,源码如下:

public interface AccessDeniedHandler {
    void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException;
}

有如下几个实现类:

  • NoOpAccessDeniedHandler:熟悉的NoOp。空实现,不做任何处理
  • AccessDeniedHandlerImpl:设置403错误码,然后转发请求,让下一个Handler来处理
  • DelegatingAccessDeniedHandler:
  • CompositeAccessDeniedHandler:组合模式,for循环遍历各个Handler实现类,依次调用其handle方法进行处理
  • InvalidSessionAccessDeniedHandler:清除缓存
  • ObservationMarkingAccessDeniedHandler:
  • RequestMatcherDelegatingAccessDeniedHandler:代理模式,维护一个map映射集合。根据具体的RequestMatcher匹配对应的Handler实现类,匹配成功则加以处理。最后使用defaultHandler加以处理。
  • OAuth2AccessDeniedHandler:spring-security-oauth2包里面的实现类,同时继承AbstractOAuth2SecurityExceptionHandler类,直接调用父类里的handle方法。

CsrfTokenRequestHandler

CSRF,Cross-Site Request Forgery,跨站请求伪造是一种攻击技术,攻击者利用用户在已登录的状态下发起的请求来执行非法操作。

CsrfTokenRequestHandler是Spring Security种用于处理CSRF攻击的处理程序。具体来说,浏览器向服务器发送请求时,服务器会在响应中返回一个CSRF令牌。在后续的请求中浏览器将该令牌包含在请求中,服务器会验证该令牌的有效性,从而防止CSRF攻击。

函数式接口,源码如下:

@FunctionalInterface
public interface CsrfTokenRequestHandler extends CsrfTokenRequestResolver {
    void handle(HttpServletRequest request, HttpServletResponse response, Supplier<CsrfToken> csrfToken);

    default String resolveCsrfTokenValue(HttpServletRequest request, CsrfToken csrfToken) {
        Assert.notNull(request, "request cannot be null");
        Assert.notNull(csrfToken, "csrfToken cannot be null");
        String actualToken = request.getHeader(csrfToken.getHeaderName());
        if (actualToken == null) {
            actualToken = request.getParameter(csrfToken.getParameterName());
        }
        return actualToken;
    }
}

实现类包括:

  • CsrfTokenRequestAttributeHandler
  • XorCsrfTokenRequestAttributeHandler:执行异或xor运算

RequestRejectedHandler

位于org.springframework.security.web.firewall包路径下,可知与防火墙策略相关,用于处理请求被拒绝的场景。当请求因为安全策略而被拒绝时,其实现类负责向用户发送相应的错误信息或执行其他定制的行为。

源码如下:

public interface RequestRejectedHandler {
    void handle(HttpServletRequest request, HttpServletResponse response, RequestRejectedException requestRejectedException) throws IOException, ServletException;
}

实现类包括:

  • DefaultRequestRejectedHandler:不做处理,抛出异常
  • HttpStatusRequestRejectedHandler:通过response.sendError(this.httpError);发送错误响应状态码,默认400,支持构造方法传参
  • ObservationMarkingRequestRejectedHandler:
  • CompositeRequestRejectedHandler:组合模式,for循环遍历列表里的所有实现类,一一加以处理。

ObservationMarkingRequestRejectedHandler的handle方法如下:

private final ObservationRegistry registry;

public void handle(HttpServletRequest request, HttpServletResponse response, RequestRejectedException exception) throws IOException, ServletException {
	Observation observation = this.registry.getCurrentObservation();
	if (observation != null) {
		observation.error(exception);
	}
}

有点复杂。

ServerAuthenticationSuccessHandler

与AuthenticationSuccessHandler接口定义几乎一致,不同的是,只有一个非default方法,

HttpServletRequest request, HttpServletResponse response两个参数变成一个参数WebFilterExchange webFilterExchange,返回参数void也变成响应式的Mono<Void>

public interface ServerAuthenticationSuccessHandler {
    Mono<Void> onAuthenticationSuccess(WebFilterExchange webFilterExchange, Authentication authentication);
}

实现类:

  • DelegatingServerAuthenticationSuccessHandler
  • RedirectServerAuthenticationSuccessHandler
  • WebFilterChainServerAuthenticationSuccessHandler

ServerAuthenticationFailureHandler

同上面的ServerAuthenticationSuccessHandler非常类似。实现类:

  • RedirectServerAuthenticationFailureHandler
  • ServerAuthenticationEntryPointFailureHandler

ServerLogoutHandler

与上面的非常相似,实现类:

  • CsrfServerLogoutHandler
  • DelegatingServerLogoutHandler
  • HeaderWriterServerLogoutHandler
  • OidcBackChannelServerLogoutHandler
  • SecurityContextServerLogoutHandler
  • WebSessionServerLogoutHandler:将WebFilterExchange里保存的WebSession做失效处理:exchange.getExchange().getSession().flatMap(WebSession::invalidate);

ServerLogoutSuccessHandler

源码比较简单,实现类:

  • HttpStatusReturningServerLogoutSuccessHandler
  • RedirectServerLogoutSuccessHandler

ServerAccessDeniedHandler

ServerAccessDeniedHandler接口源码如下:

public interface ServerAccessDeniedHandler {
    Mono<Void> handle(ServerWebExchange exchange, AccessDeniedException denied);
}

实现类:

  • HttpStatusServerAccessDeniedHandler
  • ServerWebExchangeDelegatingServerAccessDeniedHandler

ServerCsrfTokenRequestHandler

接口定义如下:

@FunctionalInterface
public interface ServerCsrfTokenRequestHandler extends ServerCsrfTokenRequestResolver {
    void handle(ServerWebExchange exchange, Mono<CsrfToken> csrfToken);

    default Mono<String> resolveCsrfTokenValue(ServerWebExchange exchange, CsrfToken csrfToken) {
        Assert.notNull(exchange, "exchange cannot be null");
        Assert.notNull(csrfToken, "csrfToken cannot be null");
        return exchange.getFormData().flatMap((data) -> {
            return Mono.justOrEmpty((String)data.getFirst(csrfToken.getParameterName()));
        }).switchIfEmpty(Mono.justOrEmpty(exchange.getRequest().getHeaders().getFirst(csrfToken.getHeaderName())));
    }
}

`

参考

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

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

相关文章

【ArcGIS微课1000例】0119:TIFF与grid格式互相转换

文章目录 一、任务描述二、tiff转grid三、grid转tif四、注意事项一、任务描述 地理栅格数据常用TIFF格式和GRID格式进行存储。TIFF格式的栅格数据常以单文件形式存储,不仅存储有R、G、B三波段的像素值,还保存有地理坐标信息。GRID格式的栅格数据常以多文件的形式进行存储,且…

ElasticSearch学习笔记之三:Logstash数据分析

第3章 Logstash数据分析 Logstash使用管道方式进行日志的搜集处理和输出。有点类似*NIX系统的管道命令 xxx | ccc | ddd&#xff0c;xxx执行完了会执行ccc&#xff0c;然后执行ddd。 在logstash中&#xff0c;包括了三个阶段: 输入input --> 处理filter&#xff08;不是必须…

【MMU】——ARM 二级页表

文章目录 二级页表项即 entry 的格式如下 二级页表项有三种类型 产生中止异常的故障条目。这可能是预取或数据中止、取决于访问类型。这实际上表示虚拟地址未映射 bit[1:0] 00大页 64KB。bit[1:0] 01。小页 4KB。bit[1:0]1x。 一级页表占用 16KB 的内存&#xff0c;二级页表…

Fastgpt接入Whisper本地模型实现语音输入

前言 FastGPT 默认使用了 OpenAI 的 LLM 模型和语音识别模型,如果想要私有化部署的话,可以使用openai 开源模型Whisper。参考文章 《openai 开源模型Whisper语音转文本模型下载使用》 开源项目地址 : 兼容openai接口api服务 https://gitee.com/taisan/whisper-api 设置安…

glm-4v-9b 部署

glm-4v-9b 模型文件地址 GLM-4 仓库文件地址 官方测试 硬件配置和系统要求 官方测试硬件信息: OS: Ubuntu 22.04Memory: 512G…

【Mac】Media Encoder 2022 for Mac(媒体编码器)V22.6.1软件介绍

软件介绍 Media Encoder 2022 for Mac是一款有着十分丰富硬件设备的编码格式设置和专门设计的预设设置功能的媒体编码器软件&#xff0c;Media Encoder Mac版能够帮助用户导出与特定交付媒体兼容的文件&#xff0c;可以很容易地将项目导出到任何屏幕上的可播放内容中。软件同时…

4.通用编程概念

目录 一、变量与常量1.1 变量1.2 常量 二、遮蔽三、数据类型3.1 标量类型1. 整型2. 浮点型3. 布尔类型4.字符类型 3.2 复合类型1. 元组2. 数组 四、函数五、语句和表达式六、函数的返回值 一、变量与常量 1.1 变量 在Rust中默认的变量是不可变的&#xff0c;如果修改其值会导致…

帮助手册到底是什么?怎么制作?

在当今竞争激烈的商业环境中&#xff0c;提供卓越的客户服务已成为企业脱颖而出的关键。而一个优质的帮助手册&#xff0c;不仅可以帮助企业提高客户服务质量&#xff0c;还能够降低客服成本&#xff0c;提升客户满意度。本文将探讨帮助手册的重要性以及如何利用它来提升企业的…

学习VUE3——组件(二)

组件插槽slots 插槽内容与出口 在某些场景中&#xff0c;我们可能想要为子组件传递一些模板片段&#xff0c;让子组件在它们的组件中渲染这些片段。这时就需要用到插槽。 如下例所示&#xff1a; <!-- Parent.vue --> <FancyButton>Click me! <!-- 插槽内容…

conntrack如何限制您的k8s网关

1.1 conntrack 介绍 对于那些不熟悉的人来说,conntrack简单来说是Linux内核的一个子系统,它跟踪所有进入、出去或通过系统的网络连接,允许它监控和管理每个连接的状态,这对于诸如NAT(网络地址转换)、防火墙和保持会话连续性等任务至关重要。它作为Netfilter的一部分运行,…

如何开发一 VSCode 插件

如何开发一个 VSCode 插件&#xff0c;本文开发一个 VSCode “Hello World” 插件&#xff0c;通过代码了解 VSCode 插件是如何工作的。 安装脚手架 npx --package yo --package generator-code -- yo code根据提示选择&#xff0c;插件开发语言选择 TypeScript ? What type…

网络编程: reactor模式的步步探索与实现

网络编程: reactor模式的步步探索与实现 一.步步探索1.先看一下之前的BUG的影响2.解决拼接式读取问题3.进一步的探索4.Connection的提出5.EpollServer的修改并将监听套接字添加进去6.小演示 二.协议与业务登场1.协议,业务,解决粘包,序列反序列化等等的函数模块实现2.读写异常事…

mac环境基于llama3和metaGPT自动开发2048游戏

1.准备虚拟环境 conda create -n metagpt python3.9 && conda activate metagpt 2.安装metagpt pip install --upgrade metagpt 3.初始化配置文件 metagpt --init-config 4. 安装llama3 5. 修改配置文件 6.让metegpt自动开发2048游戏 7.经过多轮迭代&#xff0c;最终…

彩虹外链网盘图床文件外链系统源码v5.5

彩虹外链网盘&#xff0c;是一款PHP网盘与外链分享程序&#xff0c;支持所有格式文件的上传&#xff0c;可以生成文件外链、图片外链、音乐视频外链&#xff0c;生成外链同时自动生成相应的UBB代码和HTML代码&#xff0c;还可支持文本、图片、音乐、视频在线预览&#xff0c;这…

软件杯 题目:基于深度学习的中文对话问答机器人

文章目录 0 简介1 项目架构2 项目的主要过程2.1 数据清洗、预处理2.2 分桶2.3 训练 3 项目的整体结构4 重要的API4.1 LSTM cells部分&#xff1a;4.2 损失函数&#xff1a;4.3 搭建seq2seq框架&#xff1a;4.4 测试部分&#xff1a;4.5 评价NLP测试效果&#xff1a;4.6 梯度截断…

SwiftUI六组合复杂用户界面

代码下载 应用的首页是一个纵向滚动的地标类别列表&#xff0c;每一个类别内部是一个横向滑动列表。随后将构建应用的页面导航&#xff0c;这个过程中可以学习到如果组合各种视图&#xff0c;并让它们适配不同的设备尺寸和设备方向。 下载起步项目并跟着本篇教程一步步实践&a…

[MQTT]服务器EMQX搭建SSL/TLS连接过程(wss://)

&#x1f449;原文阅读 &#x1f4a1;章前提示 本文采用8084端口进行连接&#xff0c;是EMQX 默认提供了四个常用的监听器之一&#xff0c;如果需要添加其他类型的监听器&#xff0c;可参考官方文档&#x1f517;管理 | EMQX 文档。 本文使用自签名CA&#xff0c;需要提前在L…

数据挖掘--挖掘频繁模式、关联和相关性:基本概念和方法

频繁项集、闭项集和关联规则 频繁项集&#xff1a;出现的次数超过最小支持度计数阈值 闭频繁项集&#xff1a;一个集合他的超集(包含这个集合的集合)在数据库里面的数量和这个集合在这个数据库里面的数量不一样,这个集合就是闭项集 如果这个集合还是频繁的,那么他就是极大频…

暂停系统更新

电脑左下角搜索注册表编辑器 计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings 找到这个目录 打开FlightSettingsMaxPauseDays&#xff0c;没找到的话就创建一个同名文件夹然后选择10进制填入3550​​​​​​​ 最后进入系统暂停更新界面选择最下面…

AI炒股:用Kimi获取美股的历史成交价格并画出股价走势图

在Kimi中输入提示词&#xff1a; 你是一个Python编程专家&#xff0c;要完成一个编写Python脚本的任务&#xff0c;具体步骤如下&#xff1a; 用akshare库获取谷歌(股票代码&#xff1a;105.GOOG)、亚马逊(股票代码&#xff1a;105.AMZN )、苹果(股票代码&#xff1a;105.AAP…