Vấn đề cookie WebView Android


89

Tôi có một máy chủ gửi cho ứng dụng Android của tôi một cookie phiên để được sử dụng cho giao tiếp đã xác thực. Tôi đang cố gắng tải một WebView có URL trỏ đến cùng một máy chủ đó và tôi đang cố chuyển cookie phiên để xác thực. Tôi đang quan sát thấy nó hoạt động không liên tục nhưng tôi không biết tại sao. Tôi sử dụng cùng một cookie phiên để thực hiện các cuộc gọi khác trên máy chủ của mình và những cuộc gọi này không bao giờ bị lỗi xác thực. Tôi chỉ quan sát thấy vấn đề này khi cố gắng tải một URL trong WebView và nó không xảy ra mọi lúc. Rất bực bội.

Dưới đây là mã mà tôi đang sử dụng để thực hiện việc này. Chúng tôi rất trân trọng bất kỳ sự giúp đỡ nào.

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

tham khảo câu hỏi này stackoverflow.com/questions/2566485/…
neeraj t

Câu trả lời:


55

Cảm ơn justingrammens ! Điều đó phù hợp với tôi, tôi đã quản lý để chia sẻ cookie trong các yêu cầu DefaultHttpClient và hoạt động WebView của mình:

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

Nó hiệu quả tuyệt vời đối với tôi. Do đó, tôi đã tạo url cookie của mình: String url = (cookie.isSecure ()? "Https": "http") + ": //" + cookie.getDomain () + cookie.getPath ();
Heath Borders

cảm ơn cho bài ... nó đã giúp tôi trong việc thực hiện logout twitter cho ứng dụng của tôi ...;)
Rahul

u có thể cho biết những gì được viết ở vị trí của myapp.cookie
Suraj jain

từ khóa là: String cookieString = sessionCookie.getName () + "=" + sessionCookie.getValue () + "; domain =" + sessionCookie.getDomain (); cookieManager.setCookie (myapp.domain, cookieString);
Zennichimaro

1
CookieSyncManager hiện không được dùng nữa :(
Misha Akopov

18

Cảm ơn Android đã làm hỏng ngày chủ nhật của tôi. . . Đây là những gì đã sửa Ứng dụng của tôi (sau khi bạn cài đặt chế độ xem web của mình)

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

  CookieManager cookieManager = CookieManager.getInstance();

  cookieManager.setAcceptThirdPartyCookies( webView, true );

}

Tôi nên nói các câu trả lời ở trên có thể sẽ hoạt động nhưng trong tình huống của tôi, thời điểm Android chạy v5 + 'ứng dụng' javascript webview android của tôi đã chết.


1
Oh ! Bạn vừa cứu được ngày của tôi!
Lê Minh

14

Giải pháp: 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");

bạn nhận được từ cookiegì ?, Tôi chỉ nhận được như: PHPSESSID=ljfakdjfklasdfaj!, vậy là đủ?
Francisco Corrales Morales

6
MySession ở đây là gì?
User3


3

Tôi sẽ lưu cookie phiên đó dưới dạng tùy chọn và bắt buộc phải tạo lại trình quản lý cookie với nó. Có vẻ như cookie phiên không tồn tại khi khởi động lại Hoạt động


Tôi nên nói thêm rằng ứng dụng của tôi thực hiện nhiều cuộc gọi không phải WebView trên máy chủ của tôi mà không bao giờ xác thực thất bại. Chỉ khi tôi cố gắng tải một URL trong WebView, tôi mới nhận thấy sự cố này. "Cookie sessionCookie = getCookie ();" đang truy xuất từ ​​DB của ứng dụng cookie phiên mà tôi sử dụng cho tất cả các thư với máy chủ của mình.
nannerpus

Chà nếu bạn đang sử dụng HttpClient vì nó có cửa hàng Cookie riêng, vì vậy nếu bạn giữ một phiên bản khách hàng duy nhất thì cookie của bạn sẽ tồn tại, nhưng nó có thể không liên quan gì đến cái mà chế độ xem web của bạn sử dụng
Bostone

