android获取web服务器端session并验证登陆
传统网页实现用户登陆一般采用session或cookie记录用户基本信息又或者两者结合起来使用。android也可以采用session实现用户登陆验证并记录用户登陆状态时的基本信息,session是在服务器端的;而类似cookie的记录方式,则可以在客户端采用xml文件记录用户基本信息,重要数据则可以加密存放客户端。android实现的session登陆功能与网页请求不同的是,网页形式的一次成功的登陆请求后,再点击其他页面时,session一直是存在的,在一定时间内是有效的;而采用android客户端请求的一次成功登陆后,再次发送新的请求,则会产生新的session,而不是原来的。这就需要记录session的id号,并在整个请求过程中都记录并传递这个id号,才能保证session的一致性。
以获取php session为例,主要思路实现分为客户端与服务器端3个步骤。
附件:源码下载
1.)客户端(Android)
建立一个名为GetWebSession的android项目,编写GetWebSession.java,LoginSuccessActivity.java,GetUserInfoActivity.java三个activity类。
1. GetWebSession.java主要是实现布局界面以及发送用户名和密码到php服务器端验证,如果验证成功则跳转到LoginSuccessActivity.java类。GetWebSession.java主要涉及到与服务器端连接请求,对从服务器端返回的json数据(如用户id,session等)进行解析,并存入HashMap,传递到LoginSuccessActivity.java
代码如下:
- packagecom.login.main;
- importjava.io.IOException;
- importjava.io.UnsupportedEncodingException;
- importjava.util.ArrayList;
- importjava.util.HashMap;
- importjava.util.List;
- importorg.apache.http.HttpEntity;
- importorg.apache.http.HttpResponse;
- importorg.apache.http.client.ClientProtocolException;
- importorg.apache.http.client.entity.UrlEncodedFormEntity;
- importorg.apache.http.client.methods.HttpPost;
- importorg.apache.http.impl.client.DefaultHttpClient;
- importorg.apache.http.message.BasicNameValuePair;
- importorg.apache.http.protocol.HTTP;
- importorg.apache.http.util.EntityUtils;
- importorg.json.JSONException;
- importorg.json.JSONObject;
- importandroid.app.Activity;
- importandroid.content.Context;
- importandroid.content.Intent;
- importandroid.os.Bundle;
- importandroid.view.View;
- importandroid.view.View.OnClickListener;
- importandroid.widget.Button;
- importandroid.widget.EditText;
- importandroid.widget.Toast;
- publicclassGetWebSessionextendsActivity{
- /**Calledwhentheactivityisfirstcreated.*/
- privateEditTextuser;
- privateEditTextpassword;
- privateButtonloginBtn;
- privateButtonlogoutBtn;
- //主要是记录用户会话过程中的一些用户的基本信息
- privateHashMap<String,String>session=newHashMap<String,String>();
- @Override
- publicvoidonCreate(BundlesavedInstanceState){
- 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);
- }
- OnClickListenerloginClick=newOnClickListener(){
- @Override
- publicvoidonClick(Viewv){
- //TODOAuto-generatedmethodstub
- if(checkUser()){
- Toast.makeText(v.getContext(),"用户登录成功!",Toast.LENGTH_SHORT).show();
- Contextcontext=v.getContext();
- Intentintent=newIntent(context,
- LoginSuccessActivity.class);
- //传递session参数,在用户登录成功后为session初始化赋值,即传递HashMap的值
- Bundlemap=newBundle();
- map.putSerializable("sessionid",session);
- intent.putExtra("session",map);
- context.startActivity(intent);//跳转到成功页面
- }
- else
- Toast.makeText(v.getContext(),"用户验证失败!",Toast.LENGTH_SHORT).show();
- }
- };
- OnClickListenerlogoutClick=newOnClickListener(){
- @Override
- publicvoidonClick(Viewv){
- //TODOAuto-generatedmethodstub
- System.exit(0);
- }
- };
- privatebooleancheckUser(){
- Stringusername=user.getText().toString();
- Stringpass=password.getText().toString();
- DefaultHttpClientmHttpClient=newDefaultHttpClient();
- HttpPostmPost=newHttpPost("http://10.0.2.2/web/php/login.php");
- //传递用户名和密码相当于
- //http://10.0.2.2/web/php/login.php?username=''&password=''
- List<BasicNameValuePair>pairs=newArrayList<BasicNameValuePair>();
- pairs.add(newBasicNameValuePair("username",username));
- pairs.add(newBasicNameValuePair("password",pass));
- try{
- mPost.setEntity(newUrlEncodedFormEntity(pairs,HTTP.UTF_8));
- }catch(UnsupportedEncodingExceptione){
- //TODOAuto-generatedcatchblock
- e.printStackTrace();
- }
- try{
- HttpResponseresponse=mHttpClient.execute(mPost);
- intres=response.getStatusLine().getStatusCode();
- if(res==200){
- HttpEntityentity=response.getEntity();
- if(entity!=null){
- Stringinfo=EntityUtils.toString(entity);
- System.out.println("info-----------"+info);
- //以下主要是对服务器端返回的数据进行解析
- JSONObjectjsonObject=null;
- //flag为登录成功与否的标记,从服务器端返回的数据
- Stringflag="";
- Stringname="";
- Stringuserid="";
- Stringsessionid="";
- try{
- jsonObject=newJSONObject(info);
- flag=jsonObject.getString("flag");
- name=jsonObject.getString("name");
- userid=jsonObject.getString("userid");
- sessionid=jsonObject.getString("sessionid");
- }catch(JSONExceptione){
- //TODOAuto-generatedcatchblock
- e.printStackTrace();
- }
- //根据服务器端返回的标记,判断服务端端验证是否成功
- if(flag.equals("success")){
- //为session传递相应的值,用于在session过程中记录相关用户信息
- session.put("s_userid",userid);
- session.put("s_username",name);
- session.put("s_sessionid",sessionid);
- returntrue;
- }
- else{
- returnfalse;
- }
- }
- else{
- returnfalse;
- }
- }
- }catch(ClientProtocolExceptione){
- //TODOAuto-generatedcatchblock
- e.printStackTrace();
- }catch(IOExceptione){
- //TODOAuto-generatedcatchblock
- e.printStackTrace();
- }
- returnfalse;
- }
- }
2. LoginSuccessActivity.java主要获取php的session唯一的标识id以及用户的一些基本信息,session id则作为本次用户登录状态在服务器的唯一标识,即确定用户的唯一状态进行相关操作。LoginSuccessActivity.java类的方法与GetWebSession.java类似。其主要功能是获取session id后再次发送session id到服务器进行验证,根据封装的session数据验证用户操作权限等。
代码如下:
- packagecom.login.main;
- importjava.io.IOException;
- importjava.io.UnsupportedEncodingException;
- importjava.util.ArrayList;
- importjava.util.HashMap;
- importjava.util.List;
- importorg.apache.http.HttpEntity;
- importorg.apache.http.HttpResponse;
- importorg.apache.http.client.ClientProtocolException;
- importorg.apache.http.client.entity.UrlEncodedFormEntity;
- importorg.apache.http.client.methods.HttpPost;
- importorg.apache.http.impl.client.DefaultHttpClient;
- importorg.apache.http.message.BasicNameValuePair;
- importorg.apache.http.protocol.HTTP;
- importorg.apache.http.util.EntityUtils;
- importorg.json.JSONException;
- importorg.json.JSONObject;
- importandroid.app.Activity;
- importandroid.content.Context;
- importandroid.content.Intent;
- importandroid.os.Bundle;
- importandroid.view.View;
- importandroid.view.View.OnClickListener;
- importandroid.widget.Button;
- importandroid.widget.TextView;
- importandroid.widget.Toast;
- publicclassLoginSuccessActivityextendsActivity{
- privateHashMap<String,String>session;
- @SuppressWarnings("unchecked")
- @Override
- protectedvoidonCreate(BundlesavedInstanceState){
- //TODOAuto-generatedmethodstub
- super.onCreate(savedInstanceState);
- setContentView(R.layout.login_success);
- //获取从登录成功后界面的传递的参数
- session=(HashMap<String,String>)this.getIntent()
- .getBundleExtra("session").getSerializable("sessionid");
- //读取session的基本信息,并显示相应的控件
- Stringuserid_info=session.get("s_userid");
- Stringusername_info=session.get("s_username");
- Stringsession_id=session.get("s_sessionid");
- //显示相应的内容到控件
- TextViewuserid_show=(TextView)findViewById(R.id.userid_show);
- userid_show.setText(userid_info);
- TextViewusername_show=(TextView)findViewById(R.id.username_show);
- username_show.setText(username_info);
- TextViewsessionid_show=(TextView)findViewById(R.id.sessionid_show);
- sessionid_show.setText(session_id);
- //根据本次session再次获取用户信息
- ButtongetInfo=(Button)findViewById(R.id.getinfo);
- getInfo.setOnClickListener(getInfoClick);
- }
- OnClickListenergetInfoClick=newOnClickListener(){
- @Override
- publicvoidonClick(Viewv){
- //TODOAuto-generatedmethodstub
- if(getUserInfo()){
- Contextcontext=v.getContext();
- Intentintent=newIntent(context,
- GetUserInfoActivity.class);
- //传递session参数,在用户登录成功后为session初始化赋值,即传递HashMap的值
- Bundlemap=newBundle();
- map.putSerializable("sessionid",session);
- intent.putExtra("session",map);
- context.startActivity(intent);//跳转到成功页面
- }else{
- Toast.makeText(v.getContext(),"数据为空!",Toast.LENGTH_SHORT).show();
- }
- }
- };
- privatebooleangetUserInfo(){
- Stringsess_username=session.get("s_username");
- Stringsess_userid=session.get("s_userid");
- Stringsess_id=session.get("s_sessionid");
- DefaultHttpClientmHttpClient=newDefaultHttpClient();
- HttpPostmPost=newHttpPost("http://10.0.2.2/web/php/getinfo.php");
- List<BasicNameValuePair>pairs=newArrayList<BasicNameValuePair>();
- pairs.add(newBasicNameValuePair("sess_userid",sess_userid));
- pairs.add(newBasicNameValuePair("sess_username",sess_username));
- pairs.add(newBasicNameValuePair("sess_sessionid",sess_id));
- try{
- mPost.setEntity(newUrlEncodedFormEntity(pairs,HTTP.UTF_8));
- }catch(UnsupportedEncodingExceptione){
- //TODOAuto-generatedcatchblock
- e.printStackTrace();
- }
- try{
- HttpResponseresponse=mHttpClient.execute(mPost);
- intres=response.getStatusLine().getStatusCode();
- if(res==200){
- HttpEntityentity=response.getEntity();
- if(entity!=null){
- Stringinfo=EntityUtils.toString(entity);
- System.out.println("info-----------"+info);
- //以下主要是对服务器端返回的数据进行解析
- JSONObjectjsonObject=null;
- //flag为登录成功与否的标记,从服务器端返回的数据
- Stringflag="";
- Stringuserinfo="";
- Stringlevel="";
- Stringsessionid="";
- try{
- jsonObject=newJSONObject(info);
- flag=jsonObject.getString("flag");
- userinfo=jsonObject.getString("info");
- level=jsonObject.getString("level");
- sessionid=jsonObject.getString("sessionid");
- }catch(JSONExceptione){
- //TODOAuto-generatedcatchblock
- e.printStackTrace();
- }
- //根据服务器端返回的标记,判断服务端端验证是否成功
- if(flag.equals("notempty")){
- //为session传递相应的值,用于在session过程中记录相关用户信息
- session.put("info_userinfo",userinfo);
- session.put("info_level",level);
- session.put("info_sessionid",sessionid);
- returntrue;
- }
- else{
- returnfalse;
- }
- }
- else{
- returnfalse;
- }
- }
- }catch(ClientProtocolExceptione){
- //TODOAuto-generatedcatchblock
- e.printStackTrace();
- }catch(IOExceptione){
- //TODOAuto-generatedcatchblock
- e.printStackTrace();
- }
- returnfalse;
- }
- }
3.GetUserInfoActivity.java类是根据用户登录后产生唯一session 标识进行操作获取用户详细信息的类。
代码如下:
- packagecom.login.main;
- importjava.util.HashMap;
- importandroid.app.Activity;
- importandroid.os.Bundle;
- importandroid.widget.TextView;
- publicclassGetUserInfoActivityextendsActivity{
- privateHashMap<String,String>session;
- @SuppressWarnings("unchecked")
- @Override
- protectedvoidonCreate(BundlesavedInstanceState){
- //TODOAuto-generatedmethodstub
- super.onCreate(savedInstanceState);
- setContentView(R.layout.get_info);
- //获取从登录成功后界面的再次传递的参数
- session=(HashMap<String,String>)this.getIntent().
- getBundleExtra("session").getSerializable("sessionid");
- //读取session的基本信息,并显示相应的控件
- Stringsession_info=session.get("info_userinfo");
- Stringsession_level=session.get("info_level");
- Stringsession_id=session.get("info_sessionid");
- //显示相应的内容到控件
- System.out.println("session_info--------"+session_info);
- TextViewget_info=(TextView)findViewById(R.id.get_info);
- get_info.setText(session_info);
- TextViewget_level=(TextView)findViewById(R.id.get_level);
- get_level.setText(session_level);
- TextViewget_sessionid=(TextView)findViewById(R.id.get_sessionid);
- get_sessionid.setText(session_id);
- }
- }
4.三个布局的xml文件
(1.)main.xml
- <?xmlversion="1.0"encoding="utf-8"?>
- <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <TextViewandroid:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:text="用户"></TextView>
- <EditTextandroid:layout_height="wrap_content"
- android:text=""android:layout_width="fill_parent"
- android:singleLine="true"android:id="@+id/user"></EditText>
- <TextViewandroid:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:text="密码"></TextView>
- <EditTextandroid:id="@+id/password"
- android:layout_height="wrap_content"
- android:text=""android:layout_width="fill_parent"
- android:password="true"android:singleLine="true"></EditText>
- <LinearLayoutandroid:layout_height="wrap_content"
- android:layout_width="fill_parent"
- android:orientation="horizontal"
- android:paddingLeft="0dip">
- <TableRowandroid:layout_width="fill_parent"
- android:layout_height="wrap_content">
- <Buttonandroid:layout_height="fill_parent"
- android:layout_width="fill_parent"android:text="登录"
- android:id="@+id/loginBtn"
- android:layout_weight="1"></Button>
- <Buttonandroid: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
- <?xmlversion="1.0"encoding="utf-8"?>
- <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"android:layout_height="fill_parent"
- android:orientation="vertical">
- <LinearLayoutandroid: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>
- <TextViewandroid:layout_height="fill_parent"
- android:layout_width="fill_parent"
- android:text=""
- android:id="@+id/userid_show"></TextView>
- </LinearLayout>
- <LinearLayoutandroid:layout_height="wrap_content"
- android:layout_width="fill_parent"
- android:orientation="horizontal"
- android:paddingLeft="0dip">
- <TextViewandroid:layout_height="fill_parent"
- android:layout_width="wrap_content"
- android:text="用户名:"></TextView>
- <TextViewandroid:layout_height="fill_parent"
- android:layout_width="fill_parent"
- android:text=""
- android:id="@+id/username_show"></TextView>
- </LinearLayout>
- <LinearLayoutandroid:layout_height="wrap_content"
- android:layout_width="fill_parent"
- android:orientation="horizontal"
- android:paddingLeft="0dip">
- <TextViewandroid:layout_height="fill_parent"
- android:layout_width="wrap_content"
- android:text="本次会话:"></TextView>
- <TextViewandroid:layout_height="fill_parent"
- android:layout_width="fill_parent"
- android:text=""
- android:id="@+id/sessionid_show"></TextView>
- </LinearLayout>
- <LinearLayoutandroid:layout_height="wrap_content"
- android:layout_width="fill_parent"
- android:orientation="horizontal"
- android:paddingLeft="0dip">
- <Buttonandroid:layout_height="fill_parent"
- android:layout_width="wrap_content"
- android:id="@+id/getinfo"
- android:text="根据本次会话再次获取用户信息"
- ></Button>
- </LinearLayout>
- </LinearLayout>
(3.)get_info.xml
- <?xmlversion="1.0"encoding="utf-8"?>
- <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical">
- <LinearLayoutandroid:layout_height="wrap_content"
- android:layout_width="fill_parent"
- android:orientation="horizontal"
- android:paddingLeft="0dip">
- <TextViewandroid:layout_height="fill_parent"
- android:layout_width="wrap_content"
- android:text="用户信息:">
- </TextView>
- <TextViewandroid:layout_height="fill_parent"
- android:layout_width="fill_parent"
- android:text=""
- android:id="@+id/get_info"></TextView>
- </LinearLayout>
- <LinearLayoutandroid:layout_height="wrap_content"
- android:layout_width="fill_parent"
- android:orientation="horizontal"
- android:paddingLeft="0dip">
- <TextViewandroid:layout_height="fill_parent"
- android:layout_width="wrap_content"
- android:text="用户级别:"></TextView>
- <TextViewandroid:layout_height="fill_parent"
- android:layout_width="fill_parent"
- android:text=""
- android:id="@+id/get_level"></TextView>
- </LinearLayout>
- <LinearLayoutandroid:layout_height="wrap_content"
- android:layout_width="fill_parent"
- android:orientation="horizontal"
- android:paddingLeft="0dip">
- <TextViewandroid:layout_height="fill_parent"
- android:layout_width="wrap_content"
- android:text="本次会话:"></TextView>
- <TextViewandroid:layout_height="fill_parent"
- android:layout_width="fill_parent"android:text=""
- android:id="@+id/get_sessionid"></TextView>
- </LinearLayout>
- <LinearLayoutandroid: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是连接数据库的配置文件。
2. login.php主要是用来验证android客户端发送的请求,请求成功则返回flag=’success’的状态标识,采用数组记录用户基本信息,存储用户数据到session,并且记录本次产生的session id。用户基本数据及本次session产生的id均封装成json格式(json_encode($arr)),发送android客户端。产生本次session id的方法
$sessionid=session_id();//注意没有参数
具体代码如下:
- <?php
- header("Content-Type:text/html;charset=utf-8");
- //包含数据库连接文件
- include('conn.php');
- session_start();
- $username=htmlspecialchars($_POST["username"]);
- $password=$_POST["password"];
- mysql_query("setnamesutf8");
- //检测用户名及密码是否正确
- $check_query=mysql_query("selectid,namefromuserwherename='$username'and
- password='$password'limit1");
- $arr=array();//空的数组,该数组主要是格式化数据并封装成json格式发送到客户端
- if($result=mysql_fetch_array($check_query)){
- //登录成功
- $_SESSION['username']=$result['name'];
- $_SESSION['userid']=$result['id'];
- //获取当前sessionid
- $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();
- echojson_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();
- echojson_encode($arr);
- }
- ?>
3. getinfo.php文件主要是用户再次查询信息验证session,而不是重新产生session,以记录用户状态。通过验证flag是否为empty判断数据是否显示。最后封装成json发送到客户端
获取本次session的方法:
$sessionid=$_POST["sess_sessionid"];//获取android客户端的sessionid
session_id($sessionid);//有参数
session_start();//启动session
具体代码如下:
- <?php
- header("Content-Type:text/html;charset=utf-8");
- include('conn.php');
- //获取从客户端LoginSuccessActivity类传递的参数
- $userid=$_POST["sess_userid"];
- $username=$_POST["sess_username"];
- //获取客户端传递的session标识
- $sessionid=$_POST["sess_sessionid"];
- session_id($sessionid);
- //将会根据sessionid获得原来的session
- session_start();
- //获取服务器端原来session记录的username,并且根据客户端传过来的username比较进行验证操作
- $sess_username=$_SESSION['username'];
- if($username==$sess_username){
- mysql_query("setnamesutf8");
- //查询用户基本信息
- $check_query=mysql_query("selectuserinfo,levelfrominfowhereuserid='$userid'limit1");
- $arr=array();//空的数组
- if($result=mysql_fetch_array($check_query)){
- $arr=array(
- 'flag'=>'notempty',
- 'info'=>$result['userinfo'],
- 'level'=>$result['level'],
- 'sessionid'=>$sessionid
- );
- echojson_encode($arr);
- }
- }else{
- $arr=array(
- 'flag'=>'empty',
- 'name'=>'',
- 'userid'=>'',
- 'sessionid'=>$sessionid
- );
- echojson_encode($arr);
- }
- ?>
3.)数据库端(mysql)
采用mysql建立数据库,建立两个简单的数据表:user和info。
- /*
- MySQLDataTransfer
- SourceHost:localhost
- SourceDatabase:login
- TargetHost:localhost
- TargetDatabase:login
- Date:2011-6-1411:10:46
- */
- SETFOREIGN_KEY_CHECKS=0;
- ------------------------------
- --Tablestructureforinfo
- ------------------------------
- CREATETABLE`info`(
- `id`int(12)NOTNULLAUTO_INCREMENT,
- `userid`int(12)DEFAULTNULL,
- `userinfo`varchar(100)DEFAULTNULL,
- `level`int(2)DEFAULTNULL,
- PRIMARYKEY(`id`),
- KEY`useid`(`userid`),
- CONSTRAINT`useid`FOREIGNKEY(`userid`)REFERENCES`user`(`id`)
- )ENGINE=InnoDBAUTO_INCREMENT=3DEFAULTCHARSET=utf8;
- ------------------------------
- --Tablestructureforuser
- ------------------------------
- CREATETABLE`user`(
- `id`int(12)NOTNULLAUTO_INCREMENT,
- `name`varchar(20)DEFAULTNULL,
- `password`varchar(20)DEFAULTNULL,
- `status`int(2)DEFAULTNULL,
- PRIMARYKEY(`id`)
- )ENGINE=InnoDBAUTO_INCREMENT=3DEFAULTCHARSET=utf8;
- ------------------------------
- --Records
- ------------------------------
- INSERTINTO`info`VALUES('1','1','charlieisadeveloper.','1');
- INSERTINTO`info`VALUES('2','2','williamisaboss.','20');
- INSERTINTO`user`VALUES('1','charlie','password','1');
- INSERTINTO`user`VALUES('2','william','mypassword','2');
运行效果如图:
图 -1 GetWebSession.java类的布局
图 -2 LoginSuccessActivity.java类获取的session id以及用户基本信息
图 -3 GetWebSession.java获取用户详细信息及本次session的一致性
自 http://www.yoyong.com/archives/178