Android WebView 쿠키 문제


89

인증 된 통신에 사용할 세션 쿠키를 Android 앱에 보내는 서버가 있습니다. 동일한 서버를 가리키는 URL로 WebView를로드하려고하는데 인증을 위해 세션 쿠키를 전달하려고합니다. 간헐적으로 작동하는 것을 관찰하고 있지만 이유를 모르겠습니다. 동일한 세션 쿠키를 사용하여 내 서버에서 다른 호출을 만들고 인증에 실패하지 않습니다. WebView에서 URL을로드하려고 할 때만이 문제가 발생하며 매번 발생하지 않습니다. 매우 실망 스럽습니다.

다음은이 작업을 수행하는 데 사용하는 코드입니다. 어떤 도움이라도 대단히 감사하겠습니다.

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 ! 그것은 나를 위해 일했으며 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();
}   

이것은 나를 위해 잘 작동했습니다. 따라서 쿠키 URL을 구성했습니다. String url = (cookie.isSecure ()? "https": "http") + ": //"+ cookie.getDomain () + cookie.getPath ();
Heath Borders

게시물 주셔서 감사합니다 ... 내 앱에 대한 트위터 로그 아웃을 구현하는 데 도움이되었습니다 ...;)
rahul

u는 myapp.cookie 대신에 기록되는 것을 알 수 있습니다
SURAJ 자이나교

키워드는 다음과 같습니다. String cookieString = sessionCookie.getName () + "="+ sessionCookie.getValue () + "; domain ="+ sessionCookie.getDomain (); cookieManager.setCookie (myapp.domain, cookieString);
Zennichimaro

1
CookieSyncManager는 현재 사용되지 않습니다. :(
Misha Akopov

18

내 일요일을 망치는 안드로이드에 감사드립니다. . . 내 앱을 수정 한 이유는 다음과 같습니다 (웹뷰를 초기화 한 후).

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

  CookieManager cookieManager = CookieManager.getInstance();

  cookieManager.setAcceptThirdPartyCookies( webView, true );

}

위의 답변이 아마도 작동 할 것이라고 말해야하지만 내 상황에서는 Android가 v5 +로 전환되는 순간 내 Android webview javascript 'apps'가 죽었습니다.


1
오! 당신은 내 하루를 구했습니다!
Le Minh

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!, 충분합니까?
Francisco Corrales Morales

6
여기서 MySession은 무엇입니까?
User3


3

세션 쿠키를 기본 설정으로 저장하고 쿠키 관리자를 강제로 다시 채 웁니다. 활동이 다시 시작되지 않는 세션 쿠키가 들립니다.


내 앱이 인증에 실패하지 않는 내 서버 호출에서 WebView가 아닌 ​​다른 많은 호출을 만든다는 점을 추가해야합니다. WebView에서 URL을로드하려고 할 때만이 문제가 나타납니다. "쿠키 sessionCookie = getCookie ();" 내 서버의 모든 메시지에 사용하는 세션 쿠키를 앱의 DB에서 검색하고 있습니다.
nannerpus

HttpClient를 사용하는 경우 자체 쿠키 저장소가 있으므로 클라이언트의 단일 인스턴스를 보유하면 쿠키가 유지되지만 웹보기에서 사용하는 쿠키와는 아무 관련이 없을 수 있습니다
Bostone

내가 올바르게 이해한다면 CookieManager.getInstance (); WebView가 사용하지 않는 HttpClient 인스턴스에서 사용하는 쿠키에 영향을줍니다. 이것이 사실이라면 쿠키를 WebView에 명시 적으로 전달할 수있는 방법을 알고 있습니까? 또한 CookieManager 문서를 보면 "cookieManager.setAcceptCookie (true)"를 호출하지 않으면 문제가 발생합니까? 도움을 주셔서 감사합니다. 정말 감사합니다.
nannerpus 2009

3

저는 3 시간의 절반 이상을 매우 유사한 문제에 대해 작업했습니다. 제 경우에는 a를 사용하여 웹 서비스를 호출 DefaulHttpClient한 다음 .NET Framework에서 세션 및 기타 모든 해당 쿠키를 설정하고 싶었습니다 WebView.

나는 당신의 getCookie()방법이 무엇을하는지 모르기 때문에 이것이 당신의 문제를 해결할지 모르겠지만 제 경우에는 실제로 전화해야했습니다.

cookieManager.removeSessionCookie();

먼저 세션 쿠키를 제거한 다음 다시 추가하십시오. JSESSIONID쿠키를 먼저 제거하지 않고 설정하려고했을 때 설정하고 싶은 값이 저장되지 않는 것을 발견했습니다. 이것이 특정 문제에 도움이 될지 확실하지 않지만 내가 찾은 것을 공유 할 것이라고 생각했습니다.


