Paypal IPN验证失败,因为字符编码

时间:2014-08-07 14:29:38

标签: spring paypal spring-security paypal-ipn spring-boot

我的Spring启动服务器中的Paypal IPN验证存在问题。我不确定问题出在哪里,如果在服务器端或另一方面,这是Paypal的错。我已经在我的个人资料页面中选择了UTF-8作为参与。

主要问题是IPN使用UTF-8字符,这使我的验证失败。

如果我的Spring和Spring安全服务器中没有CharacterEncodingFilter,则IPN验证工作正常。但是其他东西(例如表格)没有用UTF-8编码显示,所以这是一个不可接受的解决方案。

当我打印IPN(没有CharacterEnconding,因此付款得到已验证)我得到的响应(除其他外)时,我发现很奇怪:

  

charset = UTF-8

     

ADDRESS_NAME =Adrián

     

PAYMENT_STATUS =完成

所以Paypal说IPN是UTF-8,但那是我没有收到的。

服务器的编码工作正常,在Spring Security过滤器链之前添加了CharacterEncodingFilter:

@Order(1)
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
    @Override
    protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
        FilterRegistration.Dynamic characterEncodingFilter = servletContext
                .addFilter("characterEncodingFilter", new CharacterEncodingFilter());
        characterEncodingFilter.setInitParameter("encoding", "UTF-8");
        characterEncodingFilter.setInitParameter("forceEncoding", "false");
        characterEncodingFilter.addMappingForUrlPatterns(null, false, "/*");

        insertFilters(servletContext, new MultipartFilter());   
    }
}

现在,Paypal的IPN打印节目编程很好:

  

的charset = UTF-8

     

如first_name =阿德里安

     

PAYMENT_STATUS =完成

但Paypal的回复是无效的。

这是我的控制器处理Paypal IPN的帖子:

@RequestMapping(value = "paypalok", method = RequestMethod.POST)
    public void processIPN(HttpServletRequest request) {

        String PAY_PAL_DEBUG = "https://www.sandbox.paypal.com/cgi-bin/webscr";
        String CONTENT_TYPE = "Content-Type";
        String MIME_APP_URLENC = "application/x-www-form-urlencoded";
        String PARAM_NAME_CMD = "cmd";
        String PARAM_VAL_CMD = "_notify-validate";
        String PAYMENT_COMPLETED = "Completed";
        String paymentStatus = "";

        // Create client for Http communication
        HttpClient httpClient = HttpClientBuilder.create().build();

        // Request configuration can be overridden at the request level.
        // They will take precedence over the one set at the client level.
        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(40000).setConnectTimeout(40000)
                .setConnectionRequestTimeout(40000).build();

        HttpPost httppost = new HttpPost(PAY_PAL_DEBUG);
        httppost.setHeader(CONTENT_TYPE, MIME_APP_URLENC);

        try {
            Map<String, String> params = new HashMap<String, String>();
            List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
            nameValuePairs.add(new BasicNameValuePair(PARAM_NAME_CMD, PARAM_VAL_CMD));

            // Process the parameters
            Enumeration<String> names = request.getParameterNames();
            while (names.hasMoreElements()) {
//              String param = names.nextElement();
//              String value = request.getParameter(param);

                String param = new String (names.nextElement().getBytes ("iso-8859-1"), "UTF-8");
                String value = new String (request.getParameter(param).getBytes ("iso-8859-1"), "UTF-8");

                nameValuePairs.add(new BasicNameValuePair(param, value));
                params.put(param, value);
                System.out.println(param + "=" + value);
                // Get the payment status
                if (param.equalsIgnoreCase("payment_status")) paymentStatus = value;
            }

            httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));

            if (verifyResponse(httpClient.execute(httppost))) {
                // if (paymentStatus.equalsIgnoreCase(PAYMENT_COMPLETED)) do...
                return "elovendo/pricing/paymentOk";
            }

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return "redirect:/error";
        } catch (ClientProtocolException e) {
            e.printStackTrace();
            return "redirect:/error";
        } catch (IOException e) {
            e.printStackTrace();
            return "redirect:/error";
        }
    }

    private boolean verifyResponse(HttpResponse response) throws IllegalStateException, IOException {

        String RESP_VERIFIED = "VERIFIED";

        InputStream is = response.getEntity().getContent();
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        String responseText = reader.readLine();
        is.close();

        System.out.println("RESPONSE : " + responseText);

        return responseText.equals(RESP_VERIFIED);

    }

我用uri编码:

@Configuration
public class WebAppConfiguration {

    /** HTTPS and Paging error **/
    @Bean
    public EmbeddedServletContainerFactory servletContainer() {
        TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
        factory.setUriEncoding("UTF-8");
    }
}

恢复,如果我发送字符UTF-8编码的Paypal验证失败,即使它不应该错误编码。如果我发送错误编码,Paypal的回复就可以了。

我无法使用CharacterEncodingFilter发送IPN的响应错误编码,不是吗?

我真的不知道发生了什么事。 谢谢!

1 个答案:

答案 0 :(得分:0)

好吧,我实际上并不知道为什么Paypal发送错误编码的数据,但是一个简单的解决方法就是管理它。

像这样重写CharacterEncodingFilter:

public class CharacterEncodingFilter extends org.springframework.web.filter.CharacterEncodingFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        if (request != null && !request.getRequestURI().contains("paypalcheck")) {
            super.doFilterInternal(request, response, filterChain);
        }
        else {
            filterChain.doFilter(request, response);
        }

    }
}

引用侦听Paypal的IPN并告诉过滤器不对数据进行编码的控制器URL。

另外,确保过滤器在Spring Security chain之前:

public class SecurityConf extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        filter.setEncoding("UTF-8");
        filter.setForceEncoding(true);
        http.addFilterBefore(filter, WebAsyncManagerIntegrationFilter.class);
    }
}