аутентификация безопасности весенней загрузки для проверки содержимого тела

Я хочу аутентифицировать одну из пар ключ-значение тела почтового запроса, но я хочу сделать то же самое с помощью перехватчика/фильтра. Как я могу это сделать?


person Pankaj Sharma    schedule 26.09.2020    source источник
comment
Вы не можете вызвать response.sendError(..) after filterChain.doFilter (запрос, ответ)`. Потому что последний вызов записывает ответ в outputstream и, следовательно, ошибку. Второе решение, которое я опубликовал, похоже, работает локально для меня.   -  person Suman    schedule 28.09.2020
comment
Получите тело запроса с помощью req.getReader().lines().collect(Collectors.joining(System.lineSeparator())) И попробуйте.   -  person Suman    schedule 28.09.2020
comment
он показывает, что getReader() уже вызывается для этого запроса   -  person Pankaj Sharma    schedule 28.09.2020
comment
Да, я уже упоминал об этом. Упомянули в комментариях выше   -  person Pankaj Sharma    schedule 28.09.2020
comment
Но можно ли это сделать, чтобы решить проблему?   -  person Pankaj Sharma    schedule 28.09.2020
comment
Это идеальный способ прочитать тело запроса более одного раза. Теперь в вашем случае вы хотите прочитать requestBody (что, как я наблюдаю, не рекомендуется) в фильтре, чтобы выполнить какое-то действие, а затем перейти к другому фильтру (пружинные фильтры по умолчанию). Следовательно, вам нужно кэшировать requestBody при первом чтении, а затем передавать его дальнейшим фильтрам.   -  person Suman    schedule 28.09.2020
comment
Я чувствую, что это должно решить проблему, но тогда это определенно не рекомендуется, но, похоже, другого пути нет.   -  person Pankaj Sharma    schedule 28.09.2020
comment
Из документации HandlerInterceptor - As a basic guideline, fine-grained handler-related preprocessing tasks are candidates for HandlerInterceptor implementations, especially factored-out common handler code and authorization checks. On the other hand, a Filter is well-suited for request content and view content handling, like multipart forms and GZIP compression. This typically shows when one needs to map the filter to certain content types (e.g. images), or to all requests.   -  person Suman    schedule 28.09.2020
comment
Можешь поделиться ссылкой? так должен ли я использовать фильтры или Handler Interceptor для своей задачи?   -  person Pankaj Sharma    schedule 28.09.2020
comment
См. это - документы .spring.io/spring-framework/docs/current/javadoc-api/org/. Вы должны попытаться выполнить аутентификацию, взяв необходимые токены из заголовков и использовать HandlerInterceptor для проверки аутентификации. Но пока вы должны использовать только фильтры, потому что ваша авторизация зависит от тела запроса.   -  person Suman    schedule 28.09.2020


Ответы (3)


Вы можете создать собственный фильтр запроса, который будет проверять запрос:

public class MyFilter implements OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) {
        var user = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        // do stuff you need to do here
        
        filterChain.doFilter(request, response);
    }
}

а затем в вашем классе WebSecurityConfiguration зарегистрируйте такой фильтр

public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterAfter(new MyFilter(), BasicAuthenticationFilter.class);
    }
}
person toucheqt    schedule 26.09.2020
comment
SecurityContextHolder.getContext().getAuthentication().getPrincipal() возвращает null, если мне это нравится, есть идеи? - person Pankaj Sharma; 27.09.2020

Вы можете расширить HandlerInterceptorAdapter и выполнять свои пользовательские операции/фильтры поверх запроса, переопределяя метод preHandle().

Псевдокод здесь:

@Component
public class SimpleInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // Handle your request here. In your case, authentication check should go here.
        return true;
    }
}

Добавьте SimpleInterceptor в реестр для перехвата запросов.

@Configuration
@EnableWebMvc
public class SimpleMvnConfigurer implements WebMvcConfigurer {

    @Autowired
    SimpleInterceptor simpleInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(simpleInterceptor);
    }
}

Вот и все!
РЕДАКТИРОВАТЬ 1: Чтобы отправить ответ от метода preHandle, следуйте приведенному ниже псевдокоду:

@Override                                                                                           
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
    // Handle your request here. AIn your case, authentication check should go here.                
    if (!isValidAuth()) {                                                                           
        // Populate the response here.                                                              
        try {                                                                                       
            response.setStatus(401);                                                                
            response.getWriter().write("Authentication failed.");                                   
        } catch (IOException e) {                                                                   
            e.printStackTrace();                                                                    
        }                                                                                           
        return false;                                                                               
    }                                                                                               
    return true;                                                                                    
}                                                                                                   ```
person Suman    schedule 27.09.2020
comment
Как я могу отправить ответ об ошибке 401 Http, если аутентификация, которую я выполняю в preHandle, не удалась? - person Pankaj Sharma; 27.09.2020
comment
Обновил ответ. Пожалуйста, проверьте. - person Suman; 27.09.2020
comment
Проблема в том, что я не могу прочитать тело запроса внутри этого. Поскольку мне нужно проверить один из параметров внутри тела запроса, перейдите по этой ссылке..stackoverflow.com/questions/21193380/. - person Pankaj Sharma; 27.09.2020
comment
Как отправляется ваша аутентификация? В теле запроса? Я надеялся, что обычно токены аутентификации отправляются через заголовки. - person Suman; 27.09.2020
comment
да, я получаю доступ к аутентифицированному пользователю через. Строка user=SecurityContextHolder.getContext().getAuthentication().getName(), но мне нужно проверить один из параметров тела сообщения с этим пользователем. - person Pankaj Sharma; 27.09.2020
comment
Я также пробовал использовать фильтры и хотел сделать то же самое. Я получил доступ к телу в фильтре с помощью ContentCachingRequestWrapper, но проблема заключается в отправке ошибки в этом. Когда я это делаю, он говорит, что ответ уже передан - person Pankaj Sharma; 27.09.2020
comment
Я запутался, где мне это делать, также пытался использовать фильтры в цепочке фильтров безопасности spring, но я продолжаю получать анонимный пользователь или ноль в SecurityContextHolder.getContext().getAuthentication().getName() . Например, обратитесь к ответу toucheqt - person Pankaj Sharma; 27.09.2020
comment
Можете ли вы поделиться кодом о том, как вы это делаете? Потому что фильтр - это правильный способ решить вашу проблему. - person Suman; 27.09.2020
comment
Отредактированный вопрос - person Pankaj Sharma; 27.09.2020

