如何在Spring Boot中的每个请求中获取当前用户?

Tra*_*hoa 4 java spring spring-mvc spring-boot

我想在每个请求中获取用户的用户名,以将其添加到日志文件中。

这是我的解决方案:

首先,我创建了一个LoggedUser具有static属性的:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我创建了一个支持类来获取用户名:

public interface AuthenticationFacade {
    Authentication getAuthentication();
}
Run Code Online (Sandbox Code Playgroud)
@Component
public class AuthenticationFacadeImpl implements AuthenticationFacade {
    @Override
    public Authentication getAuthentication() {
        return SecurityContextHolder.getContext().getAuthentication();
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,我在我的控制器中使用了它们:

    @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();
        }
    }
Run Code Online (Sandbox Code Playgroud)

问题是我不想AuthenticationFacade在每个控制器中都有@Controller,例如,如果我有 10000 个控制器,这将是很多工作。

您有更好的解决方案吗?

Sap*_*asu 6

该解决方案称为“鱼类标记”。每个像样的日志框架都有这个功能。一些框架称之为MDC(映射诊断上下文)。您可以在这里这里阅读相关内容。

基本思想是在线程中使用ThreadLocalInheritableThreadLocal保存一些键值对来跟踪请求。使用日志记录配置,您可以配置如何在日志条目中打印它。

基本上,您可以编写一个过滤器,在其中从安全上下文中检索用户名并将其放入,MDC然后就不用管它了。在您的控制器中,您仅记录与业务逻辑相关的内容。用户名将与时间戳、日志级别等一起打印在日志条目中(根据您的日志配置)。