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

89

У меня есть сервер, который отправляет моему приложению Android файл cookie сеанса, который будет использоваться для аутентифицированной связи. Я пытаюсь загрузить WebView с URL-адресом, указывающим на тот же сервер, и пытаюсь передать файл cookie сеанса для аутентификации. Я замечаю, что он работает с перебоями, но не знаю почему. Я использую один и тот же файл cookie сеанса для выполнения других вызовов на моем сервере, и они никогда не завершают проверку подлинности. Я наблюдаю эту проблему только при попытке загрузить URL-адрес в WebView, и это происходит не каждый раз. Очень неприятно.

Ниже приведен код, который я использую для этого. Любая помощь будет оценена.

String myUrl = ""http://mydomain.com/"; 
CookieSyncManager.createInstance(this); 
CookieManager cookieManager = CookieManager.getInstance(); 
Cookie sessionCookie =  getCookie(); 
if(sessionCookie != null){ 
    String cookieString = sessionCookie.getName() +"="+sessionCookie.getValue()+"; domain="+sessionCookie.getDomain(); 
    cookieManager.setCookie(myUrl, cookieString); 
    CookieSyncManager.getInstance().sync(); 
} 

WebView webView = (WebView) findViewById(R.id.webview); 
webView.getSettings().setBuiltInZoomControls(true); 
webView.getSettings().setJavaScriptEnabled(true); 
webView.setWebViewClient(new MyWebViewClient()); 
webView.loadUrl(myUrl);
наннерпус
источник
обратитесь к этому вопросу stackoverflow.com/questions/2566485/…
neeraj t

Ответы:

55

Спасибо, justingrammens ! Это сработало для меня, мне удалось поделиться файлом cookie в моих запросах DefaultHttpClient и активности WebView:

//------- Native request activity
private DefaultHttpClient httpClient;
public static Cookie cookie = null;

//After Login
List<Cookie> cookies = httpClient.getCookieStore().getCookies();
for (int i = 0; i < cookies.size(); i++) {
    cookie = cookies.get(i);
}

//------- Web Browser activity
Cookie sessionCookie = myapp.cookie;
CookieSyncManager.createInstance(this);
CookieManager cookieManager = CookieManager.getInstance();
if (sessionCookie != null) {
    cookieManager.removeSessionCookie();
    String cookieString = sessionCookie.getName() + "=" + sessionCookie.getValue() + "; domain=" + sessionCookie.getDomain();
    cookieManager.setCookie(myapp.domain, cookieString);
    CookieSyncManager.getInstance().sync();
}   
k7k0
источник
Это отлично сработало для меня. Я создал свой URL-адрес cookie следующим образом: String url = (cookie.isSecure ()? "Https": "http") + ": //" + cookie.getDomain () + cookie.getPath ();
Heath Borders
спасибо за пост ... это помогло мне реализовать выход из твиттера для моего приложения ...;)
rahul
Можете ли
ключевое слово: String cookieString = sessionCookie.getName () + "=" + sessionCookie.getValue () + "; domain =" + sessionCookie.getDomain (); cookieManager.setCookie (myapp.domain, cookieString);
Зенничимаро
1
CookieSyncManager устарел :(
Миша Акопов
18

Спасибо Android за испорченное воскресенье. . . Вот что исправило мои приложения (после того, как вы запустите свой веб-просмотр)

if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ) {

  CookieManager cookieManager = CookieManager.getInstance();

  cookieManager.setAcceptThirdPartyCookies( webView, true );

}

Я должен сказать, что приведенные выше ответы, вероятно, сработают, но в моей ситуации, когда Android перешел на версию 5 +, мои приложения javascript для android webview умерли.

Джоди Джейкобус Джирс
источник
1
Ой ! Ты только что спас мне день!
Ле Мин
14

Решение: Webview CookieSyncManager

CookieSyncManager cookieSyncManager = CookieSyncManager.createInstance(mWebView.getContext());
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
cookieManager.removeSessionCookie();
cookieManager.setCookie("http://xx.example.com","mid="+MySession.GetSession().sessionId+" ; Domain=.example.com");
cookieSyncManager.sync();

