我有一个需求,想获取当前已经登录的用户的详细信息。为了获得该用户的详细信息,我们可以使用 SecurityContextHolder.getContext()
并提取细节。根据:
SecurityContextHolder,SecurityContext和认证对象。
默认情况下, SecurityContextHolder
使用 ThreadLocal
来存储这些细节,这意味着安全上下文始终可供在 一脉相承. 使用 ThreadLocal
这样一来 quite safe if care is taken to clear the thread after the present principal’s request is processed
. 当然,Spring Security会自动为您处理这些问题,所以无需担心。
在Spring Security中,负责存储的是 SecurityContext
在请求之间,属于 SecurityContextPersistenceFilter
,它默认将上下文存储为一个 HttpSession
间的属性 HTTP请求. 它将上下文恢复到 SecurityContextHolder
对于每项请求,关键是。当请求完成时,清除SecurityContextHolder。
许多其他类型的应用(例如,a) 无状态的RESTful web服务)不使用 HTTP会话,并将在每次请求时重新进行身份验证。. 然而,仍然重要的是 SecurityContextPersistenceFilter
包括在链中,以确保。SecurityContextHolder
每次请求后都会被清除。
问题是
我需要在服务层的多个地方返回基于用户权限的用户详细信息,所以我们有一个静态方法来返回这些详细信息。该项目由REST API和会话创建策略组成,具体如下 SessionCreationPolicy.STATELESS
与 SecurityContextHolderStrategy
作为 ThreadLocal
. 服务层包括 @Transactional
.
现在考虑对API的多个并发请求。
SecurityContextPersistenceFilter
对于 STATELESS 应用,是否需要手动配置?SecurityContextHolderStrategy
作为 ThreadLocal
?ThreadLocal
策略和静态方法?环境。
框架:Spring Boot ORM:Hibernate Spring Boot ORM: Hibernate Database: Postgres架构。单片机(即将迁移到微服务)
如有需要,我会补充更多细节
UPDATE。
感谢@Macro,如前所述,为 SessionCreationPolicy.STATELESS
,
SessionManagementConfigurer
包括 isStateless()
方法,返回 真正 为无状态策略。在此基础上,http将共享对象与 NullSecurityContextRepository
和请求缓存 NullRequestCache
. 因此,没有价值将在 HttpSessionSecurityContextRepository
. 所以,对于使用静态方法的用户来说,可能不存在无效的问题。
SecurityContextHolderStrategy
对用户细节有任何影响 MODE_INHERITABLETHREADLOCAL, MODE_THREADLOCAL。 因为没有值将被设置为共享对象与 HttpSessionSecurityContextRepository
?编码:
if (stateless) {
http.setSharedObject(SecurityContextRepository.class,
new NullSecurityContextRepository());
}
if (stateless) {
http.setSharedObject(RequestCache.class, new NullRequestCache());
}
代码:代码。
静态方法获取用户信息
public static Optional<String> getCurrentUserLogin() {
SecurityContext securityContext = SecurityContextHolder.getContext();
return Optional.ofNullable(extractPrincipal(securityContext.getAuthentication()));
}
private static String extractPrincipal(Authentication authentication) {
if (authentication == null) {
return null;
} else if (authentication.getPrincipal() instanceof UserDetails) {
UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal();
return springSecurityUser.getUsername();
} else if (authentication.getPrincipal() instanceof String) {
return (String) authentication.getPrincipal();
}
return null;
}
public static Optional<Authentication> getAuthenticatedCurrentUser() {
log.debug("Request to get authentication for current user");
SecurityContext securityContext = SecurityContextHolder.getContext();
return Optional.ofNullable(securityContext.getAuthentication());
}
会话管理
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
笔记
SecurityContextHolderStrategy 作为 ThreadLocal
该 服务层 包括 @Transactional
.
设置
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
将导致Spring安全使用一个 NullSecurityContextRepository
而不是默认的 HttpSessionSecurityContextRepository
.
它是一个简单的实现,因为它不会简单地保存任何东西到HTTP Session中,并为每个请求创建一个完全的 new and empty SecurityContext
,因此没有存储认证等。
所以,回答你的第一个问题。
SecurityContextPersistenceFilter就像HttpSessionRepository一样工作,不需要其他手动配置。
回答你的第二个和第三个问题,关于Threadlocals。
是的,这就是使用它们的目的,而且这也是默认的策略。所以,每个线程都有自己的SecurityContext认证对象。你是用静态方法访问ThreadLocal,因此没有机会访问 "错误的 "用户信息。在你的用例中使用 "GlocalSecurityContextHolderStrategy "会有问题,但无论如何,这不是你正在做的事情。
另外,请记住,所有这些都与@Transactionals无关。