Android与IIS身份验证——Form验证

内容摘要

  前言

  设计思路 

  ASP.NET服务器端

  Android客户端

  运行结果

         

  上篇《Android与IIS身份验证——基本验证》实现了Android客户端与IIS的简单验证。而这种验证方式虽然使用起来比较简单,但是也有很多缺点。如,安全性较差,账号密码设置不灵活。让我们回顾一下ASP.NET的身份验证方式:Windows、Form和Passport。这三种验证方式中,Form身份验证方式最经常使用,因为它有很多优越性,其优点我就不一一介绍了。那么,怎样实现Android客户端与IIS的Form身份验证呢?我整理了一下,需要以下几个步骤:

   一、设计思路

   Android客户端访问IIS服务器时,当没有登陆时,ASP.NET通过Form集成验证方法会返回一个登陆页面。然后输入正确的用户名和密码,就可以进入主程序了。流程如图1.1所示。

图1.1

 

  在Android客户端访问以IIS为宿主的ASP.NET服务器时,返回JSON格式来传递数据。客户端中,根据返回数据的不同而判断当前状态是否已登陆。由于Form验证是保存了Cookie,所示每次调用Http请求之前要先添加上次请求的Cookie。

  二、ASP.NET服务器端

  创建一个ASP.NET MVC网站项目。 

  首先,由于每次请求都返回JSON格式的数据,我们编写一个Model类来承载数据。

  

    public class ResponseResult
    {
        
/// <summary>
        
/// 是否已登录
        
/// </summary>
        public bool IsAuthenticated { getset; }

        
/// <summary>
        
/// 是否执行成功
        
/// </summary>
        public bool IsSuccess { getset; }

        
/// <summary>
        
/// 登录账号
        
/// </summary>
        public string Identity { getset; }

        
/// <summary>
        
/// 执行结果
        
/// </summary>
        public object Result { getset; }
    }

 

  接着,编写HomeController:

  

    [HandleError]
    
