繁体   English   中英

Android-在活动之间保持用户登录

[英]Android - Keep user logged between activities

在我的应用程序中,我具有允许您登录到Web服务的第一个活动。 如果服务器允许用户连接,则应调用TabHost活动。 在TabHost活动中,我有3个不同的活动:

  • HomeActivity:仅显示一个Webview
  • HistoryActivity:它应该显示一个ListView,我在其中插入通知历史记录
  • SettingsActivity:显示应用程序的一些设置

在HistoryActivity中,我必须调用Web服务来下载通知历史记录的列表。 要调用此服务,我必须保持用户登录状态,我该怎么做?

我正在使用以下代码连接到历史记录服务:

public void postData(String url) {
    HttpClient httpClient = new DefaultHttpClient();
    HttpPost httpPost = new HttpPost(url);

    try {
        StringEntity  jsonSend = new StringEntity("{\"history\": true}");
        httpPost.setHeader("Content-type", "application/json; charset=UTF-8");
        httpPost.setEntity(jsonSend);
        HttpResponse response = httpClient.execute(httpPost);

        BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
        StringBuilder builder = new StringBuilder();

        for (String line = null; (line = reader.readLine()) != null;) {
            builder.append(line).append("\n");
        }
        String json = builder.toString();
        Log.d("HISTORY", json);
        }
    } catch (JSONException e) {
        e.printStackTrace();
    } catch (ClientProtocolException e) {
        e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

我用它登录,效果很好。 要连接到登录服务,请使用以下代码:

public void postData(final String username, final String password) {
    HttpClient httpClient = new DefaultHttpClient();
    HttpPost httpPost = new HttpPost(url);

    try {
        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
        nameValuePairs.add(new BasicNameValuePair("username", username));
        nameValuePairs.add(new BasicNameValuePair("password", password));
        nameValuePairs.add(new BasicNameValuePair("pollingId", "XXXXXXXXX"));

        httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");

        httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));

        HttpResponse response = httpClient.execute(httpPost);

        BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
        StringBuilder builder = new StringBuilder();

        for (String line = null; (line = reader.readLine()) != null;) {
            builder.append(line).append("\n");
        }

        String json = builder.toString();

        JSONObject jsonObject = new JSONObject(json);
        Boolean success = jsonObject.getBoolean("success");

        if (success == true) {
            MainActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(MainActivity.this, "ACCESSO EFFETTUATO!", Toast.LENGTH_LONG).show();
                    Intent i = new Intent(MainActivity.this, TabBarActivity.class);
                    startActivity(i);
                }
            });
        }

    } catch (ClientProtocolException e) {
       Log.d("CLIENT EXCEPTION", "ERRORE: " + e);
    }catch (IOException e) {
       Log.d("I/O EXCEPTION", "ERRORE: " + e);
    } catch (JSONException e) {
        e.printStackTrace();
    }
}

如果我使用它来获取通知历史记录,JSON会告诉我该用户未登录。 我该如何解决? 谢谢

更新我尝试遵循您的建议,但结果相同。 修改后的代码如下:

MainActivity.java

public void postData(final String username, final String password) {
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost("https://extranet.gruppotesta.it/srv/at-brain/login.jsp");

        try {
            List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
            nameValuePairs.add(new BasicNameValuePair("username", username));
            nameValuePairs.add(new BasicNameValuePair("password", password));
            nameValuePairs.add(new BasicNameValuePair("pollingId", "XXXXXXX"));

            httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");

            httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));

            HttpResponse response = httpClient.execute(httpPost);

            BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
            StringBuilder builder = new StringBuilder();

            for (String line = null; (line = reader.readLine()) != null;) {
                builder.append(line).append("\n");
            }

            String json = builder.toString();

            JSONObject jsonObject = new JSONObject(json);
            Boolean success = jsonObject.getBoolean("success");

            if (success == true) {
                Header[] cookie = response.getHeaders("cookie");
                SharedPreferences sharedPreferences = getPreferences(Context.MODE_PRIVATE);
                SharedPreferences.Editor editor = sharedPreferences.edit();
                editor.putString("cookie", cookie.toString());
                editor.commit();
                MainActivity.this.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(MainActivity.this, "ACCESSO EFFETTUATO!", Toast.LENGTH_LONG).show();
                        Intent i = new Intent(MainActivity.this, TabBarActivity.class);
                        startActivity(i);
                    }
                });
            }

        } catch (ClientProtocolException e) {
           Log.d("CLIENT EXCEPTION", "ERRORE: " + e);
        }catch (IOException e) {
           Log.d("I/O EXCEPTION", "ERRORE: " + e);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
}

