首页 > 其他分享 >六、认证流程

六、认证流程

时间:2023-06-07 22:57:18浏览次数:31  
标签:return switchIfEmpty exchange Mono 流程 认证 authentication String

一、switchIfEmpty

在讨论登录流程之前,先看下Spring Web Flux中的switchIfEmpty用法。

@Test
public void test1() {
    Mono.just("test1")
            .flatMap(val -> {
                return Mono.just("test2");
            })
            .switchIfEmpty(method1())
            .subscribe(s -> System.out.println(s));
}


private static Mono<String> method1() {
    System.out.println("test3");
    return Mono.empty();
}

输出:

test3
test2

其中subscribe(System.out::println)打印的是map的结果,而不是switchIfEmpty的返回结果。

 

继续看:

 private static Mono<String> method1() {
    System.out.println("test3");
    return Mono.empty();
}

@Test
public void test2() {
    Mono.just("test1")
            .flatMap(val -> {
                return Mono.empty();
            })
            .switchIfEmpty(method1())
            .subscribe(s -> System.out.println(s));
}

输出:

test3

看到subscribe(s -> System.out.println(s))没有执行。从上面可知switchIfEmpty的上一个操作返回空,则switchIfEmpty的下一个操作不会执行。但是无论如何switchIfEmpty对应的操作都会执行。例如上面的method1()都会执行。

 

二、认证流程

认证由AuthenticationWebFilter处理。AuthenticationWebFilter相当于SpringSecurity的UsernamePasswordAuthenticationFilter。
 

AuthenticationWebFilter实现了WebFilter接口:

    public interface WebFilter {

    	Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain);

    }

 

AuthenticationWebFilter#filter

@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
	return this.requiresAuthenticationMatcher.matches(exchange).filter((matchResult) -> matchResult.isMatch())
			.flatMap((matchResult) -> this.authenticationConverter.convert(exchange))
			.switchIfEmpty(chain.filter(exchange).then(Mono.empty()))
			.flatMap((token) -> authenticate(exchange, chain, token))
			.onErrorResume(AuthenticationException.class, (ex) -> this.authenticationFailureHandler
					.onAuthenticationFailure(new WebFilterExchange(exchange, chain), ex));
}

ServerWebExchange相当于Servlet中的HttpServletRequest和HttpServletResponse。requiresAuthenticationMatcher在ServerHttpSecurity中是ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, loginPage),匹配post方式的登录接口。authenticationConverter是org.springframework.security.web.server.authentication.ServerAuthenticationConverter,用户将表单信息转换成Authentication。下一个操作是switchIfEmpty。如果Authentication为空就不会执行下一个操作authenticate(进行用户认证)。如果出现AuthenticationException异常,authenticationFailureHandler处理认证失败。

 

authenticationConverter默认是ServerFormLoginAuthenticationConverter:

@SuppressWarnings("deprecation")
public class ServerFormLoginAuthenticationConverter
		extends org.springframework.security.web.server.ServerFormLoginAuthenticationConverter
		implements ServerAuthenticationConverter {

	@Override
	public Mono<Authentication> convert(ServerWebExchange exchange) {
		return apply(exchange);
	}

}

如果要自定义解析参数,可以实现org.springframework.security.web.server.authentication.ServerAuthenticationConverter接口。 convert调用了org.springframework.security.web.server.ServerFormLoginAuthenticationConverterapply:

private String usernameParameter = "username";

private String passwordParameter = "password";

@Override
@Deprecated
public Mono<Authentication> apply(ServerWebExchange exchange) {
	return exchange.getFormData().map((data) -> createAuthentication(data));
}

private UsernamePasswordAuthenticationToken createAuthentication(MultiValueMap<String, String> data) {
	String username = data.getFirst(this.usernameParameter);
	String password = data.getFirst(this.passwordParameter);
	return UsernamePasswordAuthenticationToken.unauthenticated(username, password);
}

从请求中获取用户名和密码组装成UsernamePasswordAuthenticationToken。

 

