Сводка
В моем приложении я хочу сделать более детальную аутентификацию В AccessDecisionManager By HttpServletRequest Данные тела. Но данные тела HttpServletRequest получают только один раз. Другими словами, я реализовал AOP для инкапсуляции HttpServletRequest, который может читать данные тела несколько раз в Aspect
Actual Behavior
Если я прочитал данные тела HttpServletRequest один раз, я не смогу прочитать их позже (Контроллер не может получить Param!)
Ожидаемое поведение
Я что-то делаю 101
@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;
}
}
Описание: запрос пакета и поддержка нескольких операций чтения
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();
}
}
Описание: мой фильтр
@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);
}
}
}
Описание: 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;
}
}
В AOP я могу многократно получать данные тела HttpServletRequest, а мой фильтр добавляет Security FilterChain.
Конфигурация
@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();
}
Вопрос
в SecAccessDecisionManager, не может получить данные тела, кратные. как получить данные тела HttpServletRequest несколько раз? с нетерпением ждем вашего ответа. Спасибо