Android 用戶遠程驗證----XFIRE,BASE64,KSOAP,WEBSERVICE

在Android開發過程當中,不必定都用本地文件系統或本地數據庫SQLite,好比QQ,用戶的賬號數據都存儲遠程服務器上。而訪問遠程數據庫有不少種方式,好比HTTPCLIENT,WEBSERVICE,SOCKET等多種方式,即分別爲http通訊,webservice(Web服務通訊),還有socket套接字通訊等等,限於篇幅,本文我只講解講一下webservice方式。其餘方式,在其餘的文檔再講。  
 
第一步,在要Android中使用web服務,咱們得先配置好web服務 器端。我使用了java webservice---XFIRE框架。
 
相信XFire的優勢不用多說,google,百度一下就知道了。我這裏主要講解配置過程。配置一個簡單的webservice,相信配置了該webservice。
 
xfire使用接口和接口實現類來實現遠程方法提拱。這樣能夠將接口公佈給客戶端,但Android提拱了ksoap框架類,一種全新的實現方式,就不須要使用遠程接口。只要配置好相關參數和方法便可。
 
廢話很少說了,帖上代碼:
 
//將 POJO 發佈成 Web 服務:有兩種方法,接口和實現類是其中之一    
public interface IAccount {    
    public int account(int x,int y);     
        
    public String helloWorld(String str);    
        
    //訪問mysql數據庫    
    public int login(String username,String password);    
        
}  
 
這個是接口類,再帖出實現類。
 
public class AccountImp implements IAccount {    
    public int account(int x, int y) {    
        // TODO Auto-generated method stub    
        return x*y;     
    }    
    public String helloWorld(String str) {    
        // TODO Auto-generated method stub    
        return str;    
    }    
    public int login(String username, String password) {    
        // TODO Auto-generated method stub    
        String decodeusername="",decodepassword="";    
        //對密碼進行解密碼    
        try {    
             decodeusername=new String(com.base.encry.decry.app.Base64.decode(username));    
             decodepassword=new String(com.base.encry.decry.app.Base64.decode(password));    
        } catch (UnsupportedEncodingException e) {    
            // TODO Auto-generated catch block    
            e.printStackTrace();    
        }    
        ConnDB connDB=new ConnDB();    
        return connDB.login(decodeusername, decodepassword);    
            
            
    }    
}  
 
下面我着重講一下login方法,它裏面有兩個類提拱方法以實現其功能。
 
本篇文章來源於 Linux公社網站(www.linuxidc.com)  原文連接:http://www.linuxidc.com/Linux/2011-04/35011.htm
Base64算法相信你們都比較熟悉吧,dt.jar已經提拱了具體的實現細節。你能夠查閱相關文檔和源碼,
 
這裏爲了讓你們費時費力,我貼上代碼。
 
