Android WebView Cookie Problem


88

Ich habe einen Server, der meiner Android-App ein Sitzungscookie sendet, das für die authentifizierte Kommunikation verwendet wird. Ich versuche, eine WebView mit einer URL zu laden, die auf denselben Server verweist, und ich versuche, das Sitzungscookie zur Authentifizierung zu übergeben. Ich beobachte, dass es zeitweise funktioniert, aber ich habe keine Ahnung warum. Ich verwende dasselbe Sitzungscookie, um andere Anrufe auf meinem Server zu tätigen, und diese scheitern nie an der Authentifizierung. Ich beobachte dieses Problem nur, wenn ich versuche, eine URL in eine WebView zu laden, und es tritt nicht jedes Mal auf. Sehr frustrierend.

Unten ist der Code, den ich dazu benutze. Jede Hilfe wird sehr geschätzt.

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

beziehen Sie sich auf diese Frage stackoverflow.com/questions/2566485/…
neeraj t

Antworten:


53

Danke justingrammens ! Das hat bei mir funktioniert. Ich habe es geschafft, das Cookie in meinen DefaultHttpClient-Anforderungen und in meiner WebView-Aktivität freizugeben:

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

Das hat bei mir super funktioniert. Ich habe meine Cookie-URL folgendermaßen erstellt: String url = (cookie.isSecure ()? "Https": "http") + ": //" + cookie.getDomain () + cookie.getPath ();
Heath Borders

danke für den Beitrag ... es hat mir geholfen, das Twitter-Logout für meine App zu implementieren ...;)
rahul


Das Schlüsselwort lautet: String cookieString = sessionCookie.getName () + "=" + sessionCookie.getValue () + "; domain =" + sessionCookie.getDomain (); cookieManager.setCookie (myapp.domain, cookieString);
Zennichimaro

1
CookieSyncManager ist jetzt veraltet :(
Misha Akopov

18

Danke Android, dass du meinen Sonntag ruiniert hast. . . Hier ist, was meine Apps repariert hat (nachdem Sie Ihre Webansicht initiiert haben)

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

  CookieManager cookieManager = CookieManager.getInstance();

  cookieManager.setAcceptThirdPartyCookies( webView, true );

}

Ich sollte sagen, dass die obigen Antworten wahrscheinlich funktionieren werden, aber in meiner Situation starb in dem Moment, in dem Android v5 + ging, meine Android-Webview-Javascript-Apps.


1
Oh ! Du hast gerade meinen Tag gerettet!
Le Minh

14

Lösung: 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");

was bekommst du von cookie?, ich bekomme nur wie: PHPSESSID=ljfakdjfklasdfaj!, ist das genug?
Francisco Corrales Morales

6
Was ist MySession hier?
User3


3

Ich würde dieses Sitzungscookie als Präferenz speichern und den Cookie-Manager mit Nachdruck damit neu füllen. Es hört sich so an, als würde das Sitzungscookie den Neustart der Aktivität nicht überleben


Ich sollte hinzufügen, dass meine App auf meinen Serveraufrufen viele andere Nicht-WebView-Aufrufe ausführt, bei denen die Authentifizierung niemals fehlschlägt. Erst wenn ich versuche, eine URL in eine WebView zu laden, bemerke ich dieses Problem. "Cookie sessionCookie = getCookie ();" ruft aus der Datenbank der App das Sitzungscookie ab, das ich für alle Nachrichten mit meinem Server verwende.
Nannerpus

Wenn Sie HttpClient dafür verwenden, verfügt es über einen eigenen Cookie-Speicher. Wenn Sie also an der einzelnen Instanz des Clients festhalten, bleibt Ihr Cookie erhalten, hat jedoch möglicherweise nichts mit der von Ihrer
Webansicht

