天天看點

穩紮穩打Silverlight(22) - 2.0通信之調用WCF服務, 對傳輸資訊做加密

<a href="http://webabcd.blog.51cto.com/1787395/342790" target="_blank">[索引頁]</a>

<a href="http://down.51cto.com/data/100302" target="_blank">[源碼下載下傳]</a>

穩紮穩打Silverlight(22) - 2.0通信之調用WCF服務, 對傳輸資訊做加密

介紹

Silverlight 2.0 調用 WCF 服務,對用戶端與服務端傳輸的消息做加密    

    在 Visual Studio 2008 中使用"添加服務引用"會自動生成代理類。隻支援BasicHttpBinding

線上DEMO

<a href="http://webabcd.blog.51cto.com/1787395/342779">http://webabcd.blog.51cto.com/1787395/342779</a>

示例

clientaccesspolicy.xml

&lt;?xml version="1.0" encoding="utf-8" ?&gt; 

&lt;access-policy&gt; 

        &lt;cross-domain-access&gt; 

                &lt;policy&gt; 

                        &lt;allow-from http-request-headers="*"&gt; 

                                &lt;domain uri="*" /&gt; 

                        &lt;/allow-from&gt; 

                        &lt;grant-to&gt; 

                                &lt;resource path="/" include-subpaths="true" /&gt; 

                        &lt;/grant-to&gt; 

                &lt;/policy&gt; 

        &lt;/cross-domain-access&gt; 

&lt;/access-policy&gt; 

&lt;!-- 

System.Net 命名空間 和 System.Net.Sockets 命名空間的跨域調用,需要在目标域的根目錄下配置政策檔案 

Image 控件 和 MediaElement 控件所通路的跨域位址,不受政策檔案的限制 

HTTP 調用 僅支援 GET 和 POST ,隻有 200(确定) 和 404(未找到) 狀态代碼可用 

同域:同一子域、協定和端口。不符合以上任一條件則為跨域 

Silverlight 與 HTTP/HTTPS 的所有通信均為異步 

關于政策檔案詳見文檔 

--&gt;

1、調用 WCF 服務

WCFService.cs(WCF 服務)

using System; 

using System.Linq; 

using System.Runtime.Serialization; 

using System.ServiceModel; 

using System.ServiceModel.Activation; 

using System.Collections.Generic; 

using System.Text; 

using System.Security.Cryptography; 

using System.IO; 

/// &lt;summary&gt; 

/// 提供 WCF 服務的類 

/// &lt;/summary&gt; 

[ServiceContract] 

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] 

public class WCFService 

        /// &lt;summary&gt; 

        /// 傳回指定的 User 對象(用于示範 Silverlight 調用 WCF 服務) 

        /// &lt;/summary&gt; 

        /// &lt;param name="name"&gt;名字&lt;/param&gt; 

        /// &lt;returns&gt;&lt;/returns&gt; 

        [OperationContract] 

        public User GetUser(string name) 

        { 

                return new User { Name = name, DayOfBirth = new DateTime(1980, 2, 14) }; 

        } 

}

WCF.xaml

&lt;UserControl x:Class="Silverlight20.Communication.WCF" 

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&gt; 

        &lt;StackPanel HorizontalAlignment="Left" Margin="5"&gt; 

                &lt;TextBlock x:Name="lblMsg" /&gt; 

        &lt;/StackPanel&gt; 

&lt;/UserControl&gt;

WCF.xaml.cs

using System.Net; 

using System.Windows; 

using System.Windows.Controls; 

using System.Windows.Documents; 

using System.Windows.Input; 

using System.Windows.Media; 

using System.Windows.Media.Animation; 

using System.Windows.Shapes; 

using Silverlight20.WCFServiceReference; 

using System.Threading; 