Nếu tôi hiểu bạn chính xác, bạn đang nói rằng CookieManager được trả về bởi CookieManager.getInstance (); sẽ ảnh hưởng đến các cookie được sử dụng bởi các phiên bản của HttpClient, mà WebViews không sử dụng. Nếu điều này là đúng, bạn có biết cách tôi có thể chuyển cookie vào WebViews một cách rõ ràng không? Ngoài ra, nhìn vào tài liệu CookieManager, có lẽ việc không gọi "cookieManager.setAcceptCookie (true)" đang gây ra sự cố cho tôi? Cảm ơn sự giúp đỡ, thực sự đánh giá cao nó.
nannerpus

3

Tôi đã dành hơn 3 giờ đồng hồ để giải quyết một vấn đề tương tự. Trong trường hợp của tôi, tôi có một số cuộc gọi, tôi đã thực hiện tới một dịch vụ web bằng cách sử dụng một DefaulHttpClientvà sau đó tôi muốn đặt phiên và tất cả các cookie tương ứng khác trong của tôi WebView.

Tôi không biết liệu cách này có giải quyết được vấn đề của bạn hay không, vì tôi không biết getCookie()phương pháp của bạn làm được gì , nhưng trong trường hợp của tôi, tôi thực sự phải gọi.

cookieManager.removeSessionCookie();

Đầu tiên phải xóa cookie phiên và sau đó thêm lại nó. Tôi nhận thấy rằng khi tôi cố gắng đặt JSESSIONIDcookie mà không xóa nó trước, giá trị tôi muốn đặt thành không được lưu. Không chắc liệu điều này có giúp ích cho bạn vấn đề cụ thể hay không, nhưng tôi nghĩ tôi sẽ chia sẻ những gì tôi đã tìm thấy.


tại sao không CookieManager.getInstance().removeAllCookie ();?
Francisco Corrales Morales

2

Sau một thời gian nghiên cứu, tôi đã thu thập được một số phần giúp tôi đi đến giải pháp này. Khi CookieSyncManager không được dùng nữa, đây có thể là cách tốt nhất để đặt một cookie cụ thể cho chế độ xem web trong Kotlin hiện nay, bạn không cần bất kỳ thứ gì khác.

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

Tôi có một cách tiếp cận khác với những người khác ở đây và đó là một cách tiếp cận được đảm bảo hoạt động mà không cần xử lý CookieSyncManager (nơi bạn sử dụng ngữ nghĩa như "Lưu ý rằng thậm chí đồng bộ hóa () xảy ra không đồng bộ").

Về cơ bản, chúng tôi duyệt đến đúng tên miền, sau đó chúng tôi thực thi javascript từ ngữ cảnh trang để đặt cookie cho tên miền đó (giống như cách của chính trang đó). Hai nhược điểm của phương pháp này là có thể tăng thêm thời gian khứ hồi do yêu cầu thêm http mà bạn phải thực hiện; và nếu trang web của bạn không có trang trống tương đương, nó có thể nhấp nháy bất kỳ URL nào bạn tải đầu tiên trước khi đưa bạn đến đúng nơi.

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

Nếu bạn tin tưởng miền mà cookie đến từ đó, bạn có thể thoát mà không có dấu phẩy apache, nhưng bạn phải hiểu rằng điều này có thể gây ra rủi ro XSS nếu bạn không cẩn thận.


1

Đây là một đoạn mã hoạt động.

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

Ở đây httpclient là đối tượng DefaultHttpClient mà bạn đã sử dụng trong yêu cầu HttpGet / HttpPost. Ngoài ra một điều cần đảm bảo là tên và giá trị cookie, nó phải được cung cấp

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

setCookie sẽ thiết lập cookie cho URL đã cho.


Cũng giống như một lưu ý: bạn không thể lưu trữ các tập tin cookie phiên sử dụng CookieManager.setCookie
John Doe

tôi không hiểu ... bạn có thể giải thích không?
droid kid

1

Tôi đã giải quyết một cách kỳ diệu tất cả các vấn đề về cookie của mình với một dòng này trong onCreate:

CookieHandler.setDefault(new CookieManager());

