傳統(tǒng)網(wǎng)頁實現(xiàn)用戶登陸一般采用session或cookie記錄用戶基本信息又或者兩者結合起來使用。android也可以采用session實現(xiàn)用戶登陸驗證并記錄用戶登陸狀態(tài)時的基本信息,session是在服務器端的;而類似cookie的記錄方式,則可以在客戶端采用xml文件記錄用戶基本信息,重要數(shù)據(jù)則可以加密存放客戶端。android實現(xiàn)的session登陸功能與網(wǎng)頁請求不同的是,網(wǎng)頁形式的一次成功的登陸請求后,再點擊其他頁面時,session一直是存在的,在一定時間內(nèi)是有效的;而采用android客戶端請求的一次成功登陸后,再次發(fā)送新的請求,則會產(chǎn)生新的session,而不是原來的。這就需要記錄session的id號,并在整個請求過程中都記錄并傳遞這個id號,才能保證session的一致性。
以獲取php session為例,主要思路實現(xiàn)分為客戶端與服務器端3個步驟。
1.)客戶端
建立一個名為GetWebSession的android項目,編寫GetWebSession.java,LoginSuccessActivity.java,GetUserInfoActivity.java三個activity類。
1. GetWebSession.java主要是實現(xiàn)布局界面以及發(fā)送用戶名和密碼到php服務器端驗證,如果驗證成功則跳轉到LoginSuccessActivity.java類。GetWebSession.java主要涉及到與服務器端連接請求,對從服務器端返回的json數(shù)據(jù)(如用戶id,session等)進行解析,并存入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); // 跳轉到成功頁面
}
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");
//傳遞用戶名和密碼相當于
//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);
//以下主要是對服務器端返回的數(shù)據(jù)進行解析
JSONObject jsonObject=null;
//flag為登錄成功與否的標記,從服務器端返回的數(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ù)服務器端返回的標記,判斷服務端端驗證是否成功
if(flag.equals("success")){
//為session傳遞相應的值,用于在session過程中記錄相關用戶信息
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唯一的標識id以及用戶的一些基本信息,session id則作為本次用戶登錄狀態(tài)在服務器的唯一標識,即確定用戶的唯一狀態(tài)進行相關操作。LoginSuccessActivity.java類的方法與GetWebSession.java類似。其主要功能是獲取session id后再次發(fā)送session id到服務器進行驗證,根據(jù)封裝的session數(shù)據(jù)驗證用戶操作權限等。
代碼如下:
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的基本信息,并顯示相應的控件
String userid_info=session.get("s_userid");
String username_info=session.get("s_username");
String session_id=session.get("s_sessionid");
//顯示相應的內(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); // 跳轉到成功頁面
}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);
//以下主要是對服務器端返回的數(shù)據(jù)進行解析
JSONObject jsonObject=null;
//flag為登錄成功與否的標記,從服務器端返回的數(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ù)服務器端返回的標記,判斷服務端端驗證是否成功
if(flag.equals("notempty")){
//為session傳遞相應的值,用于在session過程中記錄相關用戶信息
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 標識進行操作獲取用戶詳細信息的類。
代碼如下:
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的基本信息,并顯示相應的控件
String session_info=session.get("info_userinfo");
String session_level=session.get("info_level");
String session_id=session.get("info_sessionid");
//顯示相應的內(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.)服務器端(php)
php服務器端主要有三個文件,conn.php,login.php和getinfo.php。
1. conn.php是連接數(shù)據(jù)庫的配置文件。
2. login.php主要是用來驗證android客戶端發(fā)送的請求,請求成功則返回flag=’success’的狀態(tài)標識,采用數(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'];
//獲取當前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標識
$sessionid=$_POST["sess_sessionid"];
session_id($sessionid);
//將會根據(jù)session id獲得原來的session
session_start();
//獲取服務器端原來session記錄的username,并且根據(jù)客戶端傳過來的username比較進行驗證操作
$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');
運行效果如圖:
圖 -1 GetWebSession.java類的布局
圖 -2 LoginSuccessActivity.java類獲取的session id以及用戶基本信息
發(fā)表評論