如何在JMX调用的目标方法中获取发起请求的登录用户名
解决方案
方案1:直接读取JMX认证上下文
JMX规范本身已经实现了认证信息的上下文传递,用户通过JMX连接器认证后的身份信息会绑定到当前调用线程的安全上下文中,可以直接通过JDK自带的API获取:
import javax.security.auth.Subject; import java.security.AccessController; import java.security.Principal; // 目标方法内部直接调用即可 public String getCurrentJmxUser() { Subject subject = Subject.getSubject(AccessController.getContext()); if (subject == null) { return "anonymous"; } for (Principal principal : subject.getPrincipals()) { // 可根据你的SSO实现的Principal实际类型做过滤 return principal.getName(); } return "anonymous"; }
如果你的JDK版本开启了安全管理器限制,给这段代码加AccessController.doPrivileged包裹即可。
方案2:复用现有应用的用户上下文工具
因为你的系统已经接入SSO,绝大多数业务系统都会封装全局的获取当前登录用户的工具类,直接搜索现有代码中类似getCurrentUser()、getLoginUsername()的公共方法即可直接调用,无需额外处理JMX逻辑。
如果是Spring技术栈的应用,且JMX控制台走HTTP接口暴露,可以直接通过RequestContextHolder获取请求中的用户信息:
import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; public String getCurrentUser() { ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (attrs == null) { return "anonymous"; } HttpServletRequest request = attrs.getRequest(); return request.getUserPrincipal() != null ? request.getUserPrincipal().getName() : "anonymous"; }
方案3:通过JMX拦截器埋点传递用户信息
如果前两种方案都不生效,可以给MBeanServer注册自定义调用拦截器,在方法调用前置阶段把用户信息存入ThreadLocal,目标方法直接读取即可:
- 实现
MBeanServerInterceptor接口,在invoke方法执行前解析用户信息存入自定义的ThreadLocal变量 - 调用
MBeanServer的addMBeanServerInterceptor方法注册你的拦截器 - 目标方法直接读取ThreadLocal中存储的用户名即可,使用完注意清理ThreadLocal避免内存泄漏
注意事项
- 如果JMX调用是本地进程内发起的非认证请求,拿到的用户会是匿名身份,需要做兼容处理
- 部分商用应用服务器会对JMX上下文做自定义封装,可以直接查阅对应服务器的官方文档获取读取当前JMX用户的API
内容的提问来源于stack exchange,提问作者Tim B
相关产品推荐
相关产品推荐

