Summary
In my app,I want do more granular authentication In AccessDecisionManager By HttpServletRequest Body data.But HttpServletRequest Body data only get once。in other words, I implemented AOP to encapsulate HttpServletRequest, which can read the body data multiple times in the Aspect
Actual Behavior
If I read HttpServletRequest Body data once, I won't be able to read it later(Controller can‘t get Param!)
Expected Behavior
I do something but is very stupid。
@Component
public class SecAccessDecisionManager implements AccessDecisionManager {
private static final Logger log = LoggerFactory.getLogger(SecAccessDecisionManager.class);
@Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
if (null == configAttributes) {
return;
}
FilterInvocation fi = (FilterInvocation) object;
HttpServletRequest request = fi.getHttpRequest();
// RequestAttributes ra = RequestContextHolder.getRequestAttributes();
// ServletRequestAttributes sra = (ServletRequestAttributes) ra;
// HttpServletRequest request = sra.getRequest();
// try {
// System.out.println(request.getReader());
// } catch (IOException e) {
// e.printStackTrace();
// }
Iterator<ConfigAttribute> iterator = configAttributes.iterator();
while (iterator.hasNext()) {
}
throw new AccessDeniedException("...");
}
@Override
public boolean supports(ConfigAttribute attribute) {
return true;
}
@Override
public boolean supports(Class<?> clazz) {
return true;
}
}
Description: Package request And Support multiple reads
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
private final byte[] body;
private String bodyStr;
public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
String bodyString = getBodyString(request);
body = bodyString.getBytes(Charset.forName("UTF-8"));
bodyStr=bodyString;
}
public String getBodyStr() {
return bodyStr;
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public int read() throws IOException {
return byteArrayInputStream.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
}
public String getBodyString(HttpServletRequest request) throws IOException {
StringBuilder sb = new StringBuilder();
InputStream inputStream = null;
BufferedReader reader = null;
try {
inputStream = request.getInputStream();
reader = new BufferedReader(
new InputStreamReader(inputStream, Charset.forName("UTF-8")));
char[] bodyCharBuffer = new char[1024];
int len = 0;
while ((len = reader.read(bodyCharBuffer)) != -1) {
sb.append(new String(bodyCharBuffer, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return sb.toString();
}
}
Description: my Filter
@Component
@WebFilter(filterName = "MessageFilter", urlPatterns = {"/*"})
public class MessageFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
ServletRequest requestWrapper = null;
requestWrapper = new BodyReaderHttpServletRequestWrapper(request);
if (null == requestWrapper) {
filterChain.doFilter(request, response);
} else {
filterChain.doFilter(requestWrapper, response);
}
}
}
Description: Aspect
@Aspect
@Component
public class NotifyAspect {
private final Logger logger = LoggerFactory.getLogger(NotifyAspect.class);
// Pointcut
@Pointcut("execution(* com.zeusas.cloud.dcc.controller.*.*(..)))")
public void excude() {
}
@Around("excude()")
public Object loggingAround(ProceedingJoinPoint pjp){
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
HttpServletRequest request = sra.getRequest();
Object object = null;
try {
logger.info(((BodyReaderHttpServletRequestWrapper) request).getBodyStr());
object = pjp.proceed();
logger.info(((BodyReaderHttpServletRequestWrapper) request).getBodyStr());
//TODO
}
} catch (Throwable e) {
logger.info("throwing logging");
e.printStackTrace();
}
logger.info("after logging");
return object;
}
}
In AOP,I can get HttpServletRequest body data many times,And my Filter add Security FilterChain.
Configuration
@Override
protected void configure(HttpSecurity http) throws Exception {
MessageFilter messageFilter = new MessageFilter();
// messageFilter.setFailureHandler(new SecAuthenticationFailureHandler());
// add my Filter
http.addFilterBefore(messageFilter,UsernamePasswordAuthenticationFilter.class);
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = http.authorizeRequests();
registry.antMatchers(HttpMethod.OPTIONS, "/**").denyAll();
registry.and().rememberMe();
registry.and().formLogin().loginPage("/login").defaultSuccessUrl("/", true)
.usernameParameter("username").passwordParameter("password")
.and().logout();
registry.anyRequest().authenticated();
registry.and().exceptionHandling().accessDeniedHandler(secAccessDeniedHandler);
registry.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
@Override
public <O extends FilterSecurityInterceptor> O postProcess(O o) {
o.setSecurityMetadataSource(securityMetadataSource);
o.setAccessDecisionManager(secAccessDecisionManager);
return o;
}
});
registry.and().headers().frameOptions().disable();
http.csrf().disable();
}
Question
in the SecAccessDecisionManager,can not get body data multiple. how to get HttpServletRequest Body data multiple times?looking forward to your reply.Thanks
Comment From: rwinch
Thanks for getting in touch, but it feels like this is a question that would be better suited to Stack Overflow. As mentioned in the guidelines for contributing, we prefer to use GitHub issues only for bugs and enhancements. Feel free to update this issue with a link to the re-posted question (so that other people can find it) or add some more details if you feel this is a genuine bug.