왜 안돼 CookieManager.getInstance().removeAllCookie ();?
Francisco Corrales Morales

2

얼마 동안 조사한 후이 솔루션에 도달하도록 만든 몇 가지 조각을 모았습니다. CookieSyncManager가 더 이상 사용되지 않으면 현재 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 ()조차 비동기 적으로 발생 함"과 같은 의미 체계의 자비에 처해있는 경우)를 처리하지 않고도 작동이 보장되는 접근 방식입니다.

기본적으로 올바른 도메인을 찾은 다음 페이지 컨텍스트에서 자바 스크립트를 실행하여 해당 도메인에 대한 쿠키를 설정합니다 (페이지 자체와 동일한 방식). 이 방법의 두 가지 단점은 추가 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;
            }
        }
    }
}

쿠키가있는 도메인을 신뢰하면 아파치 커먼즈 없이도 벗어날 수 있지만 조심하지 않으면 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는 HttpGet / HttpPost 요청에서 사용한 DefaultHttpClient 개체입니다. 또한 확인해야 할 한 가지는 쿠키 이름과 값입니다.

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

setCookie는 주어진 URL에 대한 쿠키를 설정합니다.


참고 사항 : CookieManager.setCookie를 사용하여 세션 쿠키를 저장할 수 없습니다
John Doe

이해하지 못했습니다. 설명 할 수 있나요?
droid kid

1

나는 onCreate 에서이 한 줄로 모든 쿠키 문제를 마술처럼 해결했습니다.

CookieHandler.setDefault(new CookieManager());

편집 : 오늘 작동이 중지되었습니다. :( 무슨 쓰레기, 안드로이드.


그래서, 어떤 업데이트? 왜 작동을 멈췄습니까?, 해결 했습니까?
Francisco Corrales Morales

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

// WHERE CookieStoreHelper.sessionCookie는 쿠키 목록으로 정의 된 변수 sessionCookie를 포함하는 또 다른 클래스입니다. 그리고 cookieStore는 BasicCookieStore cookieStore로 정의됩니다.

그런 다음 내 WebView가있는 내 Fragment에 다음이 있습니다.

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

빠른 팁 : Firefox에 firebug를 설치하거나 Chrome에서 개발자 콘솔을 사용하고 먼저 웹 페이지를 테스트하고 쿠키를 캡처 한 다음 도메인을 확인하여 어딘가에 저장할 수 있으며 올바른 도메인을 올바르게 설정하고 있는지 확인하십시오.

편집 : 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();"

설정 값을 브라우저에서 설정 한 값과 비교하십시오. "플래그"브라우저가 설치되지 않을 때까지 귀하가 결정한 내용에 맞을 때까지 쿠키 설치 요청을 조정하십시오. 쿼리가 "플래그"일 수 있음을 발견했습니다.

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

웹보기에서 쿠키 저장에 위의 코드를 사용했지만 경로에 대해 알려주십시오. 여기 경로는 무엇입니까?
Mehul Tank

@MehulTank 경로 매개 변수는 문서 위치를 지정합니다. 쿠키는 경로가 현재 또는 상위 문서 위치와 일치하는 경우에만 서버로 전송됩니다.
Roland van der Linden

1

내 경험을 통해 알게 된 몇 가지 의견 (적어도 API가 21 이상인 경우)은 두통을주었습니다.

  1. httphttpsURL이 다릅니다. 쿠키를 설정하는 것은 쿠키를 설정하는 http://www.example.com것과 다릅니다.https://www.example.com
  2. URL 끝에있는 슬래시도 차이를 만들 수 있습니다. 제 경우에는 https://www.example.com/작동하지만 작동 https://www.example.com하지 않습니다.
  3. CookieManager.getInstance().setCookie비동기 작업을 수행하고 있습니다. 따라서 URL을 설정 한 후 바로로드하면 쿠키가 이미 작성되었음을 보장 할 수 없습니다. 예기치 않은 불안정한 동작을 방지하려면 CookieManager # setCookie (String url, String value, ValueCallback callback) ( link )를 사용하고 콜백이 호출 된 후 URL로드를 시작하십시오.

내 2 센트가 일부 사람들의 시간을 절약하여 내가했던 것과 같은 문제에 직면 할 필요가 없도록하기를 바랍니다.


얼마나 다른지에 대한 쿠키를 설정한다 example.com을 위해 쿠키를 설정하는 것보다 다른 example.com을 ?
softmarshmallow

0

나는 같은 문제에 직면했으며 모든 안드로이드 버전 에서이 문제를 해결할 것입니다.

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

Jody Jacobus Geers와 다른 사람들에게 감사드립니다.

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

원시 URL을 사용하지 마십시오

대신에:

cookieManager.setCookie(myUrl, cookieString); 

다음과 같이 사용하십시오.

cookieManager.setCookie("your url host", cookieString); 
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.