Вы можете попробовать это с помощью фильтра.

public class SimpleFilter implements Filter {

    private void throwUnauthorized(ServletResponse res) throws IOException {
        HttpServletResponse response = (HttpServletResponse) res;
        response.reset();
        response.setHeader("Content-Type", "application/json;charset=UTF-8");
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;

        if (!isValidAuth(request)) {
            throwUnauthorized(res);
        }
        chain.doFilter(req, res);

    }

    private boolean isValidAuth(HttpServletRequest request) {
        // YOUR LOGIC GOES HERE.
        return false;
    }

    @Override
    public void destroy() {
    }

    @Override
    public void init(FilterConfig arg0) {
    }

}

Зарегистрируйте фильтр с помощью FilterRegistrationBean.

@Bean                                                                                      
public FilterRegistrationBean<SimpleFilter> simpleFilter() {                               
    FilterRegistrationBean<SimpleFilter> registrationBean = new FilterRegistrationBean<>();
    registrationBean.setFilter(new SimpleFilter());                                        
                                                                                           
    return registrationBean;                                                               
}                                                                                          

Дайте мне знать, если это работает.

person Suman    schedule 27.09.2020
comment
мой класс расширяет OncePerRequestFilter в рассматриваемом редактировании, и я переопределил метод doFilterInternal. это имеет значение, я имею в виду, отличается ли он от класса реализации фильтра? - person Pankaj Sharma; 28.09.2020
comment
Проблема в том, что я не могу извлечь тело запроса перед вызовом do filter и получаю сообщение об ошибке: ответ уже был зафиксирован - person Pankaj Sharma; 28.09.2020