public class HomeController : Controller
    {
        [Authorize]
        
public ActionResult Index()
        {
            
return Json(new ResponseResult
            {
                Result 
= "登陆成功",
                IsAuthenticated 
= true,
                IsSuccess 
= true,
                Identity 
= this.User.Identity.Name
            }, 
"text/html", JsonRequestBehavior.AllowGet);
        }

        
public ActionResult LogOn()
        {
            
return Json(new ResponseResult
            {
                Result 
= "您尚未登录",
                IsSuccess 
= true
            }, 
"text/html", JsonRequestBehavior.AllowGet);
        }

        
public ActionResult Register(string account, string password)
        {
            
if (account == "liudong" && password == "123")
            {
                FormsAuthentication.SetAuthCookie(account, 
false);
                
return Json(new ResponseResult
                {
                    Result 
= "登录成功",
                    IsSuccess 
= true,
                    IsAuthenticated 
= true,
                    Identity 
= account
                }, 
"text/html", JsonRequestBehavior.AllowGet);
            }
            
else
            {
                
return Json(new ResponseResult
                {
                    Result 
= "用户名或密码错误",
                }, 
"text/html", JsonRequestBehavior.AllowGet);
            }
        }

 

  Index Action为登陆认证后才能访问的Action。

  LogOn Action为未登陆时跳转的Action。

  Register Action为登陆Action,用户名和密码正确后就保存Form验证的Cookie。

 

  然后,在Web.config中配置Form验证配置

 

<authentication mode="Forms">
      
<forms loginUrl="~/Home/LogOn" timeout="2880" />
</authentication>


  最后,配置IIS,部署ASP.NET MV网站,如图2.1所示。

 图2.1

 

  三、Android客户端

   首先,编写一个调用Http请求的类。

  

package ld.com.authorize;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;

import org.apache.http.client.CookieStore;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.AbstractHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;

import android.util.Log;

public abstract class HttpHelper {

    
private final static String TAG = "HttpHelper";
    
private final static String SERVER_URL = "http://192.168.1.104:180/Home/";

    
private static CookieStore cookieStore;

    
public static String invoke(String actionName, List<NameValuePair> params) {
        String result 
= null;
        
try {
            String url 
= SERVER_URL + actionName + "/";
            Log.d(TAG, 
"url is" + url);

            HttpPost httpPost 
= new HttpPost(url);
            
if (params != null && params.size() > 0) {
                HttpEntity entity 
= new UrlEncodedFormEntity(params, "UTF-8");
                httpPost.setEntity(entity);
            }

            DefaultHttpClient httpClient 
= new DefaultHttpClient();

            
// 添加Cookie
            if (cookieStore != null) {
                httpClient.setCookieStore(cookieStore);
            }

            HttpResponse httpResponse 
= httpClient.execute(httpPost);

            StringBuilder builder 
= new StringBuilder();
            BufferedReader reader 
= new BufferedReader(new InputStreamReader(
                    httpResponse.getEntity().getContent()));
            
for (String s = reader.readLine(); s != null; s = reader.readLine()) {
                builder.append(s);
            }
            result 
= builder.toString();
            Log.d(TAG, 
"result is ( " + result + " )");

            
// 保存Cookie
            cookieStore = ((AbstractHttpClient) httpClient).getCookieStore();
        } 
catch (Exception e) {
            Log.e(TAG, e.toString());
        }
        Log.d(TAG, 
"over");
        
return result;
    }

    
public static String invoke(String actionName) {
        
return invoke(actionName, null);
    }
}

 

    注意的是,需要存储一个全局的Cookie,在每次调用前添加上去,再在调用j结束后保存它。

 

  接着,添加两个布局文件:

  

<?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:text="账号" android:layout_width="fill_parent"
        android:layout_height
="20dip" />

    
<EditText android:layout_width="fill_parent" android:hint="请输入账号"
        android:layout_height
="40dip" android:id="@+id/edtAccount" />

    
<TextView android:text="密码" android:layout_width="fill_parent"
        android:layout_height
="20dip" />

    
<EditText android:layout_width="fill_parent" android:hint="请输入密码"
        android:password
="true" android:layout_height="40dip" android:id="@+id/edtPassword" />

    
<Button android:text="登录" android:layout_width="fill_parent"
        android:layout_height
="40dip" android:id="@+id/btnLogon" />
</LinearLayout>

 

 

<?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">

    
<Button android:text="调用" android:id="@+id/btnInvoke"
        android:layout_width
="fill_parent" android:layout_height="wrap_content" />

</LinearLayout>

 

   然后、编写登陆和主Activity

 

package ld.com.authorize;

import java.util.ArrayList;
import java.util.List;

import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class LogonActivity extends Activity {

    
private final String TAG = this.getClass().getSimpleName();

    
private EditText edtAccount;
    
private EditText edtPassword;

    
private Button btnLogon;

    
/** Called when the activity is first created. */
    @Override
    
public void onCreate(Bundle savedInstanceState) {
        
super.onCreate(savedInstanceState);
        setContentView(R.layout.logon);

        edtAccount 
= (EditText) this.findViewById(R.id.edtAccount);
        edtPassword 
= (EditText) this.findViewById(R.id.edtPassword);

        btnLogon 
= (Button) this.findViewById(R.id.btnLogon);

        setButtonOnClick();
    }

    
private void setButtonOnClick() {
        
this.btnLogon.setOnClickListener(new OnClickListener() {

            @Override
            
public void onClick(View v) {
                
// TODO Auto-generated method stub
                AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {

                    
private ProgressDialog progressDialog;

                    @Override
                    
protected void onPostExecute(String result) {
                        
// TODO Auto-generated method stub
                        
// super.onPostExecute(result);
                        progressDialog.cancel();
                        Log.d(TAG, result);
                        
try {
                            JSONObject json 
= new JSONObject(result);
                            String msg 
= json.getString("Result");
                            
// 是否登录
                            if (json.getBoolean("IsSuccess")) {
                                Toast.makeText(LogonActivity.
this, msg,
                                        Toast.LENGTH_SHORT).show();

                                
// 跳转登录Activity
                                Intent intent = new Intent();
                                intent.setClass(LogonActivity.
this,
                                        MainActivity.
class);
                                LogonActivity.
this.startActivity(intent);
                            } 
else {
                                Toast.makeText(LogonActivity.
this, msg,
                                        Toast.LENGTH_SHORT).show();
                            }
                        } 
catch (JSONException e) {
                            
// TODO Auto-generated catch block
                            Log.e(TAG, e.toString());
                        }
                    }

                    @Override
                    
protected void onPreExecute() {
                        
// TODO Auto-generated method stub
                        super.onPreExecute();
                        progressDialog 
= new ProgressDialog(LogonActivity.this);
                        progressDialog.setCancelable(
false);
                        progressDialog
                                .setProgressStyle(ProgressDialog.STYLE_SPINNER);
                        progressDialog.setTitle(
"登录中,请稍后...");
                        progressDialog.show();
                    }

                    @Override
                    
protected String doInBackground(Void... arg0) {
                        
// TODO Auto-generated method stub
                        String account = edtAccount.getText().toString();
                        String password 
= edtPassword.getText().toString();
                        List
<NameValuePair> params = new ArrayList<NameValuePair>();
                        params.add(
new BasicNameValuePair("account", account));
                        params.add(
new BasicNameValuePair("password", password));

                        
try {
                            
return HttpHelper.invoke("Register", params);
                        } 
catch (Exception e) {
                            Log.e(TAG, e.toString());
                            
return null;
                        }
                    }
                };
                task.execute();
            }
        });
    }
}

 

 

 

package ld.com.authorize;

import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity {

    
private final String TAG = this.getClass().getSimpleName();

    
private Button btnInvoke;

    
/** Called when the activity is first created. */
    @Override
    
public void onCreate(Bundle savedInstanceState) {
        
super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        btnInvoke 
= (Button) this.findViewById(R.id.btnInvoke);

        setInvokeOnClick();
    }

    
private void setInvokeOnClick() {
        btnInvoke.setOnClickListener(
new OnClickListener() {

            @Override
            
public void onClick(View v) {
                
// TODO Auto-generated method stub
                AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {

                    
private ProgressDialog progressDialog;

                    @Override
                    
protected void onPostExecute(String result) {
                        
// TODO Auto-generated method stub
                        
// super.onPostExecute(result);
                        progressDialog.cancel();
                        Log.d(TAG, result);
                        
try {
                            JSONObject json 
= new JSONObject(result);
                            
// 是否登录
                            if (json.getBoolean("IsAuthenticated")) {
                                String msg 
= json.getString("Identity"+ ":"
                                        
+ json.getString("Result");
                                Toast.makeText(MainActivity.
this, msg,
                                        Toast.LENGTH_SHORT).show();
                            } 
else {
                                Toast.makeText(MainActivity.
this,
                                        json.getString(
"Result"),
                                        Toast.LENGTH_SHORT).show();

                                
// 跳转登录Activity
                                Intent intent = new Intent();
                                intent.setClass(MainActivity.
this,
                                        LogonActivity.
class);                                
                                MainActivity.
this.startActivity(intent);
                            }
                        } 
catch (JSONException e) {
                            
// TODO Auto-generated catch block
                            Log.e(TAG, e.toString());
                        }
                    }

                    @Override
                    
protected void onPreExecute() {
                        
// TODO Auto-generated method stub
                        super.onPreExecute();
                        progressDialog 
= new ProgressDialog(MainActivity.this);
                        progressDialog.setCancelable(
false);
                        progressDialog
                                .setProgressStyle(ProgressDialog.STYLE_SPINNER);
                        progressDialog.setTitle(
"调用中,请稍后...");
                        progressDialog.show();
                    }

                    @Override
                    
protected String doInBackground(Void... arg0) {
                        
// TODO Auto-generated method stub
                        try {
                            
return HttpHelper.invoke("Index");
                        } 
catch (Exception e) {
                            Log.e(TAG, e.toString());
                            
return null;
                        }
                    }

                };
                task.execute();
            }
        });
    }
}

 

  最后,设置访问权限:<uses-permission android:name="android.permission.INTERNET" />

  

  四、运行结果

  1.进入主MainActivity,图4.1.1所示。

图4.1.1

 

  2.调用Http请求,图4.2.1所示。

图4.2.1

 

  3.由于没有登陆,所以跳转到登陆Activity,图4.3.1所示。

图4.3.1

 

  4.故意输入错误密码使其登陆失败,图4.4.1所示。

图4.4.1

 

  5.输入正确的密码后跳转到主Activity,如图4.5.1所示。

图4.5.1

 

  6.再一次调用Http请求,这次是已登陆状态,图4.6.1所示。

图4.6.1

 

 

  代码下载

  作者:刘冬.NET

  出处:http://www.cnblogs.com/GoodHelper/archive/2011/08/19/android_iis_02.html

  欢迎转载,但须保留版权。

 

posted @ 2011-08-19 00:16 冬子哥 阅读(...) 评论(...) 编辑 收藏