public class Base64 {    
    private static char[] base64EncodeChars = new char[] { 'A', 'B', 'C', 'D',    
            'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',    
            'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',    
            'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',    
            'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3',    
            '4', '5', '6', '7', '8', '9', '+', '/' };    
    private static byte[] base64DecodeChars = new byte[] { -1, -1, -1, -1, -1,    
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,    
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,    
            -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59,    
            60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,    
            10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1,    
            -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,    
            38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1,    
            -1, -1 };    
        
        
    public static void main(String[] args) {    
        String string="徐忠明";    
        String encodeStr=encode(string.getBytes());    
        byte[] bytesStr=null;    
        try {    
             bytesStr=decode(encodeStr);    
        } catch (UnsupportedEncodingException e) {    
            // TODO Auto-generated catch block    
            e.printStackTrace();    
        }    
            
        System.out.println(encodeStr);    
        System.out.println(new String(bytesStr));    
            
    }    
    // 編碼    
    public static String encode(byte[] data) {    
        StringBuffer sb = new StringBuffer();    
        int len = data.length;    
        int i = 0;    
        int b1, b2, b3;    
        while (i < len) {    
            b1 = data[i++] & 0xff;    
            if (i == len) {    
                sb.append(base64EncodeChars[b1 >>> 2]);    
                sb.append(base64EncodeChars[(b1 & 0x3) << 4]);    
                sb.append("==");    
                break;    
            }    
            b2 = data[i++] & 0xff;    
            if (i == len) {    
                sb.append(base64EncodeChars[b1 >>> 2]);    
                sb.append(base64EncodeChars[((b1 & 0x03) << 4)    
                        | ((b2 & 0xf0) >>> 4)]);    
                sb.append(base64EncodeChars[(b2 & 0x0f) << 2]);    
                sb.append("=");    
                break;    
            }    
            b3 = data[i++] & 0xff;    
            sb.append(base64EncodeChars[b1 >>> 2]);    
            sb.append(base64EncodeChars[((b1 & 0x03) << 4)    
                    | ((b2 & 0xf0) >>> 4)]);    
            sb.append(base64EncodeChars[((b2 & 0x0f) << 2)    
                    | ((b3 & 0xc0) >>> 6)]);    
            sb.append(base64EncodeChars[b3 & 0x3f]);    
        }    
        return sb.toString();    
    }    
    // 解碼    
    public static byte[] decode(String str) throws UnsupportedEncodingException {    
        StringBuffer sb = new StringBuffer();    
        byte[] data = str.getBytes("US-ASCII");    
        int len = data.length;    
        int i = 0;    
        int b1, b2, b3, b4;    
        while (i < len) {    
            /* b1 */   
            do {    
                b1 = base64DecodeChars[data[i++]];    
            } while (i < len && b1 == -1);    
            if (b1 == -1)    
                break;    
            /* b2 */   
            do {    
                b2 = base64DecodeChars[data[i++]];    
            } while (i < len && b2 == -1);    
            if (b2 == -1)    
                break;    
            sb.append((char) ((b1 << 2) | ((b2 & 0x30) >>> 4)));    
            /* b3 */   
            do {    
                b3 = data[i++];    
                if (b3 == 61)    
                    return sb.toString().getBytes("iso8859-1");    
                b3 = base64DecodeChars[b3];    
            } while (i < len && b3 == -1);    
            if (b3 == -1)    
                break;    
            sb.append((char) (((b2 & 0x0f) << 4) | ((b3 & 0x3c) >>> 2)));    
            /* b4 */   
            do {    
                b4 = data[i++];    
                if (b4 == 61)    
                    return sb.toString().getBytes("iso8859-1");    
                b4 = base64DecodeChars[b4];    
            } while (i < len && b4 == -1);    
            if (b4 == -1)    
                break;    
            sb.append((char) (((b3 & 0x03) << 6) | b4));    
        }    
        return sb.toString().getBytes("iso8859-1");    
    }    
}  
 
這段代碼能夠也能夠在Android客戶端重用,Android端負責加密碼,而XFire服務器端負責解密,這樣作是爲了安全性着想。
你想一想若是不加密碼,直接將賬號和密碼在網絡上傳輸,裸露在Internet中,那是多麼的危險,這是用了通用的Base64加密解密碼算法也不必定安全。我只是作一個試笵,你們能夠根據自已須要來選用自已的加密碼算法。好比md5,SHA等等。
 
還有就是訪問數據庫的細節,在這裏只用了原始了JDBC,固然能夠擴展成Hibernate,iBatis.爲求簡單原始。帖上以下代碼:
 
package com.db.app;    
import java.sql.Connection;    
import java.sql.DriverManager;    
import java.sql.PreparedStatement;    
import java.sql.ResultSet;    
import com.constants.util.Constants;    
import com.sun.corba.se.impl.orbutil.closure.Constant;    
public class ConnDB {    
        
        
    public ConnDB(){    
            
    }    
        
    public Connection getConnection(){    
        Connection conn=null;    
        try{    
            Class.forName("com.mysql.jdbc.Driver");    
             conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","123456");    
        }catch (Exception e) {    
            // TODO: handle exception    
        }    
            
        return conn;    
    }    
        
    /**   
     * 功能:用戶登錄驗證   
     * @param username  用戶名   
     * @param password  密碼   
     * @return   
     * 首先判斷是否存在該用戶,若是不存在,則返回false,   
     * 若是存在該用戶,則判斷密碼是否正確,若是不正確,則返回密碼輸入錯誤   
     */   
    public int login(String username,String password){    
    try{    
                
                
            PreparedStatement ps=getConnection().prepareStatement("select * from t_customer where account=?");    
            ps.setString(1, username);    
            ResultSet rs=ps.executeQuery();    
            if(!rs.next()){    
                return  Constants.INVALID_NAME;//"該用戶不存在,請輸入你的用戶名";    
            }    
                
            ps=getConnection().prepareStatement("select * from t_customer where account=? and password=?");    
            ps.setString(1, username);    
            ps.setString(2, password);    
            rs=ps.executeQuery();    
            if (!rs.next()) {    
                return Constants.INVALID_PASSWORD;//"密碼輸入錯誤,請覈對";    
            }    
            else   
                return  Constants.VALID_USERNAME_PASSWORD;//"驗證經過";    
                
        }catch(Exception evt){    
            evt.printStackTrace();    
            return  Constants.INVALID_DATABASE;//"數據庫出現異常,請重試";    
        }    
    }    
        