再来看下AuthenticationWebFilter的authenticate:

private Mono<Void> authenticate(ServerWebExchange exchange, WebFilterChain chain, Authentication token) {
	return this.authenticationManagerResolver.resolve(exchange)
			.flatMap((authenticationManager) -> authenticationManager.authenticate(token))
			.switchIfEmpty(Mono.defer(
					() -> Mono.error(new IllegalStateException("No provider found for " + token.getClass()))))
			.flatMap((authentication) -> onAuthenticationSuccess(authentication,
					new WebFilterExchange(exchange, chain)))
			.doOnError(AuthenticationException.class,
					(ex) -> logger.debug(LogMessage.format("Authentication failed: %s", ex.getMessage())));
}

authenticationManagerResolver可以看作是认证管理器。调用authenticationManager.authenticate进行用户认证。authenticationManager默认是UserDetailsRepositoryReactiveAuthenticationManager。如果认证成功就调用onAuthenticationSuccess处理认证成功后的逻辑。

 

接下来看UserDetailsRepositoryReactiveAuthenticationManager,UserDetailsRepositoryReactiveAuthenticationManager继承了AbstractUserDetailsReactiveAuthenticationManager:

public Mono<Authentication> authenticate(Authentication authentication) {
	String username = authentication.getName();
	String presentedPassword = (String) authentication.getCredentials();
	// @formatter:off
	return retrieveUser(username)
			.doOnNext(this.preAuthenticationChecks::check)
			.publishOn(this.scheduler)
			.filter((userDetails) -> this.passwordEncoder.matches(presentedPassword, userDetails.getPassword()))
			.switchIfEmpty(Mono.defer(() -> Mono.error(new BadCredentialsException("Invalid Credentials"))))
			.flatMap((userDetails) -> upgradeEncodingIfNecessary(userDetails, presentedPassword))
			.doOnNext(this.postAuthenticationChecks::check)
			.map(this::createUsernamePasswordAuthenticationToken);
	// @formatter:on
}

retrieveUser通过用户名查询出UserDetails。接下来的操作和SpringSecurity中的类似。都是检查用户状态是否锁定,用户状态是否过期,密码是否过期,是否启用账户,以及进行密码对比等。

UserDetailsRepositoryReactiveAuthenticationManager#retrieveUser

protected Mono<UserDetails> retrieveUser(String username) {
	return this.userDetailsService.findByUsername(username);
}

调用ReactiveUserDetailsService通过用户名查询出UserDetails。如果要从数据库查询出用户。可以实现ReactiveUserDetailsService。

 

再看下AuthenticationWebFilter的authenticationFailureHandler,默认实现是new RedirectServerAuthenticationFailureHandler(loginPage + "?error")。重定向到登录页面并携带错误提示信息。

最后看AuthenticationWebFilter的onAuthenticationSuccess:

protected Mono<Void> onAuthenticationSuccess(Authentication authentication, WebFilterExchange webFilterExchange) {
	ServerWebExchange exchange = webFilterExchange.getExchange();
	SecurityContextImpl securityContext = new SecurityContextImpl();
	securityContext.setAuthentication(authentication);
	return this.securityContextRepository.save(exchange, securityContext)
			.then(this.authenticationSuccessHandler.onAuthenticationSuccess(webFilterExchange, authentication))
			.subscriberContext(ReactiveSecurityContextHolder.withSecurityContext(Mono.just(securityContext)));
}

securityContextRepository默认实现是WebSessionServerSecurityContextRepository。将Authentication保存到WebSession中。authenticationSuccessHandler实现是new RedirectServerAuthenticationSuccessHandler("/")。重定向到根路径。最后将securityContext设置到ReactiveSecurityContextHolder。

标签:return,switchIfEmpty,exchange,Mono,流程,认证,authentication,String
From: https://www.cnblogs.com/shigongp/p/17464735.html

