據說這兩天騰訊的服務器出了問題,認證的時候報這樣的錯:
- Java 代碼複製內容到剪貼板
- oauth.signpost.exception.OAuthCommunicationException: Communication with the service provider failed: Not trusted server certificate
- Caused by: javax.net.ssl.SSLPeerUnverifiedException: No peer certificate
- oauth.signpost.exception.OAuthCommunicationException: Communication with the service provider failed: Nopeer certificate
這是因爲Https認證被截獲導致,Client認爲安全失效,很久之前就出現了這個問題了,那時候在WebView上加上下面的代碼就可以解決了
- Java 代碼複製內容到剪貼板
- public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
- handler.proceed();
- }
沒想到又出現這個問題,於是一翻研究,在stackoverflow.com上找到答案,寫了一個自定義類繼承SSLSocketFactory,
- Java 代碼複製內容到剪貼板
- public class SSLSocketFactoryEx extends SSLSocketFactory {
- SSLContext sslContext = SSLContext.getInstance("TLS");
- public SSLSocketFactoryEx(KeyStore truststore)
- throws NoSuchAlgorithmException, KeyManagementException,
- KeyStoreException, UnrecoverableKeyException {
- super(truststore);
- TrustManager tm = new X509TrustManager() {
- public java.security.cert.X509Certificate[] getAcceptedIssuers() {
- return null;
- }
- @Override
- public void checkClientTrusted(
- java.security.cert.X509Certificate[] chain, String authType)
- throws java.security.cert.CertificateException {
- }
- @Override
- public void checkServerTrusted(
- java.security.cert.X509Certificate[] chain, String authType)
- throws java.security.cert.CertificateException {
- }
- };
- sslContext.init(null, new TrustManager[] { tm }, null);
- }
- @Override
- public Socket createSocket(Socket socket, String host, int port,
- boolean autoClose) throws IOException, UnknownHostException {
- return sslContext.getSocketFactory().createSocket(socket, host, port,
- autoClose);
- }
- @Override
- public Socket createSocket() throws IOException {
- return sslContext.getSocketFactory().createSocket();
- }
- }
調用方法,只要用認證返回的HttpCilent即可。代碼:
- Java 代碼複製內容到剪貼板
- public HttpClient getNewHttpClient() {
- try {
- KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
- trustStore.load(null, null);
- SSLSocketFactory sf = new SSLSocketFactoryEx(trustStore);
- sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
- HttpParams params = new BasicHttpParams();
- HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
- HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
- SchemeRegistry registry = new SchemeRegistry();
- registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
- registry.register(new Scheme("https", sf, 443));
- ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
- return new DefaultHttpClient(ccm, params);
- } catch (Exception e) {
- return new DefaultHttpClient();
- }
- }
這樣就解決了問題,有網友說把騰訊認證的地址https去掉改成http,那是不可取的做法。
我已經把代碼集成到signpost中,如果有需要的同學可自行下載,有不明白或者不好的地方給我評論留言。
源碼下載:
下載文件
2011-12-11日更新了oauth-signpost-1211.jar包,把原來打jar包時也一起打的commons-codec.jar去掉了。
好吧,把源碼也傳上來了,供大家下載:
不過還是推薦使用OAuth2.0,方便很多。而且新浪也不推薦使用OAuth1.0了。