Wenn ich Sie richtig verstehe, sagen Sie, dass der CookieManager von CookieManager.getInstance () zurückgegeben wurde; wirkt sich auf die Cookies aus, die von Instanzen von HttpClient verwendet werden, die von WebViews nicht verwendet werden. Wenn dies zutrifft, wissen Sie, wie ich Cookies explizit an WebViews übergeben kann? Wenn ich mir die CookieManager-Dokumente ansehe und möglicherweise nicht "cookieManager.setAcceptCookie (true)" aufrufe, kann ich Probleme bekommen? Danke für die Hilfe, schätze es sehr.
Nannerpus

3

Ich habe die größere Hälfte von 3 Stunden damit verbracht, an einem sehr ähnlichen Thema zu arbeiten. In meinem Fall hatte ich eine Reihe von Anrufen, die ich mit einem Webdienst getätigt habe, DefaulHttpClientund dann wollte ich die Sitzung und alle anderen entsprechenden Cookies in meinem setzen WebView.

Ich weiß nicht, ob dies Ihr Problem lösen wird, da ich nicht weiß, was Ihre getCookie()Methode tut, aber in meinem Fall musste ich tatsächlich anrufen.

cookieManager.removeSessionCookie();

Entfernen Sie zuerst das Sitzungscookie und fügen Sie es dann erneut hinzu. Ich habe festgestellt, dass JSESSIONIDder Wert, auf den ich ihn setzen wollte, nicht gespeichert wurde, als ich versuchte, das Cookie zu setzen, ohne es zuerst zu entfernen. Ich bin mir nicht sicher, ob dies Ihnen bei einem bestimmten Problem helfen wird, dachte aber, ich würde teilen, was ich gefunden habe.


warum nicht CookieManager.getInstance().removeAllCookie ();?
Francisco Corrales Morales

2

Nach einiger Zeit der Recherche habe ich einige Teile gesammelt, die mich zu dieser Lösung gebracht haben. Sobald dieser CookieSyncManager veraltet ist, kann dies heutzutage der beste Weg sein, ein bestimmtes Cookie für eine Webansicht in Kotlin zu setzen. Sie sollten nichts anderes mehr benötigen.

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

Ich habe einen anderen Ansatz als andere Leute hier, und es ist ein Ansatz, der garantiert funktioniert, ohne sich mit dem CookieSyncManager zu befassen (wo Sie der Semantik wie "Beachten Sie, dass sogar sync () asynchron geschieht" ausgeliefert sind).

Im Wesentlichen navigieren wir zur richtigen Domain und führen dann Javascript aus dem Seitenkontext aus, um Cookies für diese Domain zu setzen (genau wie die Seite selbst). Zwei Nachteile der Methode sind, dass aufgrund der zusätzlichen http-Anforderung, die Sie stellen müssen, eine zusätzliche Umlaufzeit eingeführt werden kann. Wenn Ihre Website nicht das Äquivalent einer leeren Seite hat, wird möglicherweise die URL geladen, die Sie zuerst geladen haben, bevor Sie an den richtigen Ort gebracht werden.

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

Wenn Sie der Domain vertrauen, von der die Cookies stammen, können Sie möglicherweise ohne Apache Commons davonkommen. Sie müssen jedoch verstehen, dass dies ein XSS-Risiko darstellen kann, wenn Sie nicht vorsichtig sind.


1

Dies ist ein funktionierender Code.

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

Hier ist der httpclient das DefaultHttpClient-Objekt, das Sie in der HttpGet / HttpPost-Anforderung verwendet haben. Außerdem sollten Sie sicherstellen, dass der Name und der Wert des Cookies angegeben werden

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

setCookie setzt das Cookie für die angegebene URL.


Nur als Hinweis: Sie können keine Sitzungscookies mit CookieManager.setCookie
John Doe

Ich habe das nicht verstanden ... kannst du es erklären?
Droidenkind

1

Ich habe alle meine Cookie-Probleme mit dieser einen Zeile in onCreate auf magische Weise gelöst:

CookieHandler.setDefault(new CookieManager());

