为什么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相关推荐

  1. Spring Security 4 Method security using @PreAuthorize,@PostAuthorize, @Secured, EL--转

    原文地址:http://websystique.com/spring-security/spring-security-4-method-security-using-preauthorize-pos ...

  2. .netcore 和 java_Java Spring Boot VS .NetCore (九) Spring Security vs .NetCore Security

    谈到安全,如现在市面上有的 OAuth2 \ OIDC -OpenId Connect ,身份认证.授权等,下面先来说下Java Security 这一块的东西非常多复杂,不能是Spring Secu ...

  3. Spring Boot Admin 基于security 认证监控

    首先介绍一下Spring Boot Admin是用来干嘛的,它用于监控基于 Spring Boot 的应用,它是在 Spring Boot Actuator 的基础上提供简洁的可视化 WEB UI. ...

  4. 微信小程序图片与文字安全检测security.msgSecCheck和security.imgSecCheck

    微信小程序线上版本涉及到内容发布评论等,就需要进行安全检测,否则官方会上传一些huang图等敏感信息,这样就对我们的小程序的运行非常的不友好. 微信小程序图片与文字安全检测security.msgSe ...

  5. 非spring托管对象如何获取到spring托管对象

    非spring托管对象要获取到spring托管对象,主要是对ApplicationContext的获取 总共可以分为以下四种方式获取ApplicationContext: 一,通过spring配置文件 ...

  6. java 从一个容器获取对象,Java 如何实现从spring容器中获取注入的bean对象

    Java 如何实现从spring容器中获取注入的bean对象 发布时间:2020-11-03 15:27:37 来源:亿速云 阅读:70 作者:Leah 这期内容当中小编将会给大家带来有关Java 如 ...

  7. Spring认证指南:如何构建使用Spring Integration来获取数据

    原标题:如何构建使用Spring Integration来获取数据,处理数据并将其写入文件的应用程序.(Spring中国教育管理中心) 本指南将引导您完成使用 Spring Integration 创 ...

  8. spring 单例 获取多例的位_Spring 获取单例流程(一)

    读完这篇文章你将会收获到 在 getBean 方法中, Spring 处理别名以及 factoryBean 的 name Spring 如何从多级缓存中根据 beanName 获取 bean Spri ...

  9. 任意的android程序,Android任意位置获取应用Context

    在编写某些自定义类时,无法方便的取得Context(Activity或Application),例如需要获取res资源,取些drawable或string之类的,通常会比较麻烦. 解决方法一般有: 1 ...

最新文章

  1. 数据蒋堂 | 数据压缩手段
  2. 2015年3月-前端开发月刊
  3. mysql修改表引擎Engine
  4. 我是如何进入全球顶级AI实验室的 (1)
  5. 关于 Intel 8253/8254
  6. Android:数据库增删改查、SQLite、ORM、Cursor
  7. html无限添加元素,jquery--html【添加元素】
  8. ​【文末有福利】连续型随机变量及实例详解
  9. 十大下班最晚城市,四个在广东
  10. drools 7.11.0.Final使用
  11. 调整KDevelop字体大小
  12. qtreewidgetitem 选中背景颜色_列表式报表阶梯背景色效果
  13. 鄙视那些把爬虫当作AI的SB,清华学霸尹成大哥的历史上最强大的爬虫视频
  14. html上传文件出现fakepath,IE8上传文件时获取文件本地路径问题(C:\fakepath\……)的解决...
  15. 图形 1.3 纹理的秘密
  16. js仿百度文库文档上传页面的分类选择器_第二版
  17. 光盘镜像和系统启动盘制作
  18. Python 解析log日志
  19. 全局修改样式(全局颜色更改)
  20. 旧mac迁移到Mac21款m1后微信聊天记录文件显示未下载怎么办

热门文章

  1. 冯诺依曼结构和哈佛结构01
  2. 比CopyMemory还要快的函数SuperCopyMemory
  3. 毕啸南专栏 | 对话澜亭资本创始人刘炯:2018 AI创投领域如何“去伪存真”
  4. 共享GPU来了!投身去中心化机器学习,比挖矿多赚3倍
  5. 移民火星住哪?盖房的事就交给AI机器人Justin吧
  6. G盘文件系统损坏要如何恢复数据
  7. Leetcode 1.两数之和
  8. Django后端项目----restful framework 认证源码流程
  9. Redis笔记(六)Redis的消息通知
  10. Linux Kobject