Android WebView - невозможно снова установить базовую аутентификацию после первого раза - PullRequest
2 голосов
/ 27 ноября 2011

Запуск 3.1 (Сота) на Galaxy Tab 10.1

Несмотря на несколько разных методов, мне не удалось сбросить базовое имя пользователя и пароль для веб-просмотра. Единственный способ сбросить эти значения - перезапустить приложение. Я искал вокруг и до сих пор не нашел решения и даже копался в источнике Android.

Этот код взят из действия, которое создается каждый раз, когда я хочу отобразить веб-страницу, требующую базовой аутентификации. Некоторые части не должны иметь никакого эффекта, но были испытаны из-за разочарования. Даже когда я выхожу из этого действия (которое затем уничтожается) и повторно запускает его с намерением из моего основного действия, базовая информация об аутентификации остается, и onReceivedHttpAuthRequest в WebViewClient никогда не выполняется снова.

@Override
public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.base_simple_v01);

    findViewById(R.id.lyt_bsv01_layout).setBackgroundColor(0xFF000000);

    baseContainer = (ViewGroup) findViewById(R.id.lyt_bsv01_baseContainer);

    statusProgressBar = (ProgressBar) findViewById(R.id.lyt_bsv01_statusProgress);
    resultNotificationTextView = (TextView) findViewById(R.id.lyt_bsv01_resultNotification);

    // -- Attempt to prevent and clear WebView cookies
    CookieSyncManager.createInstance(this); 
    CookieManager cookieManager = CookieManager.getInstance();
    cookieManager.removeAllCookie();
    cookieManager.removeSessionCookie();
    cookieManager.setAcceptCookie(false);

    // -- Attempt to clear WebViewDatabase
    WebViewDatabase.getInstance(this).clearHttpAuthUsernamePassword();
    WebViewDatabase.getInstance(this).clearUsernamePassword();
    WebViewDatabase.getInstance(this).clearFormData();

    // -- Brute force attempt to clear WebViewDatabase - didn't work
    //deleteDatabase("webview.db");
    //deleteDatabase("webviewCache.db");

    LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    networkWebView = (WebView)vi.inflate(R.layout.social_connect, baseContainer, false);
    // -- Removes white flickering in Honeycomb WebView page loading.
    networkWebView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    networkWebView.getSettings().setJavaScriptEnabled(true);
    networkWebView.getSettings().setSavePassword(false);
    networkWebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
    networkWebView.clearSslPreferences();

    networkWebView.setWebViewClient(mLocalDataRequester.endorseBackendAuthWebViewClient(
            new BackendAuthWebViewClient() {
                    @Override 
                    public void onReceivedHttpAuthRequest (WebView view, HttpAuthHandler handler, String host, String realm) { 
                        Toast.makeText(getApplicationContext(), "AUTH REQUESTED", Toast.LENGTH_SHORT).show();
                        super.onReceivedHttpAuthRequest (view, handler, host, realm);
                    } 

                    @Override
                    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
                        Toast.makeText(getApplicationContext(), "SSL ERROR", Toast.LENGTH_SHORT).show();
                        super.onReceivedSslError(view, handler, error);
                    }

                    @Override
                    public void onPageStarted(WebView view, String url, Bitmap favicon) {
                        statusProgressBar.setVisibility(View.VISIBLE);
                        networkWebView.setVisibility(View.INVISIBLE);
                    }

                    @Override
                    public void onPageFinished(WebView view, String url) {
                        statusProgressBar.setVisibility(View.INVISIBLE);
                        networkWebView.setVisibility(View.VISIBLE);
                    }
                })
            );

    baseContainer.addView(networkWebView);
    networkWebView.setVisibility(View.INVISIBLE);

    networkWebView.setBackgroundColor(0x00000000);
    clearWebView();

}

private void clearWebView() {
    networkWebView.loadData("", "text/html", "utf-8");
    //networkWebView.clearView();
    networkWebView.clearCache(false);
    networkWebView.clearCache(true);

    networkWebView.clearFormData();
    networkWebView.clearHistory();
    networkWebView.clearCache(true);
    networkWebView.clearMatches();


    networkWebView.freeMemory();

}

@Override
public void onResume() {
    super.onResume();
    networkWebView.loadUrl(mBackendNetworkConnectUrl);
    WebViewDatabase.getInstance(this).clearHttpAuthUsernamePassword();

}

@Override
public void onDestroy() {
    super.onDestroy();
    Toast.makeText(getApplicationContext(), "Destruction", Toast.LENGTH_SHORT).show();
    networkWebView.destroy();
}

Это подкласс WebViewClient, который инициализируется базовыми учетными данными аутентификации. Я подтвердил, что имя пользователя и пароль меняются, когда должна произойти аутентификация.

