傳統(tǒng)網(wǎng)頁實現(xiàn)用戶登陸一般采用session或cookie記錄用戶基本信息又或者兩者結(jié)合起來使用。android也可以采用session實現(xiàn)用戶登陸驗證并記錄用戶登陸狀態(tài)時的基本信息,session是在服務(wù)器端的;而類似cookie的記錄方式,則可以在客戶端采用xml文件記錄用戶基本信息,重要數(shù)據(jù)則可以加密存放客戶端。android實現(xiàn)的session登陸功能與網(wǎng)頁請求不同的是,網(wǎng)頁形式的一次成功的登陸請求后,再點(diǎn)擊其他頁面時,session一直是存在的,在一定時間內(nèi)是有效的;而采用android客戶端請求的一次成功登陸后,再次發(fā)送新的請求,則會產(chǎn)生新的session,而不是原來的。這就需要記錄session的id號,并在整個請求過程中都記錄并傳遞這個id號,才能保證session的一致性。 以獲取php session為例,主要思路實現(xiàn)分為客戶端與服務(wù)器端3個步驟。 1.)客戶端 建立一個名為GetWebSession的android項目,編寫GetWebSession.java,LoginSuccessActivity.java,GetUserInfoActivity.java三個activity類。 1. GetWebSession.java主要是實現(xiàn)布局界面以及發(fā)送用戶名和密碼到php服務(wù)器端驗證,如果驗證成功則跳轉(zhuǎn)到LoginSuccessActivity.java類。GetWebSession.java主要涉及到與服務(wù)器端連接請求,對從服務(wù)器端返回的json數(shù)據(jù)(如用戶id,session等)進(jìn)行解析,并存入HashMap,傳遞到LoginSuccessActivity.java 代碼如下: package com.login.main; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.apache.http.protocol.HTTP; import org.apache.http.util.EntityUtils; import org.json.JSONException; import org.json.JSONObject; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; public class GetWebSession extends Activity { /** Called when the activity is first created. */ private EditText user; private EditText password; private Button loginBtn; private Button logoutBtn; //主要是記錄用戶會話過程中的一些用戶的基本信息 private HashMap<String, String> session =new HashMap<String, String>(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); user=(EditText)findViewById(R.id.user); password=(EditText)findViewById(R.id.password); loginBtn=(Button)findViewById(R.id.loginBtn); loginBtn.setOnClickListener(loginClick); logoutBtn=(Button)findViewById(R.id.logoutBtn); logoutBtn.setOnClickListener(logoutClick); } OnClickListener loginClick=new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub if(checkUser()){ Toast.makeText(v.getContext(), "用戶登錄成功!", Toast.LENGTH_SHORT).show(); Context context = v.getContext(); Intent intent = new Intent(context, LoginSuccessActivity.class); //傳遞session參數(shù),在用戶登錄成功后為session初始化賦值,即傳遞HashMap的值 Bundle map = new Bundle(); map.putSerializable("sessionid", session); intent.putExtra("session", map); context.startActivity(intent); // 跳轉(zhuǎn)到成功頁面 } else Toast.makeText(v.getContext(), "用戶驗證失?。?, Toast.LENGTH_SHORT).show(); } }; OnClickListener logoutClick=new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub System.exit(0); } }; private boolean checkUser(){ String username=user.getText().toString(); String pass=password.getText().toString(); DefaultHttpClient mHttpClient = new DefaultHttpClient(); HttpPost mPost = new HttpPost("http://10.0.2.2/web/php/login.php"); //傳遞用戶名和密碼相當(dāng)于 //http://10.0.2.2/web/php/login.php?username=''&password='' List<BasicNameValuePair> pairs = new ArrayList<BasicNameValuePair>(); pairs.add(new BasicNameValuePair("username", username)); pairs.add(new BasicNameValuePair("password", pass)); try { mPost.setEntity(new UrlEncodedFormEntity(pairs, HTTP.UTF_8)); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { HttpResponse response = mHttpClient.execute(mPost); int res = response.getStatusLine().getStatusCode(); if (res == 200) { HttpEntity entity = response.getEntity(); if (entity != null) { String info = EntityUtils.toString(entity); System.out.println("info-----------"+info); //以下主要是對服務(wù)器端返回的數(shù)據(jù)進(jìn)行解析 JSONObject jsonObject=null; //flag為登錄成功與否的標(biāo)記,從服務(wù)器端返回的數(shù)據(jù) String flag=""; String name=""; String userid=""; String sessionid=""; try { jsonObject = new JSONObject(info); flag = jsonObject.getString("flag"); name = jsonObject.getString("name"); userid = jsonObject.getString("userid"); sessionid = jsonObject.getString("sessionid"); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } //根據(jù)服務(wù)器端返回的標(biāo)記,判斷服務(wù)端端驗證是否成功 if(flag.equals("success")){ //為session傳遞相應(yīng)的值,用于在session過程中記錄相關(guān)用戶信息 session.put("s_userid", userid); session.put("s_username", name); session.put("s_sessionid", sessionid); return true; } else{ return false; } } else{ return false; } } } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return false; } } 2. LoginSuccessActivity.java主要獲取php的session唯一的標(biāo)識id以及用戶的一些基本信息,session id則作為本次用戶登錄狀態(tài)在服務(wù)器的唯一標(biāo)識,即確定用戶的唯一狀態(tài)進(jìn)行相關(guān)操作。LoginSuccessActivity.java類的方法與GetWebSession.java類似。其主要功能是獲取session id后再次發(fā)送session id到服務(wù)器進(jìn)行驗證,根據(jù)封裝的session數(shù)據(jù)驗證用戶操作權(quán)限等。 代碼如下: package com.login.main; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.apache.http.protocol.HTTP; import org.apache.http.util.EntityUtils; import org.json.JSONException; import org.json.JSONObject; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; public class LoginSuccessActivity extends Activity{ private HashMap<String, String>session; @SuppressWarnings("unchecked") @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.login_success); //獲取從登錄成功后界面的傳遞的參數(shù) session = (HashMap<String, String>) this.getIntent() .getBundleExtra("session").getSerializable("sessionid"); //讀取session的基本信息,并顯示相應(yīng)的控件 String userid_info=session.get("s_userid"); String username_info=session.get("s_username"); String session_id=session.get("s_sessionid"); //顯示相應(yīng)的內(nèi)容到控件 TextView userid_show=(TextView)findViewById(R.id.userid_show); userid_show.setText(userid_info); TextView username_show=(TextView)findViewById(R.id.username_show); username_show.setText(username_info); TextView sessionid_show=(TextView)findViewById(R.id.sessionid_show); sessionid_show.setText(session_id); //根據(jù)本次session再次獲取用戶信息 Button getInfo=(Button)findViewById(R.id.getinfo); getInfo.setOnClickListener(getInfoClick); } OnClickListener getInfoClick=new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub if(getUserInfo()){ Context context = v.getContext(); Intent intent = new Intent(context, GetUserInfoActivity.class); //傳遞session參數(shù),在用戶登錄成功后為session初始化賦值,即傳遞HashMap的值 Bundle map = new Bundle(); map.putSerializable("sessionid", session); intent.putExtra("session", map); context.startActivity(intent); // 跳轉(zhuǎn)到成功頁面 }else{ Toast.makeText(v.getContext(), "數(shù)據(jù)為空!", Toast.LENGTH_SHORT).show(); } } }; private boolean getUserInfo(){ String sess_username=session.get("s_username"); String sess_userid=session.get("s_userid"); String sess_id=session.get("s_sessionid"); DefaultHttpClient mHttpClient = new DefaultHttpClient(); HttpPost mPost = new HttpPost("http://10.0.2.2/web/php/getinfo.php"); List<BasicNameValuePair> pairs = new ArrayList<BasicNameValuePair>(); pairs.add(new BasicNameValuePair("sess_userid", sess_userid)); pairs.add(new BasicNameValuePair("sess_username", sess_username)); pairs.add(new BasicNameValuePair("sess_sessionid", sess_id)); try { mPost.setEntity(new UrlEncodedFormEntity(pairs, HTTP.UTF_8)); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { HttpResponse response = mHttpClient.execute(mPost); int res = response.getStatusLine().getStatusCode(); if (res == 200) { HttpEntity entity = response.getEntity(); if (entity != null) { String info = EntityUtils.toString(entity); System.out.println("info-----------"+info); //以下主要是對服務(wù)器端返回的數(shù)據(jù)進(jìn)行解析 JSONObject jsonObject=null; //flag為登錄成功與否的標(biāo)記,從服務(wù)器端返回的數(shù)據(jù) String flag=""; String userinfo=""; String level=""; String sessionid=""; try { jsonObject = new JSONObject(info); flag = jsonObject.getString("flag"); userinfo = jsonObject.getString("info"); level = jsonObject.getString("level"); sessionid = jsonObject.getString("sessionid"); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } //根據(jù)服務(wù)器端返回的標(biāo)記,判斷服務(wù)端端驗證是否成功 if(flag.equals("notempty")){ //為session傳遞相應(yīng)的值,用于在session過程中記錄相關(guān)用戶信息 session.put("info_userinfo", userinfo); session.put("info_level", level); session.put("info_sessionid", sessionid); return true; } else{ return false; } } else{ return false; } } } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return false; } } 3.GetUserInfoActivity.java類是根據(jù)用戶登錄后產(chǎn)生唯一session 標(biāo)識進(jìn)行操作獲取用戶詳細(xì)信息的類。 代碼如下: package com.login.main; import java.util.HashMap; import android.app.Activity; import android.os.Bundle; import android.widget.TextView; public class GetUserInfoActivity extends Activity{ private HashMap<String, String>session; @SuppressWarnings("unchecked") @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.get_info); //獲取從登錄成功后界面的再次傳遞的參數(shù) session = (HashMap<String, String>) this.getIntent(). getBundleExtra("session").getSerializable("sessionid"); //讀取session的基本信息,并顯示相應(yīng)的控件 String session_info=session.get("info_userinfo"); String session_level=session.get("info_level"); String session_id=session.get("info_sessionid"); //顯示相應(yīng)的內(nèi)容到控件 System.out.println("session_info--------"+session_info); TextView get_info=(TextView)findViewById(R.id.get_info); get_info.setText(session_info); TextView get_level=(TextView)findViewById(R.id.get_level); get_level.setText(session_level); TextView get_sessionid=(TextView)findViewById(R.id.get_sessionid); get_sessionid.setText(session_id); } } 4.三個布局的xml文件 (1.)main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="用戶"></TextView> <EditText android:layout_height="wrap_content" android:text="" android:layout_width="fill_parent" android:singleLine="true" android:id="@+id/user" ></EditText> <TextView android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="密碼"></TextView> <EditText android:id="@+id/password" android:layout_height="wrap_content" android:text="" android:layout_width="fill_parent" android:password="true" android:singleLine="true"></EditText> <LinearLayout android:layout_height="wrap_content" android:layout_width="fill_parent" android:orientation="horizontal" android:paddingLeft="0dip"> <TableRow android:layout_width="fill_parent" android:layout_height="wrap_content"> <Button android:layout_height="fill_parent" android:layout_width="fill_parent" android:text="登錄" android:id="@+id/loginBtn" android:layout_weight="1"></Button> <Button android:layout_height="fill_parent" android:layout_width="fill_parent" android:text="退出" android:id="@+id/logoutBtn" android:layout_weight="1"></Button> </TableRow> </LinearLayout> </LinearLayout> (2.)login_success.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <LinearLayout android:layout_height="wrap_content" android:layout_width="fill_parent" android:orientation="horizontal" android:paddingLeft="0dip"> <TextView android:layout_height="fill_parent" android:layout_width="wrap_content" android:text="用戶ID:" > </TextView> <TextView android:layout_height="fill_parent" android:layout_width="fill_parent" android:text="" android:id="@+id/userid_show" ></TextView> </LinearLayout> <LinearLayout android:layout_height="wrap_content" android:layout_width="fill_parent" android:orientation="horizontal" android:paddingLeft="0dip"> <TextView android:layout_height="fill_parent" android:layout_width="wrap_content" android:text="用戶名: " ></TextView> <TextView android:layout_height="fill_parent" android:layout_width="fill_parent" android:text="" android:id="@+id/username_show" ></TextView> </LinearLayout> <LinearLayout android:layout_height="wrap_content" android:layout_width="fill_parent" android:orientation="horizontal" android:paddingLeft="0dip"> <TextView android:layout_height="fill_parent" android:layout_width="wrap_content" android:text="本次會話:" ></TextView> <TextView android:layout_height="fill_parent" android:layout_width="fill_parent" android:text="" android:id="@+id/sessionid_show" ></TextView> </LinearLayout> <LinearLayout android:layout_height="wrap_content" android:layout_width="fill_parent" android:orientation="horizontal" android:paddingLeft="0dip"> <Button android:layout_height="fill_parent" android:layout_width="wrap_content" android:id="@+id/getinfo" android:text="根據(jù)本次會話再次獲取用戶信息" ></Button> </LinearLayout> </LinearLayout> (3.)get_info.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <LinearLayout android:layout_height="wrap_content" android:layout_width="fill_parent" android:orientation="horizontal" android:paddingLeft="0dip"> <TextView android:layout_height="fill_parent" android:layout_width="wrap_content" android:text="用戶信息: " > </TextView> <TextView android:layout_height="fill_parent" android:layout_width="fill_parent" android:text="" android:id="@+id/get_info" ></TextView> </LinearLayout> <LinearLayout android:layout_height="wrap_content" android:layout_width="fill_parent" android:orientation="horizontal" android:paddingLeft="0dip"> <TextView android:layout_height="fill_parent" android:layout_width="wrap_content" android:text="用戶級別:" ></TextView> <TextView android:layout_height="fill_parent" android:layout_width="fill_parent" android:text="" android:id="@+id/get_level" ></TextView> </LinearLayout> <LinearLayout android:layout_height="wrap_content" android:layout_width="fill_parent" android:orientation="horizontal" android:paddingLeft="0dip"> <TextView android:layout_height="fill_parent" android:layout_width="wrap_content" android:text="本次會話:" ></TextView> <TextView android:layout_height="fill_parent" android:layout_width="fill_parent" android:text="" android:id="@+id/get_sessionid" ></TextView> </LinearLayout> <LinearLayout android:layout_height="wrap_content" android:layout_width="fill_parent" android:orientation="horizontal" android:paddingLeft="0dip"> </LinearLayout> </LinearLayout> 2.)服務(wù)器端(php) php服務(wù)器端主要有三個文件,conn.php,login.php和getinfo.php。 1. conn.php是連接數(shù)據(jù)庫的配置文件。 2. login.php主要是用來驗證android客戶端發(fā)送的請求,請求成功則返回flag=’success’的狀態(tài)標(biāo)識,采用數(shù)組記錄用戶基本信息,存儲用戶數(shù)據(jù)到session,并且記錄本次產(chǎn)生的session id。用戶基本數(shù)據(jù)及本次session產(chǎn)生的id均封裝成json格式(json_encode($arr)),發(fā)送android客戶端。產(chǎn)生本次session id的方法 $sessionid=session_id();//注意沒有參數(shù) 具體代碼如下: <?php header("Content-Type: text/html; charset=utf-8") ; //包含數(shù)據(jù)庫連接文件 include('conn.php'); session_start(); $username = htmlspecialchars($_POST["username"]); $password=$_POST["password"]; mysql_query("set names utf8"); //檢測用戶名及密碼是否正確 $check_query = mysql_query("select id ,name from user where name='$username' and password='$password' limit 1"); $arr=array();//空的數(shù)組,該數(shù)組主要是格式化數(shù)據(jù)并封裝成json格式發(fā)送到客戶端 if($result = mysql_fetch_array($check_query)){ //登錄成功 $_SESSION['username'] = $result['name']; $_SESSION['userid'] = $result['id']; //獲取當(dāng)前session id $sessionid=session_id(); $_SESSION['$sessionid'] = $sessionid; $arr = array( 'flag'=>'success', 'name'=>$result['name'], 'userid'=>$result['id'], 'sessionid'=>$sessionid ); //封裝json,如果php版本低于5.2,則不支持json_encode()方法, //可以參考本文件夾中php_json_encode.php中php_json_encode()方法代替json_encode(); echo json_encode($arr); } else { $arr = array( 'flag'=>'error', 'name'=>'', 'userid'=>'', 'sessionid'=>'' ); //封裝json,如果php版本低于5.2,則不支持json_encode()方法, //可以參考本文件夾中php_json_encode.php中php_json_encode()方法代替json_encode(); echo json_encode($arr); } ?> 3. getinfo.php文件主要是用戶再次查詢信息驗證session,而不是重新產(chǎn)生session,以記錄用戶狀態(tài)。通過驗證flag是否為empty判斷數(shù)據(jù)是否顯示。最后封裝成json發(fā)送到客戶端 獲取本次session的方法: $sessionid=$_POST["sess_sessionid"];//獲取android客戶端的sessionid session_id($sessionid);//有參數(shù) session_start();//啟動session 具體代碼如下: <?php header("Content-Type: text/html; charset=utf-8") ; include('conn.php'); //獲取從客戶端LoginSuccessActivity類傳遞的參數(shù) $userid=$_POST["sess_userid"]; $username=$_POST["sess_username"]; //獲取客戶端傳遞的session標(biāo)識 $sessionid=$_POST["sess_sessionid"]; session_id($sessionid); //將會根據(jù)session id獲得原來的session session_start(); //獲取服務(wù)器端原來session記錄的username,并且根據(jù)客戶端傳過來的username比較進(jìn)行驗證操作 $sess_username=$_SESSION['username']; if($username==$sess_username){ mysql_query("set names utf8"); //查詢用戶基本信息 $check_query = mysql_query("select userinfo,level from info where userid='$userid' limit 1"); $arr=array();//空的數(shù)組 if($result = mysql_fetch_array($check_query)){ $arr = array( 'flag'=>'notempty', 'info'=>$result['userinfo'], 'level'=>$result['level'], 'sessionid'=>$sessionid ); echo json_encode($arr); } } else { $arr = array( 'flag'=>'empty', 'name'=>'', 'userid'=>'', 'sessionid'=>$sessionid ); echo json_encode($arr); } ?> 3.)數(shù)據(jù)庫端(mysql) 采用mysql建立數(shù)據(jù)庫,建立兩個簡單的數(shù)據(jù)表:user和info。 /* MySQL Data Transfer Source Host: localhost Source Database: login Target Host: localhost Target Database: login Date: 2011-6-14 11:10:46 */ SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for info -- ---------------------------- CREATE TABLE `info` ( `id` int(12) NOT NULL AUTO_INCREMENT, `userid` int(12) DEFAULT NULL, `userinfo` varchar(100) DEFAULT NULL, `level` int(2) DEFAULT NULL, PRIMARY KEY (`id`), KEY `useid` (`userid`), CONSTRAINT `useid` FOREIGN KEY (`userid`) REFERENCES `user` (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for user -- ---------------------------- CREATE TABLE `user` ( `id` int(12) NOT NULL AUTO_INCREMENT, `name` varchar(20) DEFAULT NULL, `password` varchar(20) DEFAULT NULL, `status` int(2) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records -- ---------------------------- INSERT INTO `info` VALUES ('1', '1', 'charlie is a developer.', '1'); INSERT INTO `info` VALUES ('2', '2', 'william is a boss.', '20'); INSERT INTO `user` VALUES ('1', 'charlie', 'password', '1'); INSERT INTO `user` VALUES ('2', 'william', 'mypassword', '2'); 運(yùn)行效果如圖: 圖 -1 GetWebSession.java類的布局 圖 -2 LoginSuccessActivity.java類獲取的session id以及用戶基本信息
發(fā)表評論