Spring 安全架构 - 线程应用

Spring Security 从根本上讲是线程绑定的,因为它需要使当前经过身份验证的主体可供各种下游使用者使用。基本构件是 SecurityContext,它可以包含一个 Authentication(当用户登录时,它将是一个经过显式 authenticatedAuthentication)。你始终可以通过 SecurityContextHolder 中的静态便捷方法来访问和操作 SeucurityContext,而该方法又可以简单地操作 ThreadLocal,例如:

SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
assert(authentication.isAuthenticated);

用户应用代码执行该操作并不常见,但是例如在你需要编写自定义身份验证过滤器时可能会很有用(尽管即使如此,Spring Security 中也可以使用基类来避免需要使用 SecurityContextHolder)。

如果你需要访问 Web 端点中当前经过身份验证的用户,则可以在 @RequestMapping 中使用 method 参数。例如:

@RequestMapping("/foo")
public String foo(@AuthenticationPrincipal User user) {
  ... // do stuff with user
}

该注解将当前的 AuthenticationSecurityContext 中拉出,并对其调用 getPrincipal() 方法以产生 method 参数。Authentication 中的 Principal 类型取决于验证身份验证的 AuthenticationManager,因此这是获得对用户数据的类型安全应用的有用的小技巧。

如果使用 Spring Security,则 HttpServletRequest 中的 Principal 将为 Authentication 类型,因此你也可以直接使用它:

@RequestMapping("/foo")
public String foo(Principal principal) {
  Authentication authentication = (Authentication) principal;
  User = (User) authentication.getPrincipal();
  ... // do stuff with user
}

如果你需要编写在不使用 Spring Security 时可以工作的代码,那么有时这很有用(你需要在装入 Authentication 类时更具防御性)。

异步处理安全方法

由于 SecurityContext 是线程绑定的,因此,如果要执行任何调用安全方法的后台处理,例如使用 @Async,你需要确保传播上下文。这归结为将 SecurityContext 打包为在后台执行的任务(RunnableCallable 等)。Spring Security 提供了一些帮助程序,例如 RunnableCallable 的包装器。要将 SecurityContext 传播到 @Async 方法,你需要提供 AsyncConfigurer 并确保 Executor 具有正确的类型:

@Configuration
public class ApplicationConfiguration extends AsyncConfigurerSupport {

  @Override
  public Executor getAsyncExecutor() {
    return new DelegatingSecurityContextExecutorService(Executors.newFixedThreadPool(5));
  }

}
发布了228 篇原创文章 · 获赞 13 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/stevenchen1989/article/details/105237635
今日推荐