    public static void main(String[] args) {    
        ConnDB connDB=new ConnDB();    
        System.out.println(connDB.login("fda", "123"));    
        System.out.println(connDB.login("001", "123456"));    
        System.out.println(connDB.login("001", "123"));    
    }    
}  
 
不用多說,地球均可以看懂它們。呵呵。
固然要將這個類中的方法發佈出去還要有Services.xml文件,這個文件的存儲路徑爲:WebServices目錄下。即項目的根目錄下面。
 
代碼以下所示:
 
<?xml version="1.0" encoding="UTF-8"?>   
<beans xmlns="http://xfire.codehaus.org/config/1.0">   
    <!-- 服務一:簡單計算,直接輸出 -->   
    <service>   
        <name>MyService</name>   
        <serviceClass>test.IAccount</serviceClass>   
        <implementationClass>test.AccountImp</implementationClass>   
        <mce:style><!--   
wrapped   
--></mce:style><style mce_bogus="1">wrapped</style>   
        <use>literal</use>   
        <scope>application</scope>   
        <namespace>http://Android.googlepages.com/</namespace>   
    </service>   
    <!--服務二:訪問數據庫,功能:由用戶賬號直接獲得其密碼,若是賬號不對則提示從新輸入     
    <service>   
        <name>MyDbService</name>   
        <serviceClass>test.IConnDb</serviceClass>   
        <implementationClass>test.ConnDbImp</implementationClass>   
        <mce:style><!--   
wrapped   
--></mce:style><style mce_bogus="1">wrapped</style>   
        <use>literal</use>   
        <scope>application</scope>   
        <namespace>http://Android.googlepages.com/</namespace>   
    </service>   
     -->   
</beans>  
 
我爲了簡單,寫只了一個MyService服務。你能夠根據自已須要添加其餘的服務。
 
固然運行這個還要有一些JAR包的支持。我附圖,以下所示:

接下來咱們看看Android客戶端。要使用webservice框架,咱們要在classpath中導入D:/學習專題/Android專題/Android例程專題(自定收集)/Android WebService/android/android webservice/ksoap2_android_src.zip。html

這樣才能夠運行webservicejava

