PC 端微信掃碼注冊和登錄

一、前言

先聲明一下,本文所注重點為實現思路,代碼及數據庫設計主要為了展現思路,如果對代碼效率有著苛刻要求的項目切勿照搬。

相信做過微信開發的人授權這塊都沒少做過,但是一般來說我們更多的是為移動端的網站做授權,確切來說是在微信端下做的一個授權。今天遇到的一個問題是,項目支持微信端以及 PC 端,并且開放注冊。要求做到無論在 PC 端注冊或者是在微信端注冊之后都可以在另外一個端進行登錄。也就是說無論 PC 或是微信必須做到"你就是你"(通過某種方式關聯)。

二、尋找解決方案

按傳統的方式來思考,微信端完全可以通過授權進行注冊,但是PC端呢,傳統的方式無非就是填填手機號碼啊,或者 Email 等等。如果采用這種方式注冊,會產生下面這的問題

  1. 我先在微信端授權注冊,那么如果我要登錄PC端還是得進行注冊。

    對此解決方案可以為:微信授權注冊后“強制”要求用戶必須填寫基本信息,如手機號、Email 。這樣我們可以通過某種方式為用戶生成PC端登錄的賬號密碼.例如以用戶的 nickname 為賬號,手機號碼為密碼,等等方式。

    弊端:用戶體驗不好,再者有安全隱患。畢竟你的微信昵稱, Email 或者手機號碼都是暴露的。

  2. 如果我先在 PC 端注冊,我在微信授權的時候怎樣關聯移動端
    當然,凡是問題總會有解決方案的。思路如下:

    方案一:當用戶在 PC 端注冊后,“強制” 用戶必須填寫微信昵稱。以此作為微信授權時的關聯條件。但是很遺憾,微信昵稱可以改,不是唯一的怎么可以用來做關聯?方案一陣亡。

    方案二:在微信端授權后,以及在 PC 端注冊后“強制”要求用戶填寫手機號碼以此為關聯。這樣衍生出一個問題,必須確保用戶手機的真實信,沒問題。這個可以通過手機驗證碼來實現(Email也是一樣)。但是不妨假設一下有下面這種情況,如果我有兩個手機號碼,PC 端注冊時填一個,微信注冊時填另一個。關聯的了嗎?答案是很遺憾。再者,我在PC 端注冊后我就是不填(筆者把強制打上雙引號的原因),然后我用微信端授權登錄一下。好吧,此時將會有兩條數據等著你想辦法去關聯,典型的開發者自挖坑。這種方式某種程度上行得通,但是嚴謹程度上是開發者無法接受的。

三、回歸原點的解決方案

分析:既然方案上述方案都有問題,我們先把它們都拋到一邊。整理一下思路,讓我們回到問題的根本。關聯的問題,要的是一個唯一標識。唯一標識正如我們的身份證號碼,我們辦理信用卡的時候身份證是必須的,實名制下購買號碼卡,身份證是必須的。假設我們是這系統管理員,那么我完全可以通過你的身份證號碼查出你手機號碼,銀行卡號碼。

身份證關聯

有了上面的思路之后,我們需要做的就是找到一個唯一標識來作為關聯.微信上有個重要的角色 openid。
它跟我們上面提到的身份證號碼有這共同的作用,微信賬號對某一公眾號的唯一標識。

openid關聯

微信端的授權拿到 openid 做過微信開發的人都應該沒有問題。問題是怎樣來實現 PC 端 在注冊或者登陸的時候拿到 openid。筆者的實現思路如下。PC 端注冊,或者登陸時顯示一個二維碼引導用戶使用微信掃碼,使其跳轉到授權頁面。這一步有一個最為關鍵的細節,二維碼請帶上一個唯一的授權碼(authCode)。試想一下如果用戶授權后我們能把 openid 以及 authCode 寫入到數據庫。那么我們就可以在 PC 端通過某個 API 獲取 authCode 所關聯的這個 openid。如果我們做到這點我們就可以知道當前是誰在 PC 端進行掃碼注冊或登錄(沒注冊的注冊,有注冊的直接登錄)。 是不是突然覺得 so easy. 如果覺得文字比較抽象,請看下面圖示

PC 端微信掃碼登錄流程
微信掃碼登錄流程

核心代碼

搞清楚了思路和流程接下來我們直接上代碼啦.開發思路是共通的,開發語言就請各顯神通啦。

說明:下面代碼以 C# 語言為例,采用 MVC + EF (注:uuid 等價于我們上述的 authCode)