String cookie = cookieManager.getCookie("http://xx.example.com");

Log.d(LOGTAG, "cookie ------>"+cookie);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setWebViewClient(new TuWebViewClient());
mWebView.loadUrl("http://xx.example.com");
Санкет
источник
от чего ты получаешь cookie?, я получаю только: PHPSESSID=ljfakdjfklasdfaj!, этого достаточно?
Франсиско Корралес Моралес
6
Что здесь MySession?
User3
3

Я бы сохранил этот файл cookie сеанса в качестве предпочтения и принудительно повторно заселил им диспетчер файлов cookie. Похоже, что cookie сеанса не переживает перезапуск активности

Bostone
источник
Я должен добавить, что мое приложение выполняет много других вызовов, не связанных с WebView, на моем сервере, которые никогда не завершаются аутентификацией. Только когда я пытаюсь загрузить URL-адрес в WebView, я замечаю эту проблему. "Cookie sessionCookie = getCookie ();" извлекает из БД приложения файл cookie сеанса, который я использую для всех сообщений с моим сервером.
nannerpus
Что ж, если вы используете HttpClient для этого, у него есть собственное хранилище файлов cookie, поэтому, если вы сохраните единственный экземпляр клиента, ваш файл cookie сохранится, но он может не иметь ничего общего с тем, который используется вашим веб-представлением
Bostone,
Если я правильно вас понял, вы говорите, что CookieManager, возвращенный CookieManager.getInstance (); повлияет на файлы cookie, используемые экземплярами HttpClient, которые не используются WebView. Если это правда, знаете ли вы, как я могу явно передать файлы cookie в WebViews? Кроме того, глядя на документацию CookieManager, возможно, не вызывая "cookieManager.setAcceptCookie (true)", это вызывает у меня проблемы? Спасибо за помощь, очень признателен.
nannerpus 03
3

Я потратил большую половину из трех часов, работая над очень похожей проблемой. В моем случае у меня было несколько вызовов, которые я сделал веб-сервису, используяDefaulHttpClient а затем я хотел установить сеанс и все другие соответствующие файлы cookie в моем WebView.

Я не знаю, решит ли это вашу проблему, поскольку я не знаю, что getCookie()делает ваш метод, но в моем случае мне действительно пришлось позвонить.

cookieManager.removeSessionCookie();

Сначала удалите файл cookie сеанса, а затем снова добавьте его. Я обнаружил, что когда я пытался установить JSESSIONIDфайл cookie, не удаляя его предварительно, значение, которое я хотел установить, не сохранялось. Не уверен, что это поможет вам в конкретной проблеме, но подумал, что поделюсь тем, что нашел.

Джастин
источник
почему бы и нет CookieManager.getInstance().removeAllCookie ();?
Франсиско Корралес Моралес
2

После некоторого времени исследований я собрал несколько фрагментов, которые помогли мне прийти к этому решению. После того, как CookieSyncManager устарел, это может быть лучшим способом установить конкретный файл cookie для веб-просмотра в Kotlin в настоящее время, вам больше ничего не понадобится.

private fun setCookie(){
    val webView = WebView(this) // this = context
    val cookieManager = CookieManager.getInstance()
    cookieManager.acceptCookie()

    val domain = "https://www.yourdomain.com/"

    webView.webViewClient = WebViewClient()
    webView.settings.javaScriptEnabled = true

    cookieManager.setCookie(domain,"$cookieKey=$cookieValue")
    cookieManager.setAcceptThirdPartyCookies(webView, true)

    webView.loadUrl(domain)
}
Сэмюэл Луис
источник
1

У меня здесь другой подход, чем у других людей, и это подход, который гарантированно работает без использования CookieSyncManager (где вы находитесь во власти семантики типа «Обратите внимание, что даже sync () происходит асинхронно»).