貼上代碼:mysql

  1. package com.cn.blogs.ksoap.app;
  2. import java.io.IOException;
  3. import org.kobjects.base64.Base64;
  4. import org.ksoap2.SoapEnvelope;
  5. import org.ksoap2.serialization.SoapObject;
  6. import org.ksoap2.serialization.SoapPrimitive;
  7. import org.ksoap2.serialization.SoapSerializationEnvelope;
  8. import org.ksoap2.transport.AndroidHttpTransport;
  9. import org.ksoap2.transport.HttpTransportSE;
  10. import org.xmlpull.v1.XmlPullParserException;
  11. public class MyWebServiceHelper {
  12.  // WSDL文檔中的命名空間
  13.  private static final String targetNameSpace ="http://Android.googlepages.com/";
  14.  // WSDL文檔中的URL
  15.  private static final String WSDL ="http://10.10.178.70:8888/WSDLApp/services/MyService";
  16.  // 須要調用的方法名(得到Myervices中的helloWorld方法)
  17.  private static final String getHelloworld = "helloWorld";
  18.  //須要調用的方法名(得到Myervices中的login方法)
  19.  private static final String getLogin="login";
  20.  /********
  21. * 得到自定義WebService XFire框架信息
  22. *
  23. * @return
  24. */
  25.  public static void main(String[] args) {
  26. MyWebServiceHelper webServiceHelper=newMyWebServiceHelper();
  27.  // System.out.println(webServiceHelper.getHelloworldStr("\"你好,ksoap webservice 框架\""));
  28. System.out.println(webServiceHelper.getFlagFromDBCust("001","123"));
  29. }
  30.  public String getHelloworldStr(String string) {
  31. String str = "";
  32. SoapObject soapObject = new SoapObject(targetNameSpace,
  33. getHelloworld);
  34. soapObject.addProperty("str", string);
  35.  //調用的方法參數與參數值(根據具體須要可選可不選)
  36. SoapSerializationEnvelope envelope = newSoapSerializationEnvelope(
  37. SoapEnvelope.VER11);
  38. envelope.dotNet = false//不使用dotnet webservice;
  39. envelope.setOutputSoapObject(soapObject);//envelope.bodyOut=request;
  40. AndroidHttpTransport httpTranstation = newAndroidHttpTransport(WSDL);
  41.  //HttpTransportSE httpTranstation=new HttpTransportSE(WSDL);
  42.  try {
  43. httpTranstation.call(targetNameSpace + getHelloworld, envelope);
  44. SoapPrimitive result = (SoapPrimitive ) envelope.getResponse();
  45.  // 下面對結果進行解析,結構相似json對象
  46.  // str=(String) result.getProperty(6).toString();
  47. // int count = result.getPropertyCount();
  48. // for (int index = 0; index < count; index++) {
  49. // provinces.add(result.getProperty(index).toString());
  50. // System.out.println(result.getProperty(index).toString());
  51. // }
  52. str=result.toString();
  53. catch (IOException e) {
  54.  // TODO Auto-generated catch block
  55. e.printStackTrace();
  56. catch (XmlPullParserException e) {
  57.  // TODO Auto-generated catch block
  58. e.printStackTrace();
  59. }
  60.  return str;
  61. }
  62.  public String getFlagFromDBCust(String username,String password) {
  63. String str = "";
  64. SoapObject soapObject = newSoapObject(targetNameSpace,getLogin);
  65.  //給賬號和密碼加密碼
  66. String encodeUsername=Base64.encode(username.getBytes());
  67. String encodePassword=Base64.encode(password.getBytes());
  68. soapObject.addProperty("username", encodeUsername);
  69. soapObject.addProperty("password",encodePassword);
  70.  //調用的方法參數與參數值(根據具體須要可選可不選)
  71. SoapSerializationEnvelope envelope = newSoapSerializationEnvelope(SoapEnvelope.VER11);
  72. envelope.dotNet = false;
  73. envelope.setOutputSoapObject(soapObject);
  74. HttpTransportSE httpTranstation=newHttpTransportSE(WSDL);
  75.  //或者AndroidHttpTransport httpTranstation = new AndroidHttpTransport(WSDL);
  76.  try {
  77. httpTranstation.call(targetNameSpace + getLogin, envelope);
  78. SoapObject result = (SoapObject ) envelope.bodyIn;//getResponse();
  79.  //
  80. str=(String) result.getProperty(0).toString();
  81.  // 也能夠經過下面方式得到str
  82.  // SoapPrimitive result = (SoapPrimitive ) envelope.getResponse();
  83.  // str=result.toString();
  84.  // 直指value字符串值
  85. catch (IOException e) {
  86.  // TODO Auto-generated catch block
  87. e.printStackTrace();
  88. catch (XmlPullParserException e) {
  89.  // TODO Auto-generated catch block
  90. e.printStackTrace();
  91. }
  92.  return str;
  93. }
  94. }

 

能夠看到Base64又在這裏出現了,主要是爲了加密碼,而後傳送給服務器端linux

注意:private static final String WSDL = "http://10.10.178.70:8888/WSDLApp/services/MyService";android

而不要在後面加上?wsdl,若是加上了就錯誤了。程序員

 
 裏面的代碼。你能夠下載源碼進行解讀。

我來提一點兩種方式得到:resultweb

 

HttpTransportSE httpTranstation=new HttpTransportSE(WSDL);
//或者AndroidHttpTransport httpTranstation = new AndroidHttpTransport(WSDL);算法

這兩種均可以sql

而後還有數據庫


httpTranstation.call(targetNameSpace + getLogin, envelope);
SoapObject result = (SoapObject ) envelope.bodyIn;//getResponse();
//

str=(String) result.getProperty(0).toString();

// 也能夠經過下面方式得到str
// SoapPrimitive result = (SoapPrimitive ) envelope.getResponse();
// str=result.toString();
// 直指value字符串值

這兩種方式,我在測試的過程當中都經過。提拱多種方式,讓程序員靈活使用。

下面我貼上Activity子類MainActivity

  1. package com.net.connect.app;
  2. import Android.app.Activity;
  3. import Android.content.Intent;
  4. import Android.os.Bundle;
  5. import Android.view.View;
  6. import Android.view.View.OnClickListener;
  7. import Android.view.ViewGroup.LayoutParams;
  8. import Android.widget.Button;
  9. import Android.widget.EditText;
  10. import Android.widget.LinearLayout;
  11. import Android.widget.TextView;
  12. import Android.widget.Toast;
  13. import com.cn.blogs.ksoap.app.MyWebServiceHelper;
  14. /****
  15. * http://www.cnblogs.com/zhangdongzi/archive/2011/04/19/2020688.html
  16. *
  17. * @author mingg
  18. *
  19. */
  20. public class LoginActivity extends Activity {
  21.  /** Called when the activity is first created. */
  22. TextView txtUsername,txtPassword;
  23. EditText etUsername,etPassword;
  24. Button loginButton,exitButton;
  25.  @Override
  26.  public void onCreate(Bundle savedInstanceState) {
  27.  super.onCreate(savedInstanceState);
  28.  //setContentView(R.layout.main);
  29. constructLayout();
  30. }
  31.  private void constructLayout() {
  32. LinearLayout.LayoutParams lp = newLinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
  33. LinearLayout.LayoutParams controlpl = newLinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
  34. LinearLayout ll = new LinearLayout(this);
  35. ll.setOrientation(LinearLayout.VERTICAL);
  36. txtUsername = new TextView(this);
  37. txtUsername.setText("賬號:\t");
  38. etUsername = new EditText(this);
  39. txtPassword = new TextView(this);
  40. txtPassword.setText("密碼:\t");
  41. etPassword = new EditText(this);
  42. loginButton=new Button(this);
  43. loginButton.setText("登錄");
  44. loginButton.setOnClickListener(new OnClickListener() {
  45.  @Override
  46.  public void onClick(View v) {
  47.  // TODO Auto-generated method stub
  48. String userValue=etUsername.getText().toString();
  49. String passValue=etPassword.getText().toString();
  50.  if(userValue.length()==0 || passValue.length()==0){
  51. Toast.makeText(LoginActivity.this"賬號和密碼不能爲空,請輸入", Toast.LENGTH_LONG).show();
  52.  return;
  53. }
  54.  //調用自已寫的webService
  55. MyWebServiceHelper webServiceHelper=newMyWebServiceHelper();
  56.  intflag=Integer.parseInt(webServiceHelper.getFlagFromDBCust(userValue,passValue));
  57. String content="";
  58.  switch (flag) {
  59.  case 1 :
  60. content="該用戶不存在,請輸入你的用戶名";
  61. Toast.makeText(LoginActivity.this, content, Toast.LENGTH_LONG).show();
  62.  break;
  63.  case 2 :
  64. content="密碼輸入錯誤,請覈對";
  65. Toast.makeText(LoginActivity.this, content, Toast.LENGTH_LONG).show();
  66.  break;
  67.  case 3 :
  68. content="數據庫出現異常,請重試";
  69. Toast.makeText(LoginActivity.this, content, Toast.LENGTH_LONG).show();
  70.  break;
  71.  case 4 :
  72. content="驗證經過";
  73. Toast.makeText(LoginActivity.this, content, Toast.LENGTH_LONG).show();
  74.  try {
  75. Thread.currentThread().sleep(1000);
  76. catch (InterruptedException e) {
  77.  // TODO Auto-generated catch block
  78. e.printStackTrace();
  79. }
  80.  //轉到MainActivity
  81. Intent intent=new Intent();
  82. intent.setClass(LoginActivity.this, MainActivity.class);
  83. startActivity(intent);
  84.  break;
  85.  default:
  86.  break;
  87. }
  88. }
  89. });
  90. exitButton=new Button(this);
  91. exitButton.setText("退出");
  92. exitButton.setOnClickListener(new OnClickListener() {
  93.  @Override
  94.  public void onClick(View v) {
  95.  // TODO Auto-generated method stub
  96. LoginActivity.this.finish();
  97.  //退出
  98. }
  99. });
  100. ll.addView(txtUsername, controlpl);
  101. ll.addView(etUsername, controlpl);
  102. ll.addView(txtPassword, controlpl);
  103. ll.addView(etPassword, controlpl);
  104. ll.addView(loginButton, controlpl);
  105. ll.addView(exitButton, controlpl);
  106. addContentView(ll, lp);
  107. }
  108. }

 

最終運行效果以下所示:

有點小問題,能夠在開發中更正。

最終不要忘了加 internet permmition

AndroidManifest.xml中加入<uses-permission android:name="android.permission.INTERNET" />

相關文章
相關標籤/搜索