掃碼登錄頁后臺代碼
public ActionResult Login()
{
    //如果已登錄,直接跳轉到首頁
    if (User.Identity.IsAuthenticated)
        return RedirectToAction("Index", "Home");

    string url = Request.Url.Host;
    string uuid = Guid.NewGuid().ToString();
    ViewBag.url = "http://" + url + "/home/loginfor?uuid=" + uuid;//構造授權鏈接
    ViewBag.uuid = uuid;//保存 uuid
    return View();
}

生成二維碼采用插件 jquery.qrcode.js,想詳細了解的朋友請移步 Github
這里需要注意的一點是,該插件可以指定二維碼的生成方式,canvas 或者 table 請需要支持 IE 的朋友指定使用 table 生成

代碼如下:
jQuery('#qrcode').qrcode({
    render    : "table",
    text    : "http://baidu.com"
});
回歸正題,登錄頁面的主要代碼如下
<!--生成二維碼的容器 div-->
<div id="qrcode-container">
</div>

<script src="~/Plugins/Jquery/jquery-1.9.1.min.js"></script>
<script src="~/Plugins/jquery-qrcode/jquery.qrcode.min.js"></script>
<script>
    jQuery(function () {
        //生成二維碼
        jQuery('#qrcode-container').qrcode("@ViewBag.url");

        //輪詢判斷用戶是否授權
        var interval = setInterval(function () {
            $.post("@Url.Action("UserLogin","Home")", { "uuid": "@ViewBag.uuid" }, function (data, status) {
                if ("success" == status) {
                    //用戶成功授權=>跳轉
                    if ("success" == data) {
                        window.location.href = '@Url.Action("Index", "Home")';
                        clearInterval(interval);
                    }
                }
            });
        }, 200);
    })
</script>
輪詢判斷用戶是否授權 API 代碼
public string UserLogin(string uuid)
{
    //驗證參數是否合法
    if (string.IsNullOrEmpty(uuid))
        return "param_error";

    WX_UserRecord user = db.WX_UserRecord.Where(u => u.uuId == uuid).FirstOrDefault();
    if (user == null)
        return "not_authcode";

    //寫入cookie
    FormsAuthentication.SetAuthCookie(user.OpenId, false);

    //清空uuid
    user.uuId = null;
    db.SaveChanges();

    return "success";
} 
微信端授權 Action
public ActionResult Loginfor(string uuid)
{
   
    #region 獲取基本信息 - snsapi_userinfo

    /*
     * 創建微信通用類 - 這里代碼比較復雜不在這里貼出
     * 遲點我會將整個 Demo 稍微整理放上 Github
    */
    WechatUserContext wxcontext = new WechatUserContext(System.Web.HttpContext.Current, uuid);

    //使用微信通用類獲取用戶基本信息
    wxcontext.GetUserInfo();

    if (!string.IsNullOrEmpty(wxcontext.openid))
    {
        uuid = Request["state"];
        //判斷數據庫是否存在
        WX_UserRecord user = db.WX_UserRecord.Where(u => u.OpenId == wxcontext.openid).FirstOrDefault();
        if (null == user)
        {
            user = new WX_UserRecord();
            user.OpenId = wxcontext.openid;
            user.City = wxcontext.city;
            user.Country = wxcontext.country;
            user.CreateTime = DateTime.Now;
            user.HeadImgUrl = wxcontext.headimgurl;
            user.Nickname = wxcontext.nickname;
            user.Province = wxcontext.province;
            user.Sex = wxcontext.sex;
            user.Unionid = wxcontext.unionid;                    
            user.uuId = uuid;
            db.WX_UserRecord.Add(user);
        }
        user.uuId = uuid;
        db.SaveChanges();
    }
    #endregion

    return View();
} 
最后附上數據庫表設計

沒什么特殊的,就是微信返回的各個參數加多一個我們自定義的 uuId

數據庫表設計

微信參數說明 詳情請見 微信開發者文檔

相關字段說明

運行效果

1.掃碼登錄頁面
登錄
2.請求用戶授權
請求授權
3.用戶確認授權
用戶確認授權
4.PC 端登錄完成
首頁

文章難免有不足之處,還請海涵。如有發現錯誤還望留言指出,筆者感激不盡!
微信掃碼注冊登錄 Demo 待筆者整理后放上 Github 希望幫到更多的朋友,請有需要的朋友留意該文更新。

本文為作者原創,轉載請注明出處! 剛玩簡書不久,誠意交有共同編程愛好的朋友!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容