По сути, мы переходим к правильному домену, а затем выполняем javascript из контекста страницы, чтобы установить файлы cookie для этого домена (так же, как и сама страница). У этого метода есть два недостатка: это может привести к дополнительному времени прохождения туда и обратно из-за дополнительного HTTP-запроса, который вы должны сделать; и если на вашем сайте нет эквивалента пустой страницы, он может высветить любой URL-адрес, который вы загружаете первым, прежде чем перенаправить вас в нужное место.

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.http.cookie.Cookie;
import android.annotation.SuppressLint;
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class WebViewFragment {
    private static final String BLANK_PAGE = "/blank.html"

    private CookieSyncManager mSyncManager;
    private CookieManager mCookieManager;

    private String mTargetUrl;
    private boolean mInitializedCookies;
    private List<Cookie> mAllCookies;

    public WebViewFragment(Context ctx) {
        // We are still required to create an instance of Cookie/SyncManager.
        mSyncManager = CookieSyncManager.createInstance(ctx);
        mCookieManager = CookieManager.getInstance();
    }

    @SuppressLint("SetJavaScriptEnabled") public void loadWebView(
                String url, List<Cookie> cookies, String domain) {
        final WebView webView = ...

        webView.setWebViewClient(new CookeWebViewClient());
        webView.getSettings().setJavaScriptEnabled(true);

        mInitializedCookies = false;
        mTargetUrl = url;
        mAllCookies = cookies;
        // This is where the hack starts.
        // Instead of loading the url, we load a blank page.
        webView.loadUrl("http://" + domain + BLANK_PAGE);
    }

    public static String buildCookieString(final Cookie cookie) {
        // You may want to add the secure flag for https:
        // + "; secure"
        // In case you wish to convert session cookies to have an expiration:
        // + "; expires=Thu, 01-Jan-2037 00:00:10 GMT"
        // Note that you cannot set the HttpOnly flag as we are using
        // javascript to set the cookies.
        return cookie.getName() + "=" + cookie.getValue()
                    + "; path=" + cookie.getPath()
                    + "; domain=" + cookie.getDomain()
    };

    public synchronized String generateCookieJavascript() {
        StringBuilder javascriptCode = new StringBuilder();
        javascriptCode.append("javascript:(function(){");
        for (final Cookie cookie : mAllCookies) {
            String cookieString = buildCookieString(cookie);
            javascriptCode.append("document.cookie=\"");
            javascriptCode.append(
                     StringEscapeUtils.escapeJavascriptString(cookieString));
            javascriptCode.append("\";");
        }
        // We use javascript to load the next url because we do not
        // receive an onPageFinished event when this code finishes.
        javascriptCode.append("document.location=\"");
        javascriptCode.append(
                StringEscapeUtils.escapeJavascriptString(mTargetUrl));
        javascriptCode.append("\";})();");
        return javascriptCode.toString();
    }

    private class CookieWebViewClient extends WebViewClient {
        @Override public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            if (!mInitializedCookies) {
                mInitializedCookies = true;
                // Run our javascript code now that the temp page is loaded.
                view.loadUrl(generateCookieJavascript());
                return;
            }
        }
    }
}

Если вы доверяете домену, из которого находятся файлы cookie, вы можете обойтись без apache commons, но вы должны понимать, что это может представлять риск XSS, если вы не будете осторожны.

Патрик Хорн
источник
1

Это рабочий фрагмент кода.

    private void setCookie(DefaultHttpClient httpClient, String url) {
    List<Cookie> cookies = httpClient.getCookieStore().getCookies();
    if (cookies != null) {
        CookieSyncManager.createInstance(context);
        CookieManager cookieManager = CookieManager.getInstance();
        cookieManager.setAcceptCookie(true);

        for (int i = 0; i < cookies.size(); i++) {
            Cookie cookie = cookies.get(i);
            String cookieString = cookie.getName() + "=" + cookie.getValue();
            cookieManager.setCookie(url, cookieString);
        }
        CookieSyncManager.getInstance().sync();
    }
}

Здесь httpclient - это объект DefaultHttpClient, который вы использовали в запросе HttpGet / HttpPost. Также нужно убедиться, что имя и значение файла cookie должны быть указаны