namespace Silverlight20.Communication 

        public partial class WCF : UserControl 

                SynchronizationContext _syncContext; 

                /// &lt;summary&gt; 

                /// 示範 Silverlight 調用 WCF 服務 

                /// &lt;/summary&gt; 

                public WCF() 

                { 

                        InitializeComponent(); 

                        // 代理的配置資訊在配置檔案中,UI線程上的異步調用 

                        Demo(); 

                        // 代理的配置資訊在程式中指定,UI線程上的異步調用 

                        Demo2(); 

                        // 背景線程(非UI線程)上的異步調用) 

                        Demo3(); 

                } 

                void Demo() 

                        /*                            

                         * 服務名Client - 系統自動生成的代理類 

                         *         方法名Completed - 調用指定的方法完成後所觸發的事件 

                         *         方法名Async(參數1, 參數2 , object 使用者辨別) - 異步調用指定的方法 

                         *         Abort() - 取消調用 

                         */ 

                        WCFServiceClient client = new WCFServiceClient(); 

                        client.GetUserCompleted += new EventHandler&lt;GetUserCompletedEventArgs&gt;(client_GetUserCompleted); 

                        client.GetUserAsync("webabcd"); 

                void Demo2() 

                        /* 

                         * 服務名Client - 其構造函數可以動态地指定代理的配置資訊(Silverlight 2.0 調用 WCF 隻支援 BasicHttpBinding) 

                        WCFServiceClient client = new WCFServiceClient(new BasicHttpBinding(), new EndpointAddress("http://localhost:3036/WCFService.svc")); 

                        client.GetUserAsync("webabcd2"); 

                void client_GetUserCompleted(object sender, GetUserCompletedEventArgs e) 

                         * 方法名CompletedEventArgs.Error - 該異步操作期間是否發生了錯誤 

                         * 方法名CompletedEventArgs.Result - 異步操作傳回的結果。本例為 User 類型 

                         * 方法名CompletedEventArgs.UserState - 使用者辨別 

                        if (e.Error != null) 

                        { 

                                lblMsg.Text += e.Error.ToString() + "\r\n"; 

                                return; 

                        } 

                        if (e.Cancelled != true) 

                                OutputResult(e.Result); 

                void Demo3() 

                        // UI 線程 

                        _syncContext = SynchronizationContext.Current; 

                         * ChannelFactory&lt;T&gt;.CreateChannel() - 建立 T 類型的信道 

                         * 服務名.Begin方法名() - 背景線程上異步調用指定方法(最後一個參數為 代理對象) 

                        WCFService client = new ChannelFactory&lt;WCFService&gt;(new BasicHttpBinding(), new EndpointAddress("http://localhost:3036/WCFService.svc")).CreateChannel(); 

                        client.BeginGetUser("webabcd3", new AsyncCallback(ResponseCallback), client); 

                private void ResponseCallback(IAsyncResult result) 

                        WCFService client = result.AsyncState as WCFService; 

                        // 服務名.End方法名() - 擷取在背景線程(非UI線程)上異步調用的結果 

                        User user = client.EndGetUser(result); 

                        // 調用 UI 線程 

                        _syncContext.Post(GetResponse, user); 

                private void GetResponse(object state) 

                        OutputResult(state as User); 

                /// 輸出異步調用 WCF 服務的方法後傳回的結果 

                /// &lt;param name="user"&gt;&lt;/param&gt; 

                void OutputResult(User user) 

                        lblMsg.Text += string.Format("姓名:{0};生日:{1}\r\n", 

                                user.Name, 

                                user.DayOfBirth.ToString("yyyy-MM-dd")); 

2、對用戶端與服務端傳輸的消息做加密

        /// 傳回指定的 User 對象(用于示範傳輸資訊的加密/解密) 

        /// &lt;param name="name"&gt;&lt;/param&gt; 

        public User GetUserByCryptography(string name) 

                return new User { Name = Decrypt(name), DayOfBirth = new DateTime(1980, 2, 14) }; 

        /// 解密資料 

        /// &lt;param name="input"&gt;加密後的字元串&lt;/param&gt; 

        /// &lt;returns&gt;加密前的字元串&lt;/returns&gt; 

        public string Decrypt(string input) 

                // 鹽值(與加密時設定的值一緻) 

                string saltValue = "saltValue"; 

                // 密碼值(與加密時設定的值一緻) 

                string pwdValue = "pwdValue"; 

                byte[] encryptBytes = Convert.FromBase64String(input); 

                byte[] salt = Encoding.UTF8.GetBytes(saltValue); 

                AesManaged aes = new AesManaged(); 

                Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(pwdValue, salt); 

                aes.BlockSize = aes.LegalBlockSizes[0].MaxSize; 

                aes.KeySize = aes.LegalKeySizes[0].MaxSize; 

                aes.Key = rfc.GetBytes(aes.KeySize / 8); 

                aes.IV = rfc.GetBytes(aes.BlockSize / 8); 

                // 用目前的 Key 屬性和初始化向量 IV 建立對稱解密器對象 

                ICryptoTransform decryptTransform = aes.CreateDecryptor(); 

                // 解密後的輸出流 

                MemoryStream decryptStream = new MemoryStream(); 

                // 将解密後的目标流(decryptStream)與解密轉換(decryptTransform)相連接配接 

                CryptoStream decryptor = new CryptoStream(decryptStream, decryptTransform, CryptoStreamMode.Write); 

                // 将一個位元組序列寫入目前 CryptoStream (完成解密的過程) 

                decryptor.Write(encryptBytes, 0, encryptBytes.Length); 

                decryptor.Close(); 

                // 将解密後所得到的流轉換為字元串 

                byte[] decryptBytes = decryptStream.ToArray(); 

                string decryptedString = UTF8Encoding.UTF8.GetString(decryptBytes, 0, decryptBytes.Length); 

                return decryptedString; 

Cryptography.xaml

&lt;UserControl x:Class="Silverlight20.Communication.Cryptography" 

Cryptography.xaml.cs

        public partial class Cryptography : UserControl 

                public Cryptography() 

                        client.GetUserByCryptographyCompleted+=new EventHandler&lt;GetUserByCryptographyCompletedEventArgs&gt;(client_GetUserByCryptographyCompleted); 

                        client.GetUserByCryptographyAsync(Encrypt("webabcd")); 

                void client_GetUserByCryptographyCompleted(object sender, GetUserByCryptographyCompletedEventArgs e) 

                                lblMsg.Text += string.Format("姓名:{0};生日:{1}\r\n", 

                                        e.Result.Name, 

                                        e.Result.DayOfBirth.ToString("yyyy-MM-dd")); 

                /// 加密資料 

                /// &lt;param name="input"&gt;加密前的字元串&lt;/param&gt; 

                /// &lt;returns&gt;加密後的字元串&lt;/returns&gt; 

                private string Encrypt(string input) 

                        // 鹽值 

                        string saltValue = "saltValue"; 

                        // 密碼值 

                        string pwdValue = "pwdValue"; 

                        byte[] data = UTF8Encoding.UTF8.GetBytes(input); 

                        byte[] salt = UTF8Encoding.UTF8.GetBytes(saltValue); 

                        // AesManaged - 進階加密标準(AES) 對稱算法的管理類 

                        AesManaged aes = new AesManaged(); 

                        // Rfc2898DeriveBytes - 通過使用基于 HMACSHA1 的僞随機數生成器,實作基于密碼的密鑰派生功能 (PBKDF2 - 一種基于密碼的密鑰派生函數) 

                        // 通過 密碼 和 salt 派生密鑰 

                        Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(pwdValue, salt); 

                         * AesManaged.BlockSize - 加密操作的塊大小(機關:bit) 

                         * AesManaged.LegalBlockSizes - 對稱算法支援的塊大小(機關:bit) 

                         * AesManaged.KeySize - 對稱算法的密鑰大小(機關:bit) 

                         * AesManaged.LegalKeySizes - 對稱算法支援的密鑰大小(機關:bit) 

                         * AesManaged.Key - 對稱算法的密鑰 

                         * AesManaged.IV - 對稱算法的密鑰大小 

                         * Rfc2898DeriveBytes.GetBytes(int 需要生成的僞随機密鑰位元組數) - 生成密鑰 

                        aes.BlockSize = aes.LegalBlockSizes[0].MaxSize; 

                        aes.KeySize = aes.LegalKeySizes[0].MaxSize; 

                        aes.Key = rfc.GetBytes(aes.KeySize / 8); 

                        aes.IV = rfc.GetBytes(aes.BlockSize / 8); 

                        // 用目前的 Key 屬性和初始化向量 IV 建立對稱加密器對象 

                        ICryptoTransform encryptTransform = aes.CreateEncryptor(); 

                        // 加密後的輸出流 

                        MemoryStream encryptStream = new MemoryStream(); 

                        // 将加密後的目标流(encryptStream)與加密轉換(encryptTransform)相連接配接 

                        CryptoStream encryptor = new CryptoStream(encryptStream, encryptTransform, CryptoStreamMode.Write); 

                        // 将一個位元組序列寫入目前 CryptoStream (完成加密的過程) 

                        encryptor.Write(data, 0, data.Length); 

                        encryptor.Close(); 

                        // 将加密後所得到的流轉換成位元組數組,再用Base64編碼将其轉換為字元串 

                        string encryptedString = Convert.ToBase64String(encryptStream.ToArray()); 

                        return encryptedString; 

                }                 

OK

      本文轉自webabcd 51CTO部落格,原文連結:http://blog.51cto.com/webabcd/343130,如需轉載請自行聯系原作者

繼續閱讀