相关文章

  • Vue 执行流程
    1.main.js项目入口文件2.App.vue创建路由,设置App的样式,由router-link链接到响应的路由地址不同版本的vue区别3.router>index.js注册APP下的二级路由到不同视图4.public>index.htmlpublic下的页面配置,public的路由是5.自定义配置文件不能更改的文件:......
  • 恒电流间歇滴定法(GITT)测试锂离子电池的实验流程
    恒电流间歇滴定法(GITT)测试锂离子电池的实验流程锂电池作为现代电子设备中最常用的电源之一,其性能和安全性对于设备的正常运行至关重要。恒电流间歇滴定测试是一种常用的测试方法,用于评估锂电池的容量、循环寿命和内阻等关键参数。1、确定测试目的和参数:在进行恒电流间歇滴定测试之......
  • 华为认证 | HCIE-存储 V3.0 即将发布!
    华为认证HCIE-StorageV3.0(中文版)预计将于2023年6月30日正式对外发布。为了帮助您做好学习、培训和考试计划,现进行预发布通知,请您关注。01发布概述基于“平台+生态”战略,围绕“云-管-端”协同的新ICT技术架构,华为公司打造了覆盖ICT领域的认证体系。包含ICT基础设施认证、基础软硬......
  • OmniPlan Pro 4 Mac专业项目流程管理工具
    OmniPlanPro4forMac是一款专业的项目流程管理工具,这款软件可以让你更加快速的将一个任务完成,并在不同的工作环境中快速切换。同时能够实现项目的有效管理,让你随时随地都能进行项目的推进。该软件适用于MacOSX10.13或更高版本,拥有强大而专业的功能、丰富而专业的自定义功能以......
  • EasyCVR视频融合平台国标GB设备语音喊话流程优化
    EasyCVR视频融合平台基于云边端一体化架构,可支持多协议、多类型设备接入,在视频能力上,平台可实现视频直播、录像、回放、检索、云存储、告警上报、语音对讲、电子地图、集群、智能分析以及平台级联等。其中,语音对讲功能可以实现对监控现场的语音喊话、双向对讲,只要前端设备带语音功......
  • 网迅科技与浪潮信息KOS完成兼容性认证
    日前,北京网迅科技有限公司多款产品与浪潮信息KOS完成并通过了澎湃技术认证,此次测试的产品包括网迅科技WX1860系列千兆网络控制器、SP1000A/WX1820AL万兆网络控制器,和浪潮信息服务器操作系统KOSV5。经测试,网迅科技两个系列产品在KOS上运行稳定,兼容性良好,满足用户的关键性应用需求,与......
  • 增效又灵活的在线快速开发平台,助力企业进入流程化管理!
    一直有不少粉丝随时来询问:企业要想做好数据管理,从此进入流程化管理,可以选择什么样的平台软件?众所周知,在数字化转型发展时期,在线快速开发平台凭借其灵活、简便、易操作等优势特征,成为提升企业办公协作效率,提升表格制作水平,做好数据管理的重要助手。关键是如何选择服务商,如何选择适......
  • 流程控制之for循环
    目录一、语法二、for+break三、for+continue四、for循环嵌套五、for+else六、for循环实现loading一、语法for循环可以用于对序列(如字符串、列表或元组)进行迭代操作,其基本语法如下:复制代码for变量in序列:循环体代码其中变量是在每次迭代时,序列中的下一个值,并且该......
  • Zabbix监控流程
    明确监控的内容内置模板中是否有内容的实现如果没有,只能自定义编写采集数据的命令程序实现修改agent配置,添加自定义监控项 /etc/zabbix/zabbix_agentd.d/test.conf创建模板在模板上创建监控项、主机上关联模板案例vim/etc/zabbix/zabbix_agentd.d/test.conf#此路......
  • 游戏初始化流程
    1、2023-6-6观看暗黑战神中 看到 其实再游戏中他们不会用很多的start和另外一个进行初始化    他这样写的好处就是知道 我们初始化的一个顺序......