public class BackendAuthWebViewClient extends WebViewClient {

    private AuthenticateData mAuthenticateData = null;

    public BackendAuthWebViewClient() {
    }

    public BackendAuthWebViewClient(AuthenticateData authenticateData) {
        this.mAuthenticateData = authenticateData;
    }

    @Override 
    public void onReceivedHttpAuthRequest (WebView view, HttpAuthHandler handler, String host, String realm){ 
        handler.proceed(mAuthenticateData.mUserId, mAuthenticateData.mUserPassword);
    } 

    @Override
    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
        handler.proceed();
    }

    public void setAuthenticatedData(AuthenticateData authenticateData) {
        this.mAuthenticateData = authenticateData;
    }

}

Я пробовал следующее безрезультатно:

Android WebView - сброс HTTP-сессии

Очистка сеанса пользователя Facebook в Webview

Удалить данные в браузере

Сделать Android WebView не хранить куки или пароли

Проблема с файлом Android WebView

Это интересно, но необходимость грубой силы разочаровывает. Хотя попробую потом.

РЕДАКТИРОВАТЬ: Не работает.

Android Webview - полностью очистить кэш

Ответы [ 7 ]

1 голос
1 голос
/ 14 февраля 2012

Я почти уверен, что это ошибка в WebViewDatabase.getInstance(this).clearHttpAuthUsernamePassword();, потому что

deleteDatabase("webview.db");

помогает мне.

0 голосов
/ 12 января 2017

Я использовал многопроцессорность для решения этой проблемы.

Так как WebView в вашем Деятельности / Фрагменте должен обрабатывать Http Basic Authentication, будет инициирован onRectainedHttpAuthRequest ().Создание диалога для пользователя для ввода информации для входа.

onRecievedHttpAuthRequest(final WebView view, final HttpAuthHandler handler, final String host, String realm){
    final Dialog dialog = new Dialog(context);
    dialog.setContentView(R.layout.dialog_layout);
    dialog.findViewById(R.id.confirmBtn).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            final String account = ((EditText)dialog.findViewById(R.id.accountET)).getText().toString();
            final String pwd = ((EditText)dialog.findViewById(R.id.pwdET)).getText().toString();
            serviceIntent = new Intent(context, SSOAuthService.class);
            serviceIntent.putExtra("url", authUrl);
            serviceIntent.putExtra("account", account);
            serviceIntent.putExtra("pwd", pwd);
            context.startService(serviceIntent);

            dialog.dismiss();
        }
    });
    dialog.show();
}

Запустите службу, содержащую веб-представление для обработки базовой аутентификации http, и передайте учетную запись и pwd get из диалогового окна, приведенного выше.

public class AuthService extends Service {
    private String account;
    private String pwd;
    private String url;
    private String webView;
    private boolean isProcess = false;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        url = (String) intent.getExtras().get("url");
        account = (String) intent.getExtras().get("account");
        pwd = (String) intent.getExtras().get("pwd");
        webView = new WebView(this);
        webView.getSettings().setJavaScriptEnabled(true);
        webView.setWebViewClient(new WebViewClient() {

            @Override
            public void onPageFinished(WebView view, String url) {
                //todo Do whatever u want to do.
                closeServiceAndProcess();
            }

            @Override
            public void onReceivedHttpAuthRequest(final WebView view, final HttpAuthHandler handler, final String host, String realm) {
                if (!isProcess) {
                    isProcess = true;
                    handler.proceed(account, pwd);
                } else {
                    isProcess = false;
                    closeServiceAndProcess();
                }
            }
        });
        webView.loadUrl(url);

        return Service.START_REDELIVER_INTENT;
    }

    private void closeServiceAndProcess() {
        stopSelf();
        android.os.Process.killProcess(android.os.Process.myPid());
    }
}

В качестве полной базовой аутентификации http в AuthService,убить процесс, которым живет AuthService.И базовая аутентификация http может быть сброшена.

0 голосов
/ 29 марта 2016

У меня тоже была эта проблема.И нашел решение, надеюсь, это поможет вам.Прежде всего, метод onReceivedHttpAuthRequest() вызывается только один раз в приложении, за исключением использования файлов cookie.

Я должен был написать метод:

public void syncCookie(Context context, String url) {
        HttpClient httpClient = HttpClientContext.getInstance();
        Cookie[] cookies = httpClient.getState().getCookies();
        Cookie sessionCookie = null;
        if (cookies.length > 0) {
            sessionCookie = cookies[cookies.length - 1];
        }

        CookieManager cookieManager = CookieManager.getInstance();
        if (sessionCookie != null) {

            String cookieString = sessionCookie.getName() + "="
                    + sessionCookie.getValue() + ";domain="
                    + sessionCookie.getDomain();
            CookieSyncManager cookieSyncManager = CookieSyncManager.createInstance(context);

            cookieSyncManager.startSync();
            cookieManager.setCookie(url, cookieString);
            CookieSyncManager.getInstance().sync();
        }
    }

