как получить HttpServletRequest данные тела несколько раз в весенней безопасности - PullRequest
0 голосов
/ 18 марта 2020

Сводка

В моем приложении я хочу сделать более детальную аутентификацию В 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 несколько раз? с нетерпением ждем вашего ответа. Спасибо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...