【问题标题】:Paypal IPN verification failed because character encodingPaypal IPN 验证失败,因为字符编码
【发布时间】:2014-09-30 20:24:48
【问题描述】:

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

主要问题是带有 UTF-8 字符的 IPN,我猜这导致验证失败。

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

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

charset=UTF-8

address_name=阿德里安

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 的响应,不是吗?

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

【问题讨论】:

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


    【解决方案1】:

    好吧,我实际上不知道为什么 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 链之前:

    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);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2015-05-27
      • 2015-06-08
      • 2012-10-18
      • 1970-01-01
      • 2016-04-26
      • 2016-08-17
      • 2012-06-24
      • 2016-10-15
      • 2023-03-30
      相关资源
      最近更新 更多