String cookieString = cookie.getName() + "=" + cookie.getValue();

setCookie установит cookie для данного URL.

дроид-ребенок
источник
Просто примечание: вы не можете хранить файлы cookie сеанса с помощью CookieManager.setCookie
Джон Доу,
я не понял ... ты можешь объяснить?
дроид-ребенок
1

Я волшебным образом решил все свои проблемы с файлами cookie с помощью этой строки в onCreate:

CookieHandler.setDefault(new CookieManager());

изменить: сегодня он перестал работать. :( какая хрень, android.

Чани
источник
Итак, какие-нибудь обновления? почему перестало работать?, вы решили?
Франсиско Корралес Моралес,
1

С этим тоже столкнулся. Вот что я сделал.

В моем LoginActivity внутри моей AsyncTask у меня есть следующее:

CookieStoreHelper.cookieStore = new BasicCookieStore();
BasicHttpContext localContext = new BasicHttpContext();
localContext.setAttribute(ClientContext.COOKIE_STORE, CookieStoreHelper.cookieStore);

HttpResponse postResponse = client.execute(httpPost,localContext);
CookieStoreHelper.sessionCookie = CookieStoreHelper.cookieStore.getCookies();

// ГДЕ CookieStoreHelper.sessionCookie - это еще один класс, содержащий переменную sessionCookie, определенную как List cookies; и cookieStore определяют как BasicCookieStore cookieStore;

Затем на моем фрагменте, где находится мой WebView, у меня есть следующее:

//DECLARE LIST OF COOKIE
List<Cookie> sessionCookie;

внутри моего метода или непосредственно перед тем, как вы установите WebViewClient ()

WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
webView.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);