использовать так:

WebView webView =  ...;
  webView.getSettings().setJavaScriptEnabled(true);
  syncCookie(this,url);
  webView.loadUri(url);
  webView.setWebViewClient();
0 голосов
/ 09 сентября 2013

Оказалось, здесь есть две потенциальные проблемы.

Один из них, WebViewDatabase.clearHttpAuthUsernamePassword(), кажется, работает неправильно на некоторых устройствах / версиях Android, так что вызов WebView.getHttpAuthUsernamePassword() все еще возвращает сохраненный пароль после очистки базы данных.

Эту проблему можно решить, самостоятельно реализовав эти методы.

Вторая проблема заключается в том, что данные аутентификации также, похоже, хранятся в памяти, что в принципе хорошо, потому что WebView не должен запрашивать базу данных для каждого последующего HTTP-запроса. Однако этот кеш, похоже, используется всеми веб-приложениями, и нет очевидного способа его очистки. Оказывается, однако, что WebView, созданные с privateBrowsing = true, совместно используют другой кеш, который также ведет себя немного по-другому: после того, как последний частный просмотр WebView был разрушен, этот кеш, кажется, полностью очищен, и следующий запрос фактически сработает onReceivedHttpAuthRequest.

Ниже приведен полный рабочий пример этих двух обходных путей. Если вам приходится иметь дело с несколькими WebView, это может стать более сложным, потому что вам нужно обязательно уничтожить их все, прежде чем воссоздать их.

public class HttpAuthTestActivity extends Activity {

    ViewGroup webViewContainer;
    Button logoutButton;
    Button reloadButton;
    WebView webView;
    AuthStoreInterface authStore;

    public interface AuthStoreInterface {
        public void clear();
        public void setHttpAuthUsernamePassword(String host, String realm, String username, String password);
        public Pair<String, String> getHttpAuthUsernamePassword(String host, String realm);
    }

    //if you want to make the auth store persistent, you have implement a persistent version of this interface
    public class MemoryAuthStore implements AuthStoreInterface {
        Map<Pair<String, String>, Pair<String, String>> credentials;

        public MemoryAuthStore() {
            credentials = new HashMap<Pair<String, String>, Pair<String, String>>();
        }

        public void clear() {
            credentials.clear();
        }

        public void setHttpAuthUsernamePassword(String host, String realm, String username, String password) {
            credentials.put(new Pair<String, String>(host, realm), new Pair<String, String>(username, password));
        }

        public Pair<String, String> getHttpAuthUsernamePassword(String host, String realm) {
            return credentials.get(new Pair<String, String>(host, realm));
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        authStore = new MemoryAuthStore();

        webViewContainer = (ViewGroup)findViewById(R.id.webview_container);
        logoutButton = (Button)findViewById(R.id.logout_button);
        reloadButton = (Button)findViewById(R.id.reload_button);

        createWebView();

        logoutButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                authStore.clear();
                destroyWebView();
                createWebView();
            }
        });

        reloadButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                webView.reload();
            }
        });
    }

    @Override
    protected void onDestroy() {
        webView.destroy();
        super.onDestroy();
    }

    private void destroyWebView() {
        webView.destroy();
        webViewContainer.removeView(webView);
    }

    private void createWebView() {
        //this is the important line: if you use this ctor with privateBrowsing: true, the internal auth cache will
        //acutally be deleted in WebView.destroy, if there is no other privateBrowsing enabled WebView left only
        webView = new WebView(this, null, android.R.attr.webViewStyle, true);
        webView.setWebViewClient(new WebViewClient() {

            @Override
            public void onReceivedHttpAuthRequest(final WebView view, final HttpAuthHandler handler, final String host, final String realm) {

                Pair<String, String> credentials = authStore.getHttpAuthUsernamePassword(host, realm);
                if (credentials != null && handler.useHttpAuthUsernamePassword()) {
                    handler.proceed(credentials.first, credentials.second);
                } else {
                    LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                    final View form = inflater.inflate(R.layout.http_auth_request, null);

                    new AlertDialog.Builder(HttpAuthTestActivity.this).setTitle(String.format("HttpAuthRequest (realm: %s, host %s)", realm, host))
                            .setView(form).setPositiveButton(android.R.string.ok, new AlertDialog.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            EditText usernameEdt = (EditText) form.findViewById(R.id.username);
                            EditText passwordEdt = (EditText) form.findViewById(R.id.password);
                            String u = usernameEdt.getText().toString();
                            String p = passwordEdt.getText().toString();
                            authStore.setHttpAuthUsernamePassword(host, realm, u, p);
                            handler.proceed(u, p);
                        }
                    }).setCancelable(true).setNegativeButton(android.R.string.cancel, new AlertDialog.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.cancel();
                        }
                    }).setOnCancelListener(new DialogInterface.OnCancelListener() {
                        public void onCancel(DialogInterface dialog) {
                            handler.cancel();
                        }
                    }).create().show();
                }
            }
        });

        webView.loadUrl("http://httpbin.org/basic-auth/test/test");
        webViewContainer.addView(webView);
    }
}
0 голосов
/ 14 сентября 2012

