Поддержание сеанса cookie в Android
Хорошо, у меня есть приложение для Android, в котором есть форма, два EditText, spinner и кнопка входа. Пользователь выбирает услугу со счетчика, вводит имя пользователя и пароль и нажимает логин. Данные отправляются через POST, возвращается ответ, обрабатывается, запускается новый WebView, загружается строка html, сгенерированная из ответа, и у меня есть домашняя страница любой выбранной пользователем службы.
Это все хорошо и хорошо. Теперь, когда пользователь нажимает на ссылку, информация для входа не может быть найдена, и страница просит пользователя снова войти в систему. Мой сеанс регистрации куда-то куда-то удаляется, и я не уверен, как передать информацию из класса, который контролирует основную часть моего приложения, в класс, который только запускает активность веб-просмотра.
Обработчик onClick из формы login:
private class FormOnClickListener implements View.OnClickListener {
public void onClick(View v) {
String actionURL, user, pwd, user_field, pwd_field;
actionURL = "thePageURL";
user_field = "username"; //this changes based on selections in a spinner
pwd_field = "password"; //this changes based on selections in a spinner
user = "theUserLogin";
pwd = "theUserPassword";
List<NameValuePair> myList = new ArrayList<NameValuePair>();
myList.add(new BasicNameValuePair(user_field, user));
myList.add(new BasicNameValuePair(pwd_field, pwd));
HttpParams params = new BasicHttpParams();
DefaultHttpClient client = new DefaultHttpClient(params);
HttpPost post = new HttpPost(actionURL);
HttpResponse response = null;
BasicResponseHandler myHandler = new BasicResponseHandler();
String endResult = null;
try { post.setEntity(new UrlEncodedFormEntity(myList)); }
catch (UnsupportedEncodingException e) { e.printStackTrace(); }
try { response = client.execute(post); }
catch (ClientProtocolException e) { e.printStackTrace(); }
catch (IOException e) { e.printStackTrace(); }
try { endResult = myHandler.handleResponse(response); }
catch (HttpResponseException e) { e.printStackTrace(); }
catch (IOException e) { e.printStackTrace(); }
List<Cookie> cookies = client.getCookieStore().getCookies();
if (!cookies.isEmpty()) {
for (int i = 0; i < cookies.size(); i++) {
cookie = cookies.get(i);
}
}
Intent myWebViewIntent = new Intent(MsidePortal.this, MyWebView.class);
myWebViewIntent.putExtra("htmlString", endResult);
myWebViewIntent.putExtra("actionURL", actionURL);
startActivity(myWebViewIntent);
}
}
И вот класс WebView, который обрабатывает отображение ответа:
public class MyWebView extends android.app.Activity {
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.web);
MyWebViewClient myClient = new MyWebViewClient();
WebView webview = (WebView)findViewById(R.id.mainwebview);
webview.getSettings().setBuiltInZoomControls(true);
webview.getSettings().setJavaScriptEnabled(true);
webview.setWebViewClient(myClient);
Bundle extras = getIntent().getExtras();
if(extras != null)
{
// Get endResult
String htmlString = extras.getString("htmlString");
String actionURL = extras.getString("actionURL");
Cookie sessionCookie = MsidePortal.cookie;
CookieSyncManager.createInstance(this);
CookieManager cookieManager = CookieManager.getInstance();
if (sessionCookie != null) {
cookieManager.removeSessionCookie();
String cookieString = sessionCookie.getName()
+ "=" + sessionCookie.getValue()
+ "; domain=" + sessionCookie.getDomain();
cookieManager.setCookie(actionURL, cookieString);
CookieSyncManager.getInstance().sync();
}
webview.loadDataWithBaseURL(actionURL, htmlString, "text/html", "utf-8", actionURL);}
}
}
}
У меня был смешанный успех в реализации этого решения для файлов cookie. Кажется, что работает для одной службы, в которую я вхожу, что я знаю, хранит файлы cookie на сервере (старые, архаичные, но он работает, и они не хотят его изменять). Служба, которую я пытаюсь сейчас, требует от пользователя сохранения cookie на локальном компьютере, и он не работает с этой настройкой.
Любые предложения?
Ответы
Ответ 1
Вам нужно сохранить cookie от одного вызова другому. Вместо создания нового DefaultHttpClient используйте этот конструктор:
private Object mLock = new Object();
private CookieStore mCookie = null;
/**
* Builds a new HttpClient with the same CookieStore than the previous one.
* This allows to follow the http session, without keeping in memory the
* full DefaultHttpClient.
* @author Régis Décamps <[email protected]>
*/
private HttpClient getHttpClient() {
final DefaultHttpClient httpClient = new DefaultHttpClient();
synchronized (mLock) {
if (mCookie == null) {
mCookie = httpClient.getCookieStore();
} else {
httpClient.setCookieStore(mCookie);
}
}
return httpClient;
}
И сохраните класс Builder как поле вашего приложения.
Ответ 2
Вы можете хранить куки файлы в общих предпочтениях и загружать их по мере необходимости в других действиях.
Или попробуйте эту идею из аналогичного вопроса.
Ответ 3
Использовать это в URL-адресе Вход в систему
List<Cookie> cookies = client.getCookieStore().getCookies();
if (!cookies.isEmpty()) {
for (int i = 0; i < cookies.size(); i++) {
cookie = cookies.get(i);
}
}
Cookie sessionCookie = cookie;
if (sessionCookie != null) {
String cookieString = sessionCookie.getName() + "="
+ sessionCookie.getValue() + "; domain="
+ sessionCookie.getDomain();
cookieManager
.setCookie("www.mydomain.com", cookieString);
CookieSyncManager.getInstance().sync();
}
Ответ 4
У меня есть эта знакомая проблема несколько недель назад, потому что вы создаете новый DefaultHttpClient каждый раз, когда вы нажимаете кнопку. попробуйте создать один DefaultHttpClient и используя тот же DefaultHttpClient для каждого запроса, который вы пытаетесь отправить. он решил мою проблему
Ответ 5
dunno, если вам все еще нужен ответ, но снова здесь появляется дополнительная информация, которая может помочь
если вы хотите сохранить файлы cookie sync'ed
// ensure any cookies set by the dialog are saved
CookieSyncManager.getInstance().sync();
и если вы хотите очистить файлы cookie
public static void clearCookies(Context context) {
// Edge case: an illegal state exception is thrown if an instance of
// CookieSyncManager has not be created. CookieSyncManager is normally
// created by a WebKit view, but this might happen if you start the
// app, restore saved state, and click logout before running a UI
// dialog in a WebView -- in which case the app crashes
@SuppressWarnings("unused")
CookieSyncManager cookieSyncMngr =
CookieSyncManager.createInstance(context);
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.removeAllCookie();
}
Ответ 6
Когда запускается любое новое действие (поэтому я предполагаю, что это то же самое, когда вы запускаете новый веб-просмотр), он эффективно запускает новую программу с нуля. Это новое действие не будет иметь доступа к данным из любой предыдущей деятельности (если только эти данные не будут переданы путем присоединения к намерению).
2 возможных решения:
1) putExtra может использоваться только для передачи примитивных данных, поэтому, чтобы передать что-то более сложное, вам нужно либо
-
a) Оберните более сложную структуру в классе, который реализует
Удобный интерфейс, который может быть сохранен дополнительно.
b) Оберните более сложную структуру в классе, который реализует
Сериализуемый интерфейс, который может быть сохранен дополнительно.
Любой из этих подходов довольно сложный и справедливый бит работы.
2) Лично я предпочитаю подход, предложенный rds. Чтобы уточнить, когда rds говорит:
сохраните класс Builder как поле вашего приложения.
Я думаю, что он означает расширение класса приложения. Все хранящиеся там объекты доступны во всем мире для всех видов деятельности.
В этой статье очень четко объясняется, как это сделать:
http://www.screaming-penguin.com/node/7746
Вы можете игнорировать материал об AsyncTask (хотя я уверен, что вам это понадобится в какой-то момент) и просто сосредоточьтесь на части расширения класса приложения.
Ответ 7
Вы использовали эту строку -
if (sessionCookie != null) {
cookieManager.removeSessionCookie();
}
Чтобы каждый раз получать новый файл cookie.
Похоже, вы прошли через ту же проблему, что и я, проверьте ссылку ниже -
removeSessionCookie() проблема android (code.google., com)
говорится, что removeSessionCookie()
реализуется в потоке, поэтому всякий раз, когда он вызывается; начинается поток, и после вызова setCookie(url, cookieString);
он удаляет новый cookie, который вы только что установили.
Поэтому для некоторых устройств он хорошо работает, поскольку removeSessionCookie()
уже выполнен, а для некоторых он удаляет файл cookie, и мы получаем эту проблему.
Я предлагаю удалить этот removeSessionCookie();
, поскольку вы устанавливаете только один файл cookie, поэтому он не будет конфликтовать с другими файлами cookie. Ваш код будет работать без проблем.
Ответ 8
Sever использует идентификатор сеанса, хранящийся в файлах cookie, чтобы идентифицировать определенного пользователя. Каждый язык имеет другое имя sessionID в заголовках http. Вы можете использовать какой-либо сетевой инструмент или браузер, чтобы узнать, как называется имя sessionID.
И иначе, я буду угадывать, facebook и твиттер, вы удалите весь код, связанный с сеансом, на сервере используется токен доступа для идентификации пользователя.
Как я понял?