spring security reactive获取security context
为什么80%的码农都做不了架构师?>>>
序
本文主要研究下reactive模式下的spring security context的获取。
ReactiveSecurityContextHolder
springboot2支持了webflux的异步模式,那么传统的基于threadlocal的SecurityContextHolder就不管用了。spring security5.x也支持了reactive方式,这里就需要使用reactive版本的SecurityContextHolder
spring-security-core-5.0.3.RELEASE-sources.jar!/org/springframework/security/core/context/ReactiveSecurityContextHolder.java
public class ReactiveSecurityContextHolder {private static final Class<?> SECURITY_CONTEXT_KEY = SecurityContext.class;/*** Gets the {@code Mono<SecurityContext>} from Reactor {@link Context}* @return the {@code Mono<SecurityContext>}*/public static Mono<SecurityContext> getContext() {return Mono.subscriberContext().filter( c -> c.hasKey(SECURITY_CONTEXT_KEY)).flatMap( c-> c.<Mono<SecurityContext>>get(SECURITY_CONTEXT_KEY));}/*** Clears the {@code Mono<SecurityContext>} from Reactor {@link Context}* @return Return a {@code Mono<Void>} which only replays complete and error signals* from clearing the context.*/public static Function<Context, Context> clearContext() {return context -> context.delete(SECURITY_CONTEXT_KEY);}/*** Creates a Reactor {@link Context} that contains the {@code Mono<SecurityContext>}* that can be merged into another {@link Context}* @param securityContext the {@code Mono<SecurityContext>} to set in the returned* Reactor {@link Context}* @return a Reactor {@link Context} that contains the {@code Mono<SecurityContext>}*/public static Context withSecurityContext(Mono<? extends SecurityContext> securityContext) {return Context.of(SECURITY_CONTEXT_KEY, securityContext);}/*** A shortcut for {@link #withSecurityContext(Mono)}* @param authentication the {@link Authentication} to be used* @return a Reactor {@link Context} that contains the {@code Mono<SecurityContext>}*/public static Context withAuthentication(Authentication authentication) {return withSecurityContext(Mono.just(new SecurityContextImpl(authentication)));}
}
可以看到,这里利用了reactor提供的context机制来进行异步线程的变量传递。
实例
public Mono<User> getCurrentUser() {return ReactiveSecurityContextHolder.getContext().switchIfEmpty(Mono.error(new IllegalStateException("ReactiveSecurityContext is empty"))).map(SecurityContext::getAuthentication).map(Authentication::getPrincipal).cast(User.class);}
源码解析
ServerHttpSecurity
spring-security-config-5.0.3.RELEASE-sources.jar!/org/springframework/security/config/web/server/ServerHttpSecurity.java
public SecurityWebFilterChain build() {if(this.built != null) {throw new IllegalStateException("This has already been built with the following stacktrace. " + buildToString());}this.built = new RuntimeException("First Build Invocation").fillInStackTrace();if(this.headers != null) {this.headers.configure(this);}WebFilter securityContextRepositoryWebFilter = securityContextRepositoryWebFilter();if(securityContextRepositoryWebFilter != null) {this.webFilters.add(securityContextRepositoryWebFilter);}if(this.csrf != null) {this.csrf.configure(this);}if(this.httpBasic != null) {this.httpBasic.authenticationManager(this.authenticationManager);this.httpBasic.configure(this);}if(this.formLogin != null) {this.formLogin.authenticationManager(this.authenticationManager);if(this.securityContextRepository != null) {this.formLogin.securityContextRepository(this.securityContextRepository);}if(this.formLogin.authenticationEntryPoint == null) {this.webFilters.add(new OrderedWebFilter(new LoginPageGeneratingWebFilter(), SecurityWebFiltersOrder.LOGIN_PAGE_GENERATING.getOrder()));this.webFilters.add(new OrderedWebFilter(new LogoutPageGeneratingWebFilter(), SecurityWebFiltersOrder.LOGOUT_PAGE_GENERATING.getOrder()));}this.formLogin.configure(this);}if(this.logout != null) {this.logout.configure(this);}this.requestCache.configure(this);this.addFilterAt(new SecurityContextServerWebExchangeWebFilter(), SecurityWebFiltersOrder.SECURITY_CONTEXT_SERVER_WEB_EXCHANGE);if(this.authorizeExchange != null) {ServerAuthenticationEntryPoint authenticationEntryPoint = getAuthenticationEntryPoint();ExceptionTranslationWebFilter exceptionTranslationWebFilter = new ExceptionTranslationWebFilter();if(authenticationEntryPoint != null) {exceptionTranslationWebFilter.setAuthenticationEntryPoint(authenticationEntryPoint);}this.addFilterAt(exceptionTranslationWebFilter, SecurityWebFiltersOrder.EXCEPTION_TRANSLATION);this.authorizeExchange.configure(this);}AnnotationAwareOrderComparator.sort(this.webFilters);List<WebFilter> sortedWebFilters = new ArrayList<>();this.webFilters.forEach( f -> {if(f instanceof OrderedWebFilter) {f = ((OrderedWebFilter) f).webFilter;}sortedWebFilters.add(f);});return new MatcherSecurityWebFilterChain(getSecurityMatcher(), sortedWebFilters);}
这里的build方法创建了securityContextRepositoryWebFilter并添加到webFilters里头
securityContextRepositoryWebFilter
private WebFilter securityContextRepositoryWebFilter() {ServerSecurityContextRepository repository = this.securityContextRepository;if(repository == null) {return null;}WebFilter result = new ReactorContextWebFilter(repository);return new OrderedWebFilter(result, SecurityWebFiltersOrder.REACTOR_CONTEXT.getOrder());}
这里创建了ReactorContextWebFilter
ReactorContextWebFilter
spring-security-web-5.0.3.RELEASE-sources.jar!/org/springframework/security/web/server/context/ReactorContextWebFilter.java
public class ReactorContextWebFilter implements WebFilter {private final ServerSecurityContextRepository repository;public ReactorContextWebFilter(ServerSecurityContextRepository repository) {Assert.notNull(repository, "repository cannot be null");this.repository = repository;}@Overridepublic Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {return chain.filter(exchange).subscriberContext(c -> c.hasKey(SecurityContext.class) ? c :withSecurityContext(c, exchange));}private Context withSecurityContext(Context mainContext, ServerWebExchange exchange) {return mainContext.putAll(this.repository.load(exchange).as(ReactiveSecurityContextHolder::withSecurityContext));}
}
这里使用reactor的subscriberContext将SecurityContext注入进去。
小结
基于reactor提供的context机制,spring security也相应提供了ReactiveSecurityContextHolder用来获取当前用户,非常便利。
doc
- 聊聊reactor异步线程的变量传递
- 5.10.3 EnableReactiveMethodSecurity
转载于:https://my.oschina.net/go4it/blog/1644969
spring security reactive获取security context相关推荐
- Spring Security 4 Method security using @PreAuthorize,@PostAuthorize, @Secured, EL--转
原文地址:http://websystique.com/spring-security/spring-security-4-method-security-using-preauthorize-pos ...
- .netcore 和 java_Java Spring Boot VS .NetCore (九) Spring Security vs .NetCore Security
谈到安全,如现在市面上有的 OAuth2 \ OIDC -OpenId Connect ,身份认证.授权等,下面先来说下Java Security 这一块的东西非常多复杂,不能是Spring Secu ...
- Spring Boot Admin 基于security 认证监控
首先介绍一下Spring Boot Admin是用来干嘛的,它用于监控基于 Spring Boot 的应用,它是在 Spring Boot Actuator 的基础上提供简洁的可视化 WEB UI. ...
- 微信小程序图片与文字安全检测security.msgSecCheck和security.imgSecCheck
微信小程序线上版本涉及到内容发布评论等,就需要进行安全检测,否则官方会上传一些huang图等敏感信息,这样就对我们的小程序的运行非常的不友好. 微信小程序图片与文字安全检测security.msgSe ...
- 非spring托管对象如何获取到spring托管对象
非spring托管对象要获取到spring托管对象,主要是对ApplicationContext的获取 总共可以分为以下四种方式获取ApplicationContext: 一,通过spring配置文件 ...
- java 从一个容器获取对象,Java 如何实现从spring容器中获取注入的bean对象
Java 如何实现从spring容器中获取注入的bean对象 发布时间:2020-11-03 15:27:37 来源:亿速云 阅读:70 作者:Leah 这期内容当中小编将会给大家带来有关Java 如 ...
- Spring认证指南:如何构建使用Spring Integration来获取数据
原标题:如何构建使用Spring Integration来获取数据,处理数据并将其写入文件的应用程序.(Spring中国教育管理中心) 本指南将引导您完成使用 Spring Integration 创 ...
- spring 单例 获取多例的位_Spring 获取单例流程(一)
读完这篇文章你将会收获到 在 getBean 方法中, Spring 处理别名以及 factoryBean 的 name Spring 如何从多级缓存中根据 beanName 获取 bean Spri ...
- 任意的android程序,Android任意位置获取应用Context
在编写某些自定义类时,无法方便的取得Context(Activity或Application),例如需要获取res资源,取些drawable或string之类的,通常会比较麻烦. 解决方法一般有: 1 ...
最新文章
- 数据蒋堂 | 数据压缩手段
- 2015年3月-前端开发月刊
- mysql修改表引擎Engine
- 我是如何进入全球顶级AI实验室的 (1)
- 关于 Intel 8253/8254
- Android:数据库增删改查、SQLite、ORM、Cursor
- html无限添加元素,jquery--html【添加元素】
- ​【文末有福利】连续型随机变量及实例详解
- 十大下班最晚城市,四个在广东
- drools 7.11.0.Final使用
- 调整KDevelop字体大小
- qtreewidgetitem 选中背景颜色_列表式报表阶梯背景色效果
- 鄙视那些把爬虫当作AI的SB,清华学霸尹成大哥的历史上最强大的爬虫视频
- html上传文件出现fakepath,IE8上传文件时获取文件本地路径问题(C:\fakepath\……)的解决...
- 图形 1.3 纹理的秘密
- js仿百度文库文档上传页面的分类选择器_第二版
- 光盘镜像和系统启动盘制作
- Python 解析log日志
- 全局修改样式(全局颜色更改)
- 旧mac迁移到Mac21款m1后微信聊天记录文件显示未下载怎么办