開發共享軟件,傳統的是采用注冊碼驗證方式,這種方式是大多數共享軟件采用的方式,另外還有一種常見的驗證方式,就是通過網絡授權認證的方式,這種方式通過在程序中調用服務器的服務進行。一般具有驗證用戶名可用、注冊新用戶、用戶登錄認證、用戶修改密碼等操作,另外還需要配備一個網絡授權入口給管理員對注冊的用戶進行授權控制。
這個是為了進行網絡授權認證搭建的一個簡單的管理后台,用戶在共享軟件客戶端通過調用服務器的服務連接,可以注冊一個新用戶,或者進行登錄獲取身份信息(試用、已注冊、已禁用等狀態),還可以通過服務接口來進行密碼修改,提高安全性及使用合理性。
網絡認證有幾個好處,一是可以不受限於傳統的機器碼限制,可以在多個計算機中登錄使用;二是方便軟件開發者集中管理用戶信息,動態授權或者取消授權用戶的身份信息,還可以獲取更多用戶的信息,以便進行推廣溝通。
開發網絡授權業務后台的時候,需要創建一個服務接口給軟件客戶端進行調用,這個服務接口可以通過創建ashx這樣的處理程序來進行處理,這種類和ASPX頁面處理有些少不同,這個提供更原始的輸出,需要什么輸出什么。
這個處理頁面和傳統的aspx頁面一樣,都接受類似test.aspx?id=1&name=test 這樣的參數,它的處理代碼如下所示。
/// <summary> /// 用戶測試賬號可用性、注冊新用戶、登錄驗證、修改密碼等操作業務處理類 /// </summary> [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] public class UserAction : IHttpHandler { public void ProcessRequest(HttpContext context) { //context.Response.ContentType = "text/plain"; //context.Response.Write("Hello World"); context.Request.ContentEncoding = Encoding.Default ; string action = context.Request["action"]; string usr = context.Request["usr"]; string password = context.Request["pass"]; string machineCode = context.Request["code"];
通過獲取參數的內容,我們就可以進行不同的業務處理,這里我使用了一個Action的標志,用來區分是做什么操作的。
string action = context.Request["action"]; string usr = context.Request["usr"]; string password = context.Request["pass"]; string machineCode = context.Request["code"]; bool result = false; switch (action) { case "r"://檢測注冊 UserAction.ashx?action=r&usr=&pass=&code= string reg = BLLFactory<SoftwareRegister>.Instance.CheckRegisterd(usr, password, machineCode); context.Response.ContentType = "text/plain"; context.Response.Write(reg); break;
以上就是執行一個檢測用戶是否注冊的操作代碼,如果授權注冊了,返回true,如果用戶登錄成功但沒有授權,返回False,其他錯誤返回字符串描述。具體的BLLFactory<SoftwareRegister>.Instance.CheckRegisterd邏輯處理代碼如下所示。
public string CheckRegisterd(string username, string passwod, string code) { bool result = VerifyUser(username, passwod, code); if (result) { string condition = string.Format(" Username='{0}' and IsForbid <> true", username); SoftwareRegisterInfo info = base.FindSingle(condition); if (info != null) { if (info.IsRegister) { if (info.MachineCode != code && info.LastAccessed.AddMinutes(10) >= DateTime.Now) { return "一個賬號多處登錄!"; } else { info.MachineCode = code; info.LastAccessed = DateTime.Now; base.Update(info, info.ID.ToString()); return "true"; } } else { return "false"; } } else { return "賬號被鎖定"; } } else { return "賬號密碼不正確"; } }
那我們在共享軟件的地方如何驗證用戶身份呢,就是通過傳遞頁面參數並調用ashx接口處理,判斷返回值即可。具體操作代碼如下所示。為了簡化操作,里面使用了一個我的公用類庫來提交數據(輔助類HttpHelper)。
private void btnOK_Click(object sender, EventArgs e) { if (this.txtUserName.Text.Length == 0) { MessageExUtil.ShowTips("請輸入賬號密碼登錄"); return; } string data = string.Format("action=r&usr={0}&pass={1}&code={2}", this.txtUserName.Text, this.txtPassword.Text, WHC.OrderWater.Commons.HardwareInfoHelper.GetMacAddress()); HttpHelper helper = new HttpHelper(); string result = helper.GetHtml(Portal.gc.UserActionUrl, data, true); if (!string.IsNullOrEmpty(result)) { if (result.ToLower() == "true") { Portal.gc.UserName = this.txtUserName.Text; Portal.gc.Registered = true; MessageExUtil.ShowTips("登錄成功"); this.DialogResult = DialogResult.OK; } else if (result.ToLower() == "false") { MessageExUtil.ShowTips("未授權用戶,但可繼續使用"); Portal.gc.UserName = this.txtUserName.Text; Portal.gc.Registered = false; this.DialogResult = DialogResult.OK; } else { MessageExUtil.ShowTips("操作失敗:" + result); } } else { MessageExUtil.ShowTips("操作失敗"); } }
以上就是一個功能的完整實現流程,其他的功能也是類似操作,下面給出ashx的完整代碼實現,供大家參考,並指正。
/// <summary> /// 用戶測試賬號可用性、注冊新用戶、登錄驗證、修改密碼等操作業務處理類 /// </summary> [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] public class UserAction : IHttpHandler { public void ProcessRequest(HttpContext context) { //context.Response.ContentType = "text/plain"; //context.Response.Write("Hello World"); context.Request.ContentEncoding = Encoding.Default ; string action = context.Request["action"]; string usr = context.Request["usr"]; string password = context.Request["pass"]; string machineCode = context.Request["code"]; string conditon = ""; bool result = false; switch (action) { case "r"://檢測注冊 UserAction.ashx?action=r&usr=&pass=&code= string reg = BLLFactory<SoftwareRegister>.Instance.CheckRegisterd(usr, password, machineCode); context.Response.ContentType = "text/plain"; context.Response.Write(reg); break; case "g"://測試登錄UserAction.ashx?action=g&usr=&pass=&code= result = BLLFactory<SoftwareRegister>.Instance.VerifyUser(usr, password, machineCode); context.Response.ContentType = "text/plain"; context.Response.Write(result); break; case "t"://測試用戶名UserAction.ashx?action=t&usr= result = BLLFactory<SoftwareRegister>.Instance.IsExistKey("Username", usr); context.Response.ContentType = "text/plain"; context.Response.Write(!result);//如果存在則返回False,否則True break; case "a"://添加用戶UserAction.ashx?action=a&usr=&pass=&sex=&code=&qq=&email= bool exist = BLLFactory<SoftwareRegister>.Instance.IsExistKey("Username", usr); if (!exist) { password = context.Request["pass"]; machineCode = context.Request["code"]; string sex = context.Request["sex"]; string qq = context.Request["qq"]; string email = context.Request["email"]; SoftwareRegisterInfo newInfo = new SoftwareRegisterInfo(); newInfo.Username = usr; newInfo.Password = MD5Util.GetMD5_16(password); newInfo.Sex = sex; newInfo.MachineCode = machineCode; newInfo.QQ = qq; newInfo.Email = email; result = BLLFactory<SoftwareRegister>.Instance.Insert(newInfo); } context.Response.ContentType = "text/plain"; context.Response.Write(result); break; case "ep"://修改用戶密碼UserAction.ashx?action=ep&usr=&pass=&newp= conditon = string.Format("Username='{0}'", usr); password = context.Request["pass"]; string newpass = context.Request["newp"]; SoftwareRegisterInfo info = BLLFactory<SoftwareRegister>.Instance.FindSingle(conditon); if (info != null) { if (MD5Util.GetMD5_16(password) == info.Password) { info.Password = MD5Util.GetMD5_16(newpass); result = BLLFactory<SoftwareRegister>.Instance.Update(info, info.ID.ToString()); } } context.Response.ContentType = "text/plain"; context.Response.Write(result); break; } } public bool IsReusable { get { return false; } } }
如果要考慮安全性,可能整體還需要進行一定的調整,不過具體操作,已經實現了我們所需要的功能了。歡迎大家一起探討。