【发布时间】:2023-04-03 19:00:01
【问题描述】:
我需要获取当前已登录用户的详细信息。要获取详细信息,我们可以使用SecurityContextHolder.getContext() 并提取详细信息。据了解,
SecurityContextHolder, SecurityContext and Authentication Objects
默认情况下,SecurityContextHolder 使用ThreadLocal 来存储这些详细信息,这意味着安全上下文始终可用于同一执行线程中的方法。以这种方式使用ThreadLocal 是quite safe if care is taken to clear the thread after the present principal’s request is processed。当然,Spring Security 会自动为您处理这些,因此您无需担心。
Storing the SecurityContext between requests
在 Spring Security 中,存储请求之间的SecurityContext 的责任落在了SecurityContextPersistenceFilter 上,它默认将上下文存储为HTTP 请求之间的HttpSession 属性。它将每个请求的上下文恢复到 SecurityContextHolder,并且至关重要的是,在请求完成时清除 SecurityContextHolder
许多其他类型的应用程序(例如,无状态 RESTful 网络服务)不使用 HTTP 会话,并且会在每个请求上重新进行身份验证。但是,将SecurityContextPersistenceFilter 包含在链中以确保在每次请求后清除SecurityContextHolder 仍然很重要。
问题是
我要求服务层多处的用户详细信息根据用户权限返回信息,所以我们有一个静态方法返回这些详细信息。该项目由 REST API 和会话创建策略组成,SessionCreationPolicy.STATELESS,SecurityContextHolderStrategy,ThreadLocal。服务层由@Transactional 组成。
现在考虑对 API 的多个并发请求,
- Spring Security 将如何为 STATELESS 应用程序管理
SecurityContextPersistenceFilter,是否需要手动配置? - 可以将
SecurityContextHolderStrategy用作ThreadLocal吗? - 由于
ThreadLocal策略和静态方法,是否有可能获取错误/无效的用户详细信息?
环境:
框架:Spring Boot
ORM:休眠
数据库:Postgres
架构:单体(即将迁移到微服务)
如果需要,我会添加更多详细信息
更新:
感谢@Macro,如上所述,SessionCreationPolicy.STATELESS,
SessionManagementConfigurer 由isStateless() 方法组成,该方法为无状态策略返回 true。基于该 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 as ThreadLocal
服务层由@Transactional组成。
【问题讨论】:
标签: java spring spring-boot spring-security static