java - 使用带有 Spring security UsernameAndPasswordAuthFilter 的 MultiReadHttpServletRequest 时无法登录

标签 java spring spring-security aop aspectj

我正在尝试构建一个简单的日志记录工具,使用 AspectJ 可以打印 HttpServletRequest 主体。

为此,我创建了一个简单的 PointCut,它捕获 javax Filter.doFilter、HttpServlet doPost、doGet、service 等的所有执行。

然后,我将 HttpServletRequest 替换为我自己的请求包装器,该包装器复制请求的正文,以便可以多次调用它,以便我能够记录它。 请参阅 - https://github.com/Alotor/test-binding/blob/master/src/java/grails/util/http/MultiReadHttpServletRequest.java .

到目前为止,它工作得很好,直到我尝试在使用 Spring 安全过滤器的应用程序中记录主体。现在我无法登录,似乎 HttpServletRequstWrapper 的实现对 Spring 来说很重要,但我不知道在哪里以及为什么。

我的代码(对原始代码进行了一些修改,但它给出了想法):

aspect MyAspect {
     pointcut httpCalls(HttpServletRequest req, HttpServletResponse resp):
        args(req, resp, ..) && (execution(void             javax.servlet.Servlet+.service(..))
                || execution(void javax.servlet.Servlet+.doGet(..))
                ...
                || execution(void javax.servlet.Filter.doFilter(..));

   Object around(HttpServletRequest req, HttpServletResponse resp):httpCalls(req,resp) {
    ...
    if (!ThreadContext.getContext().wasReplaced()) { // we need to replace the request
        reqWrapper = new MultiReadHttpServletRequest(req);
        ThreadContext.getContext().setWasReplaced(true);           
        obj = proceed(reqWrapper, resp);
        TraceContextFactory.getFactory().getContext().setWasReplaced(false);
    } else { 
        obj = proceed(req, resp);
    }
    return obj;
  }

}

知道为什么我无法登录并且这无法与 Spring 安全一起使用吗? 我看到他们使用自己的包装器,但由于 API 是相同的,所以应该可以工作。

澄清一下 - 我正在 tomcat 上运行一个应用程序,并且我没有检测 org.apache.catalina (它不起作用,可能是由于类加载顺序阻止了aspectj 编织 tomcat 源代码)。

编辑:

我现在发现问题出在 UsernamePasswordAuthenticationFilter.java 内部:

 protected String obtainUsername(HttpServletRequest request) {
    return request.getParameter(usernameParameter);
}

如果我使用我的包装器,上面返回 null,否则它返回“guest”,这是我使用的用户名。我确实覆盖了输入流和阅读器,但实际调用 getParameter (...) 是通过底层请求完成的,该请求使用来自 org.apache.catalina.connector.RequestFacade 的原始输入流。

<强> http://localhost:8081/someApp/j_spring_security_check :

谢谢

最佳答案

无法登录,因为spring security调用了tomcat的org.apache.coyote.Request来读取参数。该请求不使用InputStream,而是使用BufferInput。无论哪种方式,它都不使用我包装的InputStream。

有两种解决方案:

  • request.getParametersMap() - 如果是 post 调用(例如登录,例如 spring security j_spring_security_check),您可以使用 request.getParametersMap() 并从中生成请求正文。
  • 使用 java 反射将 org.apach.coyote.Request 的 inputBuffer 替换为您自己的实现,允许从流中多次读取。

我选择了第一个选项,因为恕我直言,后者风险太大。

关于java - 使用带有 Spring security UsernameAndPasswordAuthFilter 的 MultiReadHttpServletRequest 时无法登录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36521793/

相关文章:

java - @Query 中是否可以进行灵活的排序?

java - Autowiring 到不同的bean

java - 从数据库或属性中获取 Spring Security 拦截 url

java - jframe 执行的操作 jframe

java - HashMap桶是什么类型

java - 如何使用 Retrofit 处理具有相同键 "Value"及其字符串和数组的 JSON 响应

java - 是否有任何基于 Spring-Security 的 Java 生产就绪安全包?

具有 2 个通用参数的 Java 类

java - Spring EntityManager.persist 问题

apache - 是否可以只允许 Apache HTTPd 静态资源访问在 Tomcat 中验证的客户端?