chỉnh sửa: nó ngừng hoạt động hôm nay. :( cái quái gì vậy, android.


vì vậy, bất kỳ cập nhật? Tại sao nó ngừng hoạt động ?, Bạn đã giải quyết được chưa?
Francisco Corrales Morales

1

Cũng gặp phải điều này. Đây là những gì tôi đã làm.

Trên LoginActivity, bên trong AsyncTask, tôi có những thứ sau:

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 là một lớp khác chứa biến sessionCookie được định nghĩa là cookie Danh sách; và cookieStore định nghĩa là BasicCookieStore cookieStore;

Sau đó, trên Fragment, nơi đặt WebView của tôi, tôi có những thứ sau:

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

bên trong phương thức của tôi hoặc ngay trước khi bạn thiết lập 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
 }

Mẹo nhanh: Hãy cài đặt firebug trên firefox hoặc sử dụng bảng điều khiển dành cho nhà phát triển trên chrome và kiểm tra trang web của bạn trước tiên, chụp Cookie và kiểm tra miền để bạn có thể lưu trữ nó ở đâu đó và đảm bảo rằng bạn đang đặt đúng miền phù hợp.

Chỉnh sửa: đã chỉnh sửa CookieStoreHelper.cookies thành CookieStoreHelper.sessionCookie


1

Mã làm việc của tôi

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

Để gỡ lỗi truy vấn, "cookieManager.setCookie (....);" Tôi khuyên bạn nên xem qua nội dung của cơ sở dữ liệu webviewCookiesChromium.db (được lưu trữ trong "/data/data/my.app.webview/database") Ở đó Bạn có thể thấy cài đặt chính xác.

Đang tắt "cookieManager.removeSessionCookie ();" và / hoặc "cookieManager.removeAllCookie ();"

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

So sánh giá trị đặt với giá trị được đặt bởi trình duyệt. Điều chỉnh yêu cầu cài đặt cookie trước đó cho đến khi trình duyệt "cờ" không được cài đặt sẽ phù hợp với những gì Bạn quyết định. Tôi nhận thấy rằng một truy vấn có thể là "cờ":

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

Tôi đã sử dụng mã trên cho cookie cửa hàng trong chế độ xem web nhưng vui lòng cho tôi biết về đường dẫn. con đường ở đây là gì?
Mehul Tank

@MehulTank Tham số đường dẫn chỉ định vị trí tài liệu. Cookie chỉ được gửi đến máy chủ nếu đường dẫn khớp với vị trí tài liệu mẹ hoặc hiện tại.
Roland van der Linden

1

Một vài nhận xét (ít nhất là đối với API> = 21) mà tôi đã tìm ra từ kinh nghiệm của mình và khiến tôi đau đầu:

  1. httphttps url là khác nhau. Đặt cookie cho http://www.example.comkhác với đặt cookie chohttps://www.example.com
  2. Dấu gạch chéo ở cuối url cũng có thể tạo ra sự khác biệt. Trong trường hợp của tôihttps://www.example.com/ hoạt động nhưng https://www.example.comkhông hoạt động.
  3. CookieManager.getInstance().setCookieđang thực hiện một hoạt động không đồng bộ. Vì vậy, nếu bạn tải một url ngay sau khi bạn đặt nó, nó không được đảm bảo rằng các cookie sẽ được ghi. Để ngăn các hành vi không mong muốn và không ổn định, hãy sử dụng CookieManager # setCookie (String url, String value, ValueCallback callback) ( liên kết ) và bắt đầu tải url sau khi lệnh gọi lại sẽ được gọi.

Tôi hy vọng hai xu của tôi tiết kiệm thời gian của một số người để bạn sẽ không phải đối mặt với những vấn đề tương tự như tôi đã làm.


Đặt cookie cho example.com khác với đặt cookie cho example.com như thế nào?
softmarshmallow

0

Tôi đã gặp phải vấn đề tương tự và nó sẽ giải quyết vấn đề này trong tất cả các phiên bản 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

Lưu ý rằng tốt hơn có thể sử dụng tên miền phụ thay vì URL thông thường. Vì vậy, hãy đặt .example.comthay vì https://example.com/.

Cảm ơn Jody Jacobus Geers và những người khác, tôi đã viết như vậy:

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

Không sử dụng url thô của bạn

Thay vì:

cookieManager.setCookie(myUrl, cookieString); 

sử dụng nó như thế này:

cookieManager.setCookie("your url host", cookieString); 
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.