java如何在Spring Boot中获取每个请求中的当前用户?
我想在每个请求中获得用户的用户名,以便将其添加到日志文件中
这是我的解决方案:
首先,我创建了一个带有static
属性的LoggedUser
:
public class LoggedUser {
private static final ThreadLocal<String> userHolder =
new ThreadLocal<>();
public static void logIn(String user) {
userHolder.set(user);
}
public static void logOut() {
userHolder.remove();
}
public static String get() {
return userHolder.get();
}
}
然后我创建了一个支持类来获取用户名:
public interface AuthenticationFacade {
Authentication getAuthentication();
}
@Component
public class AuthenticationFacadeImpl implements AuthenticationFacade {
@Override
public Authentication getAuthentication() {
return SecurityContextHolder.getContext().getAuthentication();
}
}
最后,我在控制器中使用了它们:
@RestController
public class ResourceController {
Logger logger = LoggerFactory.getLogger(ResourceController.class);
@Autowired
private GenericService userService;
@Autowired
private AuthenticationFacade authenticationFacade;
@RequestMapping(value ="/cities")
public List<RandomCity> getCitiesAndLogWhoIsRequesting(){
loggedUser.logIn(authenticationFacade.getAuthentication().getName());
logger.info(LoggedUser.get()); //Log username
return userService.findAllRandomCities();
}
}
问题是我不希望在每个@Controller
中都有AuthenticationFacade
,例如,如果我有10000个控制器,那将需要大量的工作
你有更好的解决办法吗
# 1 楼答案
Spring安全性中有various ways用于从安全上下文中获取用户详细信息。但根据您的要求,您只对用户名感兴趣,因此您可以尝试以下方法:
希望这有帮助
# 2 楼答案
好的,您已经直接从SecurityContextHolder访问了身份验证对象,您可以在控制器中进行访问
如果您不想将所有这些放在每个端点中,可以创建一个实用程序方法来提取身份验证,并在找到时返回其名称
在端点中调用它,就像
然而,您仍然在每个端点中添加代码行,在添加了几行代码之后,被迫这样做会让您感觉不对劲。我建议您尝试使用面向方面的编程来实现这类功能。这将需要您投入一些时间来学习它的工作原理,创建所需的注释或执行。但你应该在一两天内拿到。 使用面向方面的方法,端点可以这样结束
当然,您可以删除@LogUserName自定义注释,并配置由包内的方法或扩展@Controller的类触发的新特性,等等。 当然这是值得的,因为您可以使用aspect来记录用户名
# 3 楼答案
该解决方案称为鱼标签。每个好的日志框架都有这个功能。一些框架称之为
MDC
(映射的诊断上下文)。你可以在here和here读到它基本思想是使用
ThreadLocal
或InheritableThreadLocal
在线程中保存一些键值对来跟踪请求。使用日志配置,您可以配置如何在日志条目中打印日志基本上,您可以编写一个过滤器,从安全上下文中检索用户名并将其放入
MDC
中,然后忘记它。在控制器中,您只记录与业务逻辑相关的内容。用户名将与时间戳、日志级别等一起打印在日志条目中(根据您的日志配置)# 4 楼答案
根据Jhovanni的建议,我创建了一个AOP注释,如下所示:
在同一个包中,我使用}类:
AuthenticationFacade
注入添加了新的@Aop
{然后,在每个
@GetMapping
方法中,如果我需要记录用户名,我可以在方法之前添加注释:最后,这是结果:
# 5 楼答案
您可以通过控制器方法中的请求或参数获取用户名。如果添加
Principal principal
作为参数,SpringIoC容器将注入有关用户的信息,或者对于匿名用户,它将为null