edit: es hat heute aufgehört zu funktionieren. :( Was zum Teufel, Android.


Also irgendwelche Updates? Warum hat es aufgehört zu funktionieren? Hast du es gelöst?
Francisco Corrales Morales

1

Auch dem begegnet. Folgendes habe ich getan.

In meiner LoginActivity in meiner AsyncTask habe ich Folgendes:

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

// WHERE CookieStoreHelper.sessionCookie ist eine weitere Klasse, die die Variable ListCookie enthält, die als List Cookies definiert ist. und cookieStore definieren als BasicCookieStore cookieStore;

Dann habe ich auf meinem Fragment, wo sich mein WebView befindet, Folgendes:

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

in meiner Methode oder kurz bevor Sie den WebViewClient () einstellen

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
 }

Kurztipp: Lassen Sie firebug auf Firefox installieren oder verwenden Sie die Entwicklerkonsole auf Chrome und testen Sie zuerst Ihre Webseite, erfassen Sie das Cookie und überprüfen Sie die Domain, damit Sie es irgendwo speichern und sicherstellen können, dass Sie die richtige Domain richtig einstellen.

Bearbeiten: CookieStoreHelper.cookies zu CookieStoreHelper.sessionCookie bearbeitet


1

Mein Arbeitscode

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

Um die Abfrage zu debuggen, "cookieManager.setCookie (....);" Ich empfehle Ihnen, den Inhalt der Datenbank webviewCookiesChromium.db (gespeichert in "/data/data/my.app.webview/database") durchzusehen. Dort sehen Sie die richtigen Einstellungen.

Deaktivieren von "cookieManager.removeSessionCookie ();" und / oder "cookieManager.removeAllCookie ();"

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

Vergleichen Sie den eingestellten Wert mit denen, die vom Browser eingestellt wurden. Passen Sie die Anforderung für die Installation der Cookies an, bis der Browser "Flags" nicht installiert ist. Ich habe festgestellt, dass eine Abfrage "Flags" sein kann:

// 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"

Ich habe den obigen Code für das Speichern von Cookies in der Webansicht verwendet, aber bitte teilen Sie mir den Pfad mit. Was ist der Weg hier?
Mehul Tank

@MehulTank Der Pfadparameter gibt einen Dokumentspeicherort an. Das Cookie wird nur an den Server gesendet, wenn der Pfad mit dem aktuellen oder einem übergeordneten Dokumentspeicherort übereinstimmt.
Roland van der Linden

1

Einige Kommentare (zumindest für APIs> = 21), die ich aus meiner Erfahrung herausgefunden und mir Kopfschmerzen bereitet habe:

  1. httpund httpsURLs sind unterschiedlich. Das Festlegen eines Cookies für http://www.example.comunterscheidet sich vom Festlegen eines Cookies fürhttps://www.example.com
  2. Ein Schrägstrich am Ende der URL kann ebenfalls einen Unterschied machen. In meinem Fall https://www.example.com/funktioniert aber https://www.example.comnicht.
  3. CookieManager.getInstance().setCookieführt eine asynchrone Operation durch. Wenn Sie also eine URL sofort nach dem Festlegen laden, kann nicht garantiert werden, dass die Cookies bereits geschrieben wurden. Um unerwartete und instabile Verhaltensweisen zu vermeiden, verwenden Sie den CookieManager # setCookie (String-URL, String-Wert, ValueCallback-Rückruf) ( Link ) und laden Sie die URL, nachdem der Rückruf aufgerufen wurde.

Ich hoffe, meine zwei Cent sparen einigen Leuten Zeit, damit Sie nicht mit den gleichen Problemen konfrontiert werden wie ich.


Wie unterschiedlich ist das Festlegen eines Cookies für example.com vom Festlegen eines Cookies für example.com ?
Uzu

0

Ich habe das gleiche Problem und es wird dieses Problem in allen Android-Versionen beheben

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

Beachten Sie, dass es möglicherweise besser ist, Subdomains anstelle der üblichen URL zu verwenden. Also setzen .example.comstatt https://example.com/.

Dank Jody Jacobus Geers und anderen habe ich so geschrieben:

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

-4

Verwenden Sie nicht Ihre rohe URL

Anstatt:

cookieManager.setCookie(myUrl, cookieString); 

benutze es so:

cookieManager.setCookie("your url host", cookieString); 
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.