sessionCookie = CookieStoreHelper.cookieStore.getCookies();
CookieSyncManager.createInstance(webView.getContext());
CookieSyncManager.getInstance().startSync();
CookieManager cookieManager = CookieManager.getInstance();
CookieManager.getInstance().setAcceptCookie(true);
if (sessionCookie != null) {
   for(Cookie c:  sessionCookie){
      cookieManager.setCookie(CookieStoreHelper.DOMAIN, c.getName() + "=" + c.getValue());
   }
   CookieSyncManager.getInstance().sync();

 }

 webView.setWebViewClient(new WebViewClient() {
    //AND SO ON, YOUR CODE
 }

Совет: установите firebug в firefox или используйте консоль разработчика в Chrome и сначала протестируйте свою веб-страницу, запишите файл cookie и проверьте домен, чтобы вы могли его где-нибудь сохранить, и убедитесь, что вы правильно устанавливаете правильный домен.

Изменить: отредактировал CookieStoreHelper.cookies на CookieStoreHelper.sessionCookie

Бурнок
источник
1

Мой рабочий код

public View onCreateView(...){
    mWebView = (WebView) view.findViewById(R.id.webview);

    WebSettings webSettings = mWebView.getSettings();
    webSettings.setJavaScriptEnabled(true);

        ...
        ...
        ...

    CookieSyncManager.createInstance(mWebView.getContext());
    CookieManager cookieManager = CookieManager.getInstance();
    cookieManager.setAcceptCookie(true);
    //cookieManager.removeSessionCookie(); // remove
    cookieManager.removeAllCookie(); //remove
    // Recommended "hack" with a delay between the removal and the installation of "Cookies"
    SystemClock.sleep(1000);

    cookieManager.setCookie("https://my.app.site.com/", "cookiename=" + value + "; path=/registration" + "; secure"); // ;
    CookieSyncManager.getInstance().sync();

    mWebView.loadUrl(sp.getString("url", "") + end_url);

    return view;
}

Для отладки запроса cookieManager.setCookie (....); Я рекомендую вам просмотреть содержимое базы данных webviewCookiesChromium.db (хранится в "/data/data/my.app.webview/database") Там вы можете увидеть правильные настройки.

Отключение cookieManager.removeSessionCookie (); и / или cookieManager.removeAllCookie ();

//cookieManager.removeSessionCookie();
// and/or
//cookieManager.removeAllCookie();"

Сравните установленное значение с тем, что установлено браузером. Отрегулируйте запрос на установку файлов cookie до тех пор, пока не будут установлены «флажки», браузер будет соответствовать вашему выбору. Я обнаружил, что запрос может быть «флагами»:

// You may want to add the secure flag for https:
+ "; secure"
// In case you wish to convert session cookies to have an expiration:
+ "; expires=Thu, 01-Jan-2037 00:00:10 GMT"
// These flags I found in the database:
+ "; path=/registration"
+ "; domain=my.app.site.com"
Вадим Иванов
источник
Я использую приведенный выше код для сохранения файлов cookie в веб-представлении, но, пожалуйста, дайте мне знать о пути. какой здесь путь?
Mehul Tank
@MehulTank Параметр path указывает расположение документа. Файл cookie отправляется на сервер только в том случае, если путь соответствует текущему или родительскому местоположению документа.
Роланд ван дер Линден
1

Пара комментариев (по крайней мере, для API> = 21), которые я узнал из своего опыта и вызвал у меня головную боль:

  1. httpи httpsURL-адреса разные. Установка cookie для http://www.example.comотличается от установки cookie дляhttps://www.example.com
  2. Косая черта в конце URL-адреса также может иметь значение. В моем случае https://www.example.com/работает, но https://www.example.comне работает.
  3. CookieManager.getInstance().setCookieвыполняет асинхронную операцию. Таким образом, если вы загрузите URL-адрес сразу после его установки, не гарантируется, что файлы cookie уже будут записаны. Чтобы предотвратить неожиданное и нестабильное поведение, используйте CookieManager # setCookie (String url, String value, ValueCallback callback) ( ссылка ) и начните загружать URL после того, как будет вызван обратный вызов.

Я надеюсь, что мои два цента сэкономят время некоторым людям, чтобы вам не пришлось столкнуться с теми же проблемами, что и мне.

giorgos.nl
источник
Чем отличается установка файла cookie для example.com от настройки файла cookie для example.com ?
softmarshmallow
0

Я столкнулся с такой же проблемой, и это решит эту проблему во всех версиях Android.

private void setCookie() {
    try {
        CookieSyncManager.createInstance(context);
        CookieManager cookieManager = CookieManager.getInstance();
        cookieManager.setAcceptCookie(true);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            cookieManager.setCookie(Constant.BASE_URL, getCookie(), value -> {
                String cookie = cookieManager.getCookie(Constant.BASE_URL);
                CookieManager.getInstance().flush();
                CustomLog.d("cookie", "cookie ------>" + cookie);
                setupWebView();
            });
        } else {
            cookieManager.setCookie(webUrl, getCookie());
            new Handler().postDelayed(this::setupWebView, 700);
            CookieSyncManager.getInstance().sync();
        }

    } catch (Exception e) {
        CustomLog.e(e);
    }
}
Принкал Кумар
источник
0

Обратите внимание, что может быть лучше использовать поддомены вместо обычного URL. Итак, установите .example.comвместоhttps://example.com/ .

Благодаря Джоди Джейкобусу Гирсу и другим я написал так:

if (savedInstanceState == null) {
    val cookieManager = CookieManager.getInstance()
    cookieManager.acceptCookie()
    val domain = ".example.com"
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        cookieManager.setCookie(domain, "token=$token") {
            view.webView.loadUrl(url)
        }
        cookieManager.setAcceptThirdPartyCookies(view.webView, true)
    } else {
        cookieManager.setCookie(domain, "token=$token")
        view.webView.loadUrl(url)
    }
} else {
    // Check whether we're recreating a previously destroyed instance.
    view.webView.restoreState(savedInstanceState)
}
CoolMind
источник
-4

Не используйте свой необработанный URL

Вместо того:

cookieManager.setCookie(myUrl, cookieString); 

используйте это так:

cookieManager.setCookie("your url host", cookieString); 
Джейсон
источник