HistoryActivity.java

   public void postData(String url) {
        HttpClient httpClient = new DefaultHttpClient();

        SharedPreferences sharedPreferences = getPreferences(Context.MODE_PRIVATE);
        String stringCookie = sharedPreferences.getString("cookie", null);
        BasicCookieStore cookieStore = new BasicCookieStore();
        Cookie cookie = new BasicClientCookie("login", stringCookie);
        cookieStore.addCookie(cookie);

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

        HttpPost httpPost = new HttpPost(url);

        try {
            StringEntity jsonRequest = new StringEntity("{\"history\": true}");
            httpPost.setEntity(jsonRequest);
            httpPost.setHeader("Content-type", "application/json; charset=UTF-8");
            httpPost.setHeader("Cookie", cookie.toString());

            HttpResponse response = httpClient.execute(httpPost, localContext);

            BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
            StringBuilder builder = new StringBuilder();

            for (String line = null; (line = reader.readLine()) != null;) {
                builder.append(line).append("\n");
            }
            String json = builder.toString();
            Log.d("HISTORY", json);

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

当我尝试运行该应用程序时,服务器用错误“用户未登录”回答我。 我的代码有什么问题?

首次登录时,Web服务必须为您提供某种访问令牌-也许是有效的用户ID 您需要在SharedPreference存储和检索此用户ID 用户标识必须作为参数传递给所有后续的Web服务,以指示该用户确实已登录。

有关如何获取和设置SharedPreference的官方教程在这里

您可以尝试使用CookieStore来存储具有登录凭据的cookie。 看一下此链接: Android中的Http cookie存储

成功登录后,您的服务是否还提供会话cookie? 如果是这样,您应该存储登录后服务发出的cookie(在服务器响应中的Set-Cookie标头中),并为以后的任何HTTP请求设置此cookie。

httpPost.setHeader("Cookie", COOKIE_FROM_SERVER_AFTER_LOGIN);

您也可以使用CookieStore来帮助您存储来自HTTP请求的cookie-这将使cookie和会话管理更加容易。

UPDATE

服务器标头将不包含Cookie标头,但包含Set-Cookie标头(因为服务器正在指示您的useragent /浏览器/客户端设置Cookie,而该Cookie将包含在Cookie标头中),因此请更改以下行:

response.getHeaders("cookie");

response.getHeaders("set-cookie"); 

更新:

您的修订版现在正在提取正确的Set-Cookie标头,但您错误地存储了该值(当您只需要该值时,会将整个标头存储为cookie)。

if (success == true) {

    Header[] cookies = response.getHeaders("set-cookie");
    //at this point cookies looks like this:
    //Set-Cookie: JSESSIONID=84DB43CE8CABC52EBDF777BC0EA96D0F; Path=/; Secure
    //if you just do cookies.toString() like you were doing before it will also include
    //the cookie header which will create an incorrect cookie value.
    //you just need the value of the Set-Cookie header and store that as your cookie
    if (cookies.length > 0){

        //it is very possible for a server to return more than one Set-Cookie header so the proper
        //way would be to iterate through all of the values and string them together
        //in the correct synatax of
        //so you might want to store all of the values as a list in sharedPreferences
        //and let your cookie store put them all in the request for you

        String finalCookie = "";

        for (Header header: cookies){

            //access the value from the Header object and nothing else
            //JSESSIONID=90D84EF5D5BD1C4008F332F9EDA8F9AA; Path=/; Secure;
            if (header.getValue().contains(";")){
                finalCookie += String.format("%s; ", header.getValue().split(";")[0]);
            } else {
                finalCookie += String.format("%s; ", header.getValue());
            }
        }
        //finalCookie = JSESSIONID=1B70CAB822430E14991E14ACAE153F5D; 

        SharedPreferences sharedPreferences = getActivity().getPreferences(Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sharedPreferences.edit();
        editor.putString("cookie", finalCookie);
        editor.commit();
    }

现在,在StoredPreferences中,您将具有正确格式的cookie(在这种情况下,您仅从服务器返回一个Set-Cookie ,但是服务器响应中可能包含多个Set-Cookie标头。因此,此实现会解析每个cookie并构建正确格式的Cookie字符串。

由于我们现在自己正确地构建了cookie字符串,因此您可以删除CookieStore并从SharedPreferences中拉出“ cookie”值,并使用setHeader调用中返回的字符串:

SharedPreferences sharedPreferences = getPreferences(Context.MODE_PRIVATE);
String stringCookie = sharedPreferences.getString("cookie", "");
...
httpPost.setHeader("Cookie", cookie);

请记住,尽管此实现对您有效,但在整个会话过程中Cookie都不会发生变化。 由于您是Web应用程序的作者,因此您应该了解cookie是否会发生变化-也许当您登录时,系统会为您提供在浏览器中设置cookie的唯一时间,此解决方案将为您服务。 但是,更健壮的解决方案是单独保存所有cookie(而不是使用editor.putString,而不必使用editor.putStringSet保存所有cookie头),那么当您要为响应构建cookie时,可以.add()将每个单独的cookie放入cookie存储,然后以以前的方式使用cookie存储。 这样,每个cookie都按名称存储,这样,如果您再次为已加载到客户端中的cookie获得另一个Set-Cookie标头,它将使用更新的cookie值正确覆盖该值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM