簡體   English   中英

客戶端無法使用自簽名證書連接到REST API

[英]Client can't connect to REST API using self-signed certificate

我正在嘗試將我的Android客戶端連接到TOMCAT REST API。 只要使用HTTP,一切正常。 不幸的是,必須實施HTTPS。

在服務器端HTTPS實現服務器看起來正常之后(服務器正在使用自簽名證書。使用JAVA KEYTOOL創建)。

不幸的是,由於某些原因,我無法連接Android客戶端。

最初的錯誤是:“找不到證書路徑的信任錨”。 我嘗試使用Android Developer指南,但是使用“ AsyncTask”訪問.crt / cer文件時遇到問題。 因此,我決定暫時可以使用“ ALLOW_ALL_HOSTNAME_VERIFIER”。 HTTPS CLIENT類如下所示:

(注釋部分為HTTP版本)

import android.util.Base64;
import android.os.Build;
import android.annotation.TargetApi;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.SingleClientConnManager;

import android.os.AsyncTask;
import android.util.Log;

public class UrlUtil extends AsyncTask<String, Void, String> {

    @TargetApi(Build.VERSION_CODES.O_MR1)
    @Override
    protected String doInBackground(String... strings) {

        StringBuilder jsonResult = new StringBuilder();
        String message = null;

        try {
            //setup SSL
            HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
            DefaultHttpClient client = new DefaultHttpClient();
            SchemeRegistry registry = new SchemeRegistry();
            SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
            socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
            registry.register(new Scheme("https", socketFactory, 443));
            SingleClientConnManager mgr = new SingleClientConnManager(client.getParams(), registry);
            DefaultHttpClient httpClient = new DefaultHttpClient(mgr, client.getParams());
            // Set verifier
            HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);

            String cred = "xxxx:yyyy";
            String encoding = Base64.encodeToString(cred.getBytes(), Base64.DEFAULT);
            // Example send http request
            HttpPost httpPost = new HttpPost(strings[0]);
            httpPost.setHeader("Authorization", "Basic " + encoding);
            HttpResponse response = httpClient.execute(httpPost);
            InputStream is = response.getEntity().getContent(); //outputs an inputstream

            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            StringBuilder sb = new StringBuilder();
            String line = null;

            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }

            is.close();
            Log.d("httpstest",sb.toString());
            return sb.toString();

        } catch (IOException e) {  }
        return null;

//            try {
//                URL url = new URL(strings[0]);
//
//                Authenticator.setDefault(new Authenticator() {
//                    protected PasswordAuthentication getPasswordAuthentication() {
//                        return new PasswordAuthentication("user", "userPass".toCharArray());
//                    }
//                });
//                HttpURLConnection connection = (HttpURLConnection) new URL(url.toString()).openConnection();
//                connection.setUseCaches(false);
//                connection.connect();
//                InputStream inputStream = connection.getInputStream();
//                InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
//                BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
//                message = org.apache.commons.io.IOUtils.toString(bufferedReader);
//
//            } catch (MalformedURLException e) {
//                e.printStackTrace();
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//
//
//
//        } catch (Exception e) {  }
//
//        return message;
    }
}

錯誤信息:

07/09 18:27:29: Launching app
$ adb install-multiple -r -t -p org.pilat.eko_raporty20 C:\Users\Pilat\Desktop\AndroidStudioProjects\ekoraporty20\app\build\intermediates\split-apk\debug\slices\slice_9.apk 
Split APKs installed in 2 s 675 ms
$ adb shell am start -n "org.pilat.eko_raporty20/org.pilat.eko_raporty20.activity.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Client not ready yet..Waiting for process to come online
Connected to process 944 on device lenovo-lenovo_p2a42-ZY223TJMN2
Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
D/LenovoAppIconTheme: ExtraResources;cleanCachedIcon;clear cache..
W/ActivityThread: Application org.pilat.eko_raporty20 can be debugged on port 8100...
W/System: ClassLoader referenced unknown path: /data/app/org.pilat.eko_raporty20-1/lib/arm64
I/InstantRun: starting instant run server: is main process
I/Typeface: setThemeFont(): sThemeFontPath = ,fontPath = 
W/Typeface: setThemeFont(): FontPath Not Changed!
W/art: Before Android 4.1, method android.graphics.PorterDuffColorFilter android.support.graphics.drawable.VectorDrawableCompat.updateTintFilter(android.graphics.PorterDuffColorFilter, android.content.res.ColorStateList, android.graphics.PorterDuff$Mode) would have incorrectly overridden the package-private method in android.graphics.drawable.Drawable
V/BoostFramework: mAcquireFunc method = public int com.qualcomm.qti.Performance.perfLockAcquire(int,int[])
V/BoostFramework: mReleaseFunc method = public int com.qualcomm.qti.Performance.perfLockRelease()
    mAcquireTouchFunc method = public int com.qualcomm.qti.Performance.perfLockAcquireTouch(android.view.MotionEvent,android.util.DisplayMetrics,int,int[])
    mIOPStart method = public int com.qualcomm.qti.Performance.perfIOPrefetchStart(int,java.lang.String)
    mIOPStop method = public int com.qualcomm.qti.Performance.perfIOPrefetchStop()
V/BoostFramework: BoostFramework() : mPerf = com.qualcomm.qti.Performance@e5acceb
    BoostFramework() : mPerf = com.qualcomm.qti.Performance@fdb0a48
D/NetworkSecurityConfig: No Network Security Config specified, using platform default
I/DpmTcmClient: RegisterTcmMonitor from: org.apache.http.impl.conn.TcmIdleTimerMonitor
I/System.out: [socket][0] connection /"ip":"port";LocalPort=-1(0)
I/System.out: [socket][/100.82.169.168:35907] connected
I/System.out: close [socket][/100.82.169.168:35907]
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
    Process: org.pilat.eko_raporty20, PID: 944
    java.lang.RuntimeException: Unable to start activity ComponentInfo{org.pilat.eko_raporty20/org.pilat.eko_raporty20.activity.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.String.toString()' on a null object reference
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2659)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2720)
        at android.app.ActivityThread.-wrap12(ActivityThread.java)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1466)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6111)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.String.toString()' on a null object reference
        at org.pilat.eko_raporty20.activity.MainActivity.onCreate(MainActivity.java:126)
        at android.app.Activity.performCreate(Activity.java:6734)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2612)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2720) 
        at android.app.ActivityThread.-wrap12(ActivityThread.java) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1466) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:154) 
        at android.app.ActivityThread.main(ActivityThread.java:6111) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755) 
Application terminated.
  1. 為什么我沒有從服務器獲取數據?

    (我不明白:I / System.out:[socket] [0]連接/“ ip”:“端口”; LocalPort = -1(0))

  2. 如何正確地做呢?

    如果沒有其他選擇可以接受所有證書,則首選選項是使其使用自簽名證書來工作。

提前致謝 :-)

經過兩天的互聯網搜索並嘗試了許多選項的結果是使用Android Developer選項: https : //developer.android.com/training/articles/security-ssl比起添加證書文件,您將遇到問題。 Android將看不到它。 您可以通過將新的構造函數添加到AsyncTask類來添加證書。 它看起來應該像這樣:

    Public class UrlUtil extends AsyncTask<String, String, String> {

        private Context context;

        public UrlUtil (Context myContext) {
            this.context = myContext;
        }

        public UrlUtil () {};

        @TargetApi(Build.VERSION_CODES.O_MR1)
        @Override
        protected String doInBackground(String... params) {...}

...}

您可以像這樣執行AsyncTask:

new UrlUtil(this).execute("https://myserver:myport/restofpath").get()

其中“ this”是ACTIVITY上下文。

證書文件應放在ASSETS文件夾中。 如果您的項目中沒有一個,最簡單的添加方法是右鍵單擊項目的“新建” /“文件夾” /“資產文件夾”。 要將文件添加到“資產文件夾”,您不能簡單地使用“拖放”。 您必須在OS資源管理器中找到文件夾並將其放入該文件夾中。

我希望您會發現它有用:-)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM