将MultiReadHttpServletRequest与Spring Security UsernameAndPasswordAuthFilter一起使用时无法登录 [英] Can't login while using MultiReadHttpServletRequest with 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 :
http://localhost:8081/someApp/j_spring_security_check:
谢谢
林
推荐答案
我无法登录,因为Spring安全调用了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.
有2种解决方案:
- request.getParametersMap()-如果发生邮寄呼叫(例如登录,例如spring security j_spring_security_check),则可以使用request.getParametersMap()并从中生成请求主体.
- 使用Java反射将org.apach.coyote.Request的inputBuffer替换为您自己的实现,该实现允许从流中读取多次.
我选择第一个选项是因为IMHO风险太大.
I chose the first option since the latter is too risky IMHO.
这篇关于将MultiReadHttpServletRequest与Spring Security UsernameAndPasswordAuthFilter一起使用时无法登录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!