Я предлагаю вообще не вызывать setHttpAuthUsernamePassword ().

Скорее, используйте onReceivedHttpAuthRequest () только для динамической обработки запроса аутентификации каждый раз.

Это в сочетании с

WebViewDatabase.getInstance(getContext()).clearHttpAuthUsernamePassword();
WebViewDatabase.getInstance(getContext()).clearUsernamePassword();
WebViewDatabase.getInstance(getContext()).clearFormData();

вызывает загрузку, чтобы очистить устаревшие записи, и моя проблема с этим ушла.

0 голосов
/ 28 ноября 2011

Хотя это не решает проблему с исходной аутентификацией WebView сброса, я использую это в качестве обходного пути.Используя этот SO в качестве ссылки:

POST Android Webview

В этом решении используется запрос HttpClient (предпочтительно в другом потоке или AsyncTask, чтобы избежать ANR - приложение не отвечает) изатем загрузка этого ответа в WebView.Поскольку мне нужно взаимодействовать со ссылками на загруженной странице, мне нужно использовать loadDataWithBaseURL.

Для этого ответа я лицензирую весь код ниже под Apache License 2.0.

Код HttpClient - лучше всего использовать в другом потоке или AsyncTask.Переменные authenticateData, method, url и nameValuePairs должны быть определены или удалены.

public String send() {
    try {
        // -- Create client.
        HttpParams httpParameters = new BasicHttpParams();
        // Set the timeout in milliseconds until a connection is established.
        int timeoutConnection = 10000;
        HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
        // Set the default socket timeout (SO_TIMEOUT) 
        // in milliseconds which is the timeout for waiting for data.
        int timeoutSocket = 10000;
        HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);

        DefaultHttpClient httpClient = new DefaultHttpClient(httpParameters);
        HttpGet httpGet;
        HttpPost httpPost;
        HttpDelete httpDelete;
        HttpResponse httpResponse;

        String authHeader;
        if( authenticateData != null ) {
            // -- Set basic authentication in header.
            String base64EncodedCredentials = Base64.encodeToString(
                    (authenticateData.username + ":" + authenticateData.password).getBytes("US-ASCII"), Base64.URL_SAFE|Base64.NO_WRAP);
            authHeader = "Basic " + base64EncodedCredentials;
        } else {
            authHeader = null;
        }

        // -- Send to server.
        if( method == GET ) {
            httpGet = new HttpGet(url);
            if( authHeader != null ) {
                httpGet.setHeader("Authorization", authHeader);
            }
            httpResponse = httpClient.execute(httpGet);
        }
        else if( method == POST) {
            httpPost = new HttpPost(url);
            if( authHeader != null ) {
                httpPost.setHeader("Authorization", authHeader);
            }
            httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
            httpResponse = httpClient.execute(httpPost);
        }
        else if( method == DELETE) {
            httpDelete = new HttpDelete(url);
            httpDelete.setHeader("Content-Length", "0");
            if( authHeader != null ) {
                httpDelete.setHeader("Authorization", authHeader);
            }
            httpResponse = httpClient.execute(httpDelete);
        }
        else {
            return null;
        }

        // -- Method 1 for obtaining response.
        /*
        InputStream is = httpResponse.getEntity().getContent();
        // -- Convert response.
        Scanner scanner = new Scanner(is);
        // -- TODO: specify charset
        String response = scanner.useDelimiter("\\A").next();

        */

        // -- Method 2 for obtaining response.
        String response = new BasicResponseHandler().handleResponse(httpResponse);


        return response;

    }
    catch(SocketTimeoutException exception) {
        exception.printStackTrace();
    }
    catch(ConnectTimeoutException exception) {
        exception.printStackTrace();
    }
    catch(NoHttpResponseException exception) {
        exception.printStackTrace();
    }
    catch(UnknownHostException exception) {
        exception.printStackTrace();
    }
    catch(ClientProtocolException exception) {
        exception.printStackTrace();
    }
    catch(IOException exception) {
        exception.printStackTrace();
    }

    return null;

}

Код WebView - должен быть в действии, которое содержит WebView.

WebView webView = new WebView(Activity.this);
webView.loadDataWithBaseURL(url, response, "text/html", "utf-8", null);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...