You need to enable JavaScript to run this app. Tomcat 9访问日志无法显示HttpSession登录的%u用户名如何解决
优惠活动
大模型
产品
解决方案
定价
更多

Tomcat 9访问日志无法显示HttpSession登录的%u用户名如何解决

解决方案

Tomcat默认AccessLogValve里的%u占位符读取的是HttpServletRequest.getRemoteUser()返回值,这个值只有在使用Tomcat内置的容器认证(比如Basic认证、JDBC Realm等)时才会被自动填充,你自行存在HttpSession里的username默认不会被日志组件识别,所以对应位置显示为-,这个需求可以通过以下两种方案实现:


方案1:通过Request属性传递用户名(最便捷)

无需改动原有日志结构,只要补充少量代码即可:

  • 第一步修改你的LoginFilter,在doFilter方法逻辑里添加属性赋值:
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;
    HttpSession session = request.getSession(false);
    String loginURI = request.getContextPath() + "/login.jsp";
    boolean loggedIn = session != null && session.getAttribute("username") != null;
    boolean loginRequest = request.getRequestURI().equals(loginURI);

    // 新增:把用户名存入Request属性,未登录则赋值为-
    if (loggedIn) {
        request.setAttribute("access_log_username", session.getAttribute("username"));
    } else {
        request.setAttribute("access_log_username", "-");
    }

    // 原有逻辑保持不变
    if(loginRequest) {
        if (loggedIn) {
            response.sendRedirect(request.getContextPath() + "/system.jsp");
        }
        else {
            chain.doFilter(request, response);
        }
    } else {
        // 原有其他逻辑
        chain.doFilter(request, response);
    }
}
  • 第二步修改server.xml里的AccessLogValve配置,把原来的%u替换为%{access_log_username}r:
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
       prefix="localhost_access_log" suffix=".txt"
       pattern="%{X-Forwarded-For}i %l %{access_log_username}r %t &quot;%r&quot; %s %b" />
  • 重启Tomcat后即可生效,已登录用户的用户名会正常显示在日志对应位置。

方案2:重写getRemoteUser方法兼容原生%u占位符

如果你不想修改原有日志pattern的结构,可以通过HttpServletRequestWrapper包装请求,重写getRemoteUser方法返回session中的用户名:

  1. 先在Filter同包下创建请求包装类:
public class UserInfoRequestWrapper extends HttpServletRequestWrapper {
    public UserInfoRequestWrapper(HttpServletRequest request) {
        super(request);
    }

    @Override
    public String getRemoteUser() {
        HttpSession session = getSession(false);
        if (session != null && session.getAttribute("username") != null) {
            return (String) session.getAttribute("username");
        }
        return super.getRemoteUser();
    }
}
  1. 修改LoginFilter的doFilter方法,把包装后的请求传递给后续流程:
// 原有逻辑判断完loggedIn之后,传递包装后的请求
chain.doFilter(new UserInfoRequestWrapper(request), response);
  1. 无需修改server.xml的原有pattern配置,重启Tomcat即可生效。

注意事项

  • 如果需要对全站所有请求都记录用户名,需要把LoginFilter的urlPatterns改为/*,否则仅匹配你当前配置的几个路径的请求会显示用户名。
  • 日志是在请求处理完成后输出,只要在请求处理流程中设置的Request属性或包装类逻辑都会被正确读取。

内容的提问来源于stack exchange,提问作者Jan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.14 23:15:01