使用 MultiReadHttpServletRequest 和 Spring security UsernameAndPasswordAuthFilter 时无法登录 [英] Can't login while using MultiReadHttpServletRequest with Spring security UsernameAndPasswordAuthFilter

查看:22
本文介绍了使用 MultiReadHttpServletRequest 和 Spring security UsernameAndPasswordAuthFilter 时无法登录的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to build a simple logging tool that using AspectJ can print the HttpServletRequest body.

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

For this I created a simple PointCut that catches all executions of javax Filter.doFilter, HttpServlet doPost, doGet, service etc.

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

I then replace the HttpServletRequest with my own request wrapper that copies the request's body so it can be called more than once so I'll be able to log it. See - https://github.com/Alotor/test-binding/blob/master/src/java/grails/util/http/MultiReadHttpServletRequest.java.

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

It worked fine so far until I tried to log the body in an application that uses Spring security filters. Now I can't login, seems that somehow the implementation of the HttpServletRequstWrapper is important for Spring, but I can't figure out where and why.

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

My code (a bit modified from the original, but it gives the idea):

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 是相同的,所以它应该可以工作.

Any idea why I can't login and this fails to work with Spring security? I saw that they are using their own wrappers, but since the API is the same it should have worked.

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

For clarification - I'm running an application on tomcat, and I'm not instrumenting org.apache.catalina (it doesn't work, probably due to class loading order that prevents the aspectj from weaving tomcat source code).

我现在看到问题出在 UsernamePasswordAuthenticationFilter.java 中:

I see now the the problem is inside the UsernamePasswordAuthenticationFilter.java:

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

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

The above returns null in case I use my Wrapper, otherwise it returns "guest", which is the username I used. I did override the inputstream and the reader, but the actual call to getParameter(...) is done through the underlying request which uses the original input stream from org.apache.catalina.connector.RequestFacade.

http://localhost:8081/someApp/j_spring_security_check:

谢谢,

推荐答案

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

I couldn't login because spring security called tomcat's org.apache.coyote.Request to read the parameters. The request doesn't use an InputStream, but a BufferInput. Either way, it doesn't use my wrapped InputStream.

有两种解决方案:

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

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

I chose the first option since the latter is too risky IMHO.

这篇关于使用 MultiReadHttpServletRequest 和 Spring security UsernameAndPasswordAuthFilter 时无法登录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