CSS&javascript 避免重複創立帳號&亂數碼驗證

目的相當很簡單
1、取得亂數圖的值
2、不重複寫入資料庫

在加入會員部份已經做過很多:

「加入會員」驗證資料及亂數產生驗證碼
jquery使用ajax驗證帳號(運用介面、多型)

其中的亂數驗證,本來是用cookie的方式達到傳取值的目的
現在用Session的方式好處是相對安全一點
因為cookie是放在使用者的電腦
而Session是放在伺服器中
壞處自然是伺服器負擔會相對大一點

第2點呢,是使用者的行為是不可預期的,假設某使用者
在加入會員時,輸入數值後一直重新整理
會造成重複寫入資料庫的嚴重錯誤
若是訂單的話就更可怕了,所以要避免這樣的情況發生



亂數部份,請先參考之前寫好的資料
並改成以下的程式碼,以存入Session
檔案位於/Tools/GetVaildImage.ashx:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Web;
using System.Web.SessionState;//務必放入,不然寫不進Session

namespace WebPractice.Tools
{

    public class GetVaildImage : IHttpHandler,IRequiresSessionState//要implement這個類別
    {

        public void ProcessRequest(HttpContext context)
        {
            //記得引入驗證圖參考,本例為8位數的驗證圖
            Vaild.VaildNum vn = new Vaild.VaildNum(8);
            context.Session.Add("VaildAns", vn.VaildNumAnswer);//寫入Session
            Bitmap bmp = vn.VaildNumImage;
            
            //存於記憶體中的串流
            System.IO.MemoryStream ms = new System.IO.MemoryStream();
            //bmp.Save(存放位置,存放格式)
            bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
            //轉成陣列後輸出
            byte[] bb = ms.ToArray();
            context.Response.OutputStream.Write(bb,0,bb.Length);
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

接著,再撰寫取得Session的ashx
位於/Tools/GetVaildAnswer.ashx:
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.SessionState;//務必放入,不然寫不進Session

namespace WebPractice.Tools
{
    public class GetVaildAnswer : IHttpHandler,IRequiresSessionState//要implement這個類別
    {

        public void ProcessRequest(HttpContext context)
        {
            context.Response.Write(context.Session["VaildAns"]);//取得Session的值並回傳
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

=============================================================================

以上,即完成Session的存取設定,接著
要在專門執行寫入資料庫的NWDB專案進行修改
才可以引用及寫入資料庫的行為:

IMember.cs:

    public interface IMember
    {
            bool CheckMemberDuplicate(string Account);
            //加入會員的方法,會回傳bool值
            bool addNewMember(
                        string Account, byte[] Password,string FirstName, string LastName, byte Sex
                        ,string Birth,string County,string Region,string Address,string Edu,string Email);
    }
}

在實作的檔案加入addNewMember新增會員的方法

ImplImember.cs:

public bool addNewMember(string Account, byte[] Password, string FirstName, string LastName,byte Sex, string Birth, string County, string Region, string Address, string Edu, string Email)
{
    SqlCommand cmd = new SqlCommand(
        "INSERT INTO 會員表(帳號,密碼,姓,名,性別,生日,縣市,鄉鎮,地址,學歷,電子郵件) VALUES(@account,@password,@firstname,@lastname,@sex, @birth, @county, @region, @address, @edu, @email)", cnn);
    cmd.Parameters.Add("@account", SqlDbType.VarChar).Value = Account;
    cmd.Parameters.Add("@password", SqlDbType.Image).Value = Password;
    cmd.Parameters.Add("@firstname", SqlDbType.VarChar).Value = FirstName;
    cmd.Parameters.Add("@lastname", SqlDbType.VarChar).Value = LastName;
    cmd.Parameters.Add("@sex", SqlDbType.Bit).Value = Sex;
    cmd.Parameters.Add("@birth", SqlDbType.VarChar).Value = Birth;
    cmd.Parameters.Add("@county", SqlDbType.VarChar).Value = County;
    cmd.Parameters.Add("@region", SqlDbType.VarChar).Value = Region;
    cmd.Parameters.Add("@address", SqlDbType.VarChar).Value = Address;
    cmd.Parameters.Add("@edu", SqlDbType.VarChar).Value = Edu;
    cmd.Parameters.Add("@email", SqlDbType.VarChar).Value = Email;

    cnn.Open();
    int nn = cmd.ExecuteNonQuery();
    cmd.Dispose();
    cnn.Close();

    if (nn > 0)
        return true;//寫入成功
    else
        return false;//失敗

}
NWDB.cs當然也要加入這個方法,如此才可以引用

NWDB.cs:

#region 新增帳戶
public bool addNewMember(string Account, byte[] Password, string FirstName, string LastName, byte Sex, string Birth, string County, string Region, string Address, string Edu, string Email)
{
    return im.addNewMember(Account,Password,FirstName,LastName,Sex,Birth,County,Region,Address,Edu,Email);
}
#endregion 新增帳戶

=============================================================================
看來很複雜,其實滿好寫的, 如此即完成NWDB的撰寫
最後就是網頁端的重點
由於使用者可能會上一頁、下一頁、重新整理的亂按
無法預期,為了避免這樣的狀況
我們使用一個方法就是:

當使用者寫完註冊內容送出後,會先到一個使用者看不到網頁
進行寫入資料庫的行為及跳轉,到另一個網頁出現「新增帳戶成功!」的訊息

中間放一個跳板,使按下「上一頁」回不去註冊畫面
即使重新整理,也只是整理成功訊息的網頁,裡面沒有任何資料

首先是加入會員的網頁jquery撰寫:

<script type="text/javascript">
    
     //由於內容太長,而且之前也寫過了,所以重複的部份就不寫入
    //這邊程式碼只針對驗證圖及對應答案的部份
    $(document).ready(function () {
        //驗證答案
        getVaildans();

        //按下重新取得驗證圖
        $("#RefreshVaildImgBtn").click(function () {
            $("#VaildNumImg").attr
                ("src", "/Tools/GetVaildImage.ashx?time=" + new Date().getTime());
            getVaildans();
        });
        


    });

    //取得驗證答案
    function getVaildans() {
        $.get("/Tools/GetVaildAnswer.ashx?time=" + new Date().getTime(), null, function (ans) {
            $("#VaildAns").val(ans);
            alert(ans);
        }, "text");
    }

    function checkForm() {

        var msg = "";
        if ($("#VaildAnsText").val() != $("#VaildAns").val().toLowerCase())
            msg += "* 驗證答案有誤";

        if (msg != "") {
            alert(msg);
            return false;
        }
        else {
            $("#form1").submit();
        }
    }
        
</script>

//form的部份請將action轉向中轉的ashx泛式
<form id="form1" action="AddNewMemberProcess.ashx" method="post">


再來是中轉的AddNewMemberProcess.ashx網頁撰寫:

public void ProcessRequest(HttpContext context)
{
    string Account = context.Request.Form["Account"];
    string Password = context.Request.Form["Password"];
    string FirstName = context.Request.Form["FirstName"];
    string LastName = context.Request.Form["LastName"];
    string Sex = context.Request.Form["Sex"];
    string Birth = context.Request.Form["Birth"];
    string County = context.Request.Form["County"];
    string Region = context.Request.Form["Region"];
    string Address = context.Request.Form["Address"];
    string Edu = context.Request.Form["Edu"];
    string Email = context.Request.Form["EMail"];

    //密碼要加密,即使進到資料庫也看不出答案
    //最前面要引入using System.Security.Cryptography;
    //簡單來說,只有使用者知道自已設定的密碼,網站及資料庫都沒辦法得知

    byte[] originalPassword = System.Text.Encoding.UTF8.GetBytes(Password);//將使用者輸入的轉成2進位碼
    SHA256Managed sha256 = new SHA256Managed();//new出加密引擎,使用SHA256
    byte[] hashlPassword = sha256.ComputeHash(originalPassword);//將該2進位碼加密

    byte ssex = (byte)((Sex == "男") ? 1 : 0);

    //寫入資料庫,sqluser權限不夠所以要改用sqladmin帳號
    NWDB.NWDB nwdb = new NWDB.NWDB("SQLAdmin", "1234");
    NWDB.IMember im = new NWDB.ImplImember(nwdb.Connection);
    nwdb.SetMember(im);
    nwdb.addNewMember(Account, hashlPassword, FirstName, LastName, ssex, Birth, County, Region, Address, Edu, Email);
    //轉向成功訊息的網站
    context.Response.Redirect("AddNewMemberFinish.aspx");
}

成功的訊息網頁很簡單,就只是短短一行加入會員成功。
這樣就可以避免重複寫入資料庫了
不只是會員,像是訂單同樣也可以這樣運用。


留言

熱門文章