C#开发微信门户及应用(41)--基于微信开放平台的扫码登录处理
在现今很多网站里面,都使用了微信开放平台的扫码登录认证处理,这样做相当于把身份认证交给较为权威的第三方进行认证,在应用网站里面可以不需要存储用户的密码了。本篇介绍如何基于微信开放平台的扫码进行网站的登陆处理。
1、开放平台的认证
要使用网站的扫码登录处理,就需要先进行微信开放平台帐号的开发者资质认证,提交相关的资料,以及交付每年300元的认证费用。

认证后,建立相关的网站应用后,就有相关的APPID和APPSecret了,这些关键的参数就可以用来获取相关的用户信息了。
网站应用的应用详情界面如下所示。

整个开放平台感觉没有多少东西,不过需要收费认证才能使用这些功能,感觉不是很爽。
我们采用的扫码登录,需要通过开放平台获取用户的信息,因此还需要设置获取用户基本信息接口的域名,否则无法获取信息,从而会导致重定向出错。
设置域名在【接口权限】【网页账号】【网页授权获取用户基本信息】的修改入口,如下图所示。

然后在弹出的对话框里面输入授权回调的域名即可。

这样设置就可以确保获取到用户信息了。
2、扫码登录的说明和具体使用
网站应用微信登录是基于OAuth2.0协议标准构建的微信OAuth2.0授权登录系统。
在进行微信OAuth2.在进行微信OAuth2.0授权登录接入之前,在微信开放平台注册开发者帐号,并拥有一个已审核通过的网站应用,并获得相应的AppID和AppSecret,申请微信登录且通过审核后,可开始接入流程。
微信OAuth2.0授权登录让微信用户使用微信身份安全登录第三方应用或网站,在微信用户授权登录已接入微信OAuth2.0的第三方应用后,第三方可以获取到用户的接口调用凭证(access_token),通过access_token可以进行微信开放平台授权关系接口调用,从而可实现获取微信用户基本开放信息和帮助用户实现基础开放功能等。
微信OAuth2.0授权登录目前支持authorization_code模式,适用于拥有server端的应用授权。该模式整体流程为:
. 第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到第三方网站,并且带上授权临时票据code参数; . 通过code参数加上AppID和AppSecret等,通过API换取access_token; . 通过access_token进行接口调用,获取用户基本数据资源或帮助用户实现基本操作。
获取access_token时序图:

从上图我们可以大概了解整个扫码登陆的处理过程。
3、扫码登录的各个步骤处理
1)用户身份的绑定
为了实现二维码扫码登录,我们需要在现有系统里面绑定用户的微信,这样才能在用户扫码的时候,判断用户的身份从而实现自动登录的过程。
我们可以在用户管理里面进行统一设置,也可以在常规用户登录(用户名+密码)后进行设置,这个主要看我们是否需要保留用户名密码登陆这种方式。
例如可以在用户管理里面统一绑定,也就是在创建用户的时候,让用户绑定下微信,获取微信的唯一标识。

也可以在保留用户名密码的登陆方式外,让用户登陆系统后自行进行绑定微信即可。

上面的界面,就是在一个页面里面弹出一个层,然后请求二维码显示即可,如下界面代码所示。
<div id="divWechat" class="easyui-dialog" style="width:450px;height:350px;padding:10px 20px"
closed="true" resizable="true" modal="true" iconcls="icon-setting">
<div>
<h4>扫描用户二维码,进行绑定</h4>
</div>
<div align="center">
<img id="imgQRcode" alt="使用微信扫码进行绑定" style="height:200px;width:auto" />
</div> <div align="right">
<a href="javascript:void(0)" class="easyui-linkbutton" iconcls="icon-cancel" onclick="javascript: $('#divWechat').dialog('close')">关闭</a>
</div>
</div>
上面的层在打开的时候,我们使用JS来动态获取二维码进行显示,具体JS代码如下所示。
//绑定微信登陆
function BindWechat() {
var url = "http://www.iqidi.com/H5/BindWechat?id=@Session["UserID"]";
url = encodeURIComponent(url);
$("#imgQRcode").attr("src", "/H5/QR?url=" + url);
//打开绑定窗口
$("#divWechat").dialog('open').dialog('setTitle', '使用微信扫码进行绑定');
}
上面的JS只是做前端的数据请求和显示,具体的QR动作Action其实就是生成扫描二维码的过程,这个二维码其实就是采用通用的方式,来构建一个指向我们绑定账号的地址,从而实现我们绑定账号的判断,二维码的生成过程如下所示。
/// <summary>
/// 转换二维码连接为图片格式
/// </summary>
/// <param name="url">二维码连接</param>
/// <returns></returns>
[HttpGet]
public ActionResult QR(string url)
{
//初始化二维码生成工具
QRCodeEncoder qrCodeEncoder = new QRCodeEncoder();
qrCodeEncoder.QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.BYTE;
qrCodeEncoder.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.M;
qrCodeEncoder.QRCodeVersion = ;
qrCodeEncoder.QRCodeScale = ; //将字符串生成二维码图片
var image = qrCodeEncoder.Encode(url, Encoding.Default);
//保存为PNG到内存流
MemoryStream ms = new MemoryStream();
image.Save(ms, ImageFormat.Png);
image.Dispose(); return File(ms.ToArray(), "image/Png");
}
为了实现用户的绑定,我们需要获取当前用户的身份信息,因此需要在BindWeChat的操作里面做一个转向处理,如下接口所示。
/// <summary>
/// 生成绑定微信的地址
/// </summary>
/// <returns></returns>
public ActionResult BindWechat()
这个函数处理里面,我们需要重新定向处理,我们把它定向到BindAccount函数里面,方便获取用户的openid和其他必要的信息。
另外我们基于微信开放平台的应用,建立了一个和微信账号信息的联系,因此创建数据库信息如下所示。

也就是一个具体的开放平台应用对应着一个具体的微信账号,这样我们就可以充分利用配置进行处理了。
上面提到的BindAccount的处理的逻辑就是获取必要的信息,然后在数据库层面对身份信息进行验证,具体代码如下所示。
/// <summary>
/// 绑定用户微信号
/// </summary>
/// <param name="id">账号ID</param>
/// <returns></returns>
public ActionResult BindAccount()
{
WebAppInfo appInfo = GetWebApp(ConfigData.WebAppId);
AccountInfo accountInfo = GetAccount(appInfo.AccountNo); var htResult = GetOpenIdAndUnionId(accountInfo.UniteAppId, accountInfo.UniteAppSecret);//存储openid方便使用
string openid = htResult["openid"].ToString();
var unionid = htResult["unionid"].ToString();
var userid = Request.QueryString["id"];
var state = Request.QueryString["state"]; if (!string.IsNullOrEmpty(openid) && !string.IsNullOrEmpty(userid))
{
CommonResult result = BLLFactory<User>.Instance.BindUser(openid, unionid, userid.ToInt32());
if (result.Success)
{
return BindSuccess();
}
else
{
return BindFail();
}
}
else
{
throw new WeixinException("无法获取openid" + string.Format(", openid:{0}, userid:{1}", openid, userid));
}
}
在绑定的过程,我们需要考虑绑定正确账号,重复绑定其他账号,无效绑定几种情况,如果成功绑定正确账号(可多次处理结果一样),那么得到界面如下所示(这个界面的样式采用了weui的样式)。

2)用户的扫码登录处理
上面绑定了账号后,就可以通过扫码进行登录了,扫码回调的时候我们有自己的判断处理,扫码界面如下所示(我们在保留用户名密码登陆的方式外,增加了一个扫码登录的处理)。
如果是Bootstrap的界面效果

如果是EasyUI的界面效果

这个和前面的二维码显示规则差不多,不过他们的连接地址是不同的,这个地方用到了开放平台的接口,也就是我们前面提到开放平台认证的接口了。
上面的扫码登录的界面代码如下所示。
<!--二维码扫描登陆的界面层-->
<div id="divWechat" class="easyui-dialog" style="width:550px;height:500px;padding:10px 20px"
closed="true" resizable="true" modal="true" iconcls="icon-setting">
<div id="login_container" align="center">
</div> <div align="right">
<a href="javascript:void(0)" class="easyui-linkbutton" iconcls="icon-cancel" onclick="javascript: $('#divWechat').dialog('close')">关闭</a>
</div>
</div>
上面代码需要引入JS文件,并使用微信JSSDK的API进行显示的。
<!--使用微信扫码进行登陆-->
<script src="http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js"></script>
<script language="javascript"> function OpenJSLogin() {
var obj = new WxLogin({
id: "login_container",
appid: "@ViewBag.appid",
scope: "snsapi_login",
redirect_uri: "@ViewBag.redirect_uri",
state: "@ViewBag.state",
style: "black",
href: ".impowerBox .qrcode {width: 200px;}"
}); //打开绑定窗口
$("#divWechat").dialog('open').dialog('setTitle', '使用微信扫码进行登陆');
}
</script>
这个里面的参数,如APPID就是来源我们认证后的开放平台参数。
这些信息我们在MVC控制器后面获取后绑定在ViewBag,方便界面前端的使用。
//使用JSLogin登陆
WebAppInfo appInfo = BLLFactory<WebApp>.Instance.FindByID(ConfigData.WebAppId);
ArgumentValidation.CheckForNullReference(appInfo, "Web应用程序appInfo"); if (appInfo != null)
{
ViewBag.appid = appInfo.OpenAppID;
ViewBag.redirect_uri = appInfo.LoginCallBackUrl;
ViewBag.state = ConfigData.AuthState;
}
其中的redirect_uri是通过数据库获取的LoginCallBackUrl地址,这个地址类似如下格式:http://www.iqidi.com/H5/callback?uid=iqidiSoftware
也就是我们在开放平台处理返回后进行的回调处理。
通过开放平台的APPID和APPSecret,我们可以获取到对应的接口调用凭证,然后根据接口凭证,以及openid,获得用户的公众平台统一的UnionID,这个标识是我们用户的唯一标识,代码如下所示。
var result = baseApi.GetAuthToken(appid, appsecret, code);
if (result != null && !string.IsNullOrEmpty(result.openid))
{
openid = result.openid;
var unionResult = baseApi.GetSnsapiUserInfo(result.access_token, result.openid); ht.Add("openid", openid);
ht.Add("unionid", unionResult != null ? unionResult.unionid : "");
}
有了unionid我们就可以根据这个标识在我们的用户数据库里面查找对应的用户,如下代码所示。
//开放平台的OpenID,不是公众号的OpenID,需要转换为unionid
if (!string.IsNullOrEmpty(openid) && !string.IsNullOrEmpty(unionid))
{
UserInfo userInfo = BLLFactory<User>.Instance.FindByUnionId(unionid);
然后判断我们去到的用户信息是否正确,如下代码所示
if (userInfo != null)
{
CommonResult loginResult = CheckLogin(userInfo.Name);
if (!loginResult.Success)
{
LogHelper.Info(string.Format("用户登陆不成功,{0}", loginResult.ErrorMessage));
} //登陆成功后的重定向地址
var url = appInfo.HomeUrl; //例如:http://www.iqidi.com/Home
return Redirect(url);
}
如果不成功,那么我们定向到指定的界面即可。
//如不成功,最后都统一提示信息
ViewBag.Error = "获取信息失败,登陆错误";
return View("LoginError");
如果我们登陆成功后,需要设置一些Session信息或者Cookie信息,那么就可以通过CheckLogin函数进行处理即可。
以上就是我们结合微信开放平台实现微信扫码登录的过程,其中整个过程就是用到了下面几个过程。
1)使用JSSDK的脚本实现扫码获取code
JS微信登录主要用途:网站希望用户在网站内就能完成登录,无需跳转到微信域下登录后再返回,提升微信登录的流畅性与成功率。 网站内嵌二维码微信登录JS实现办法:
步骤1:在页面中先引入如下JS文件(支持https):
<script src="http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js"></script>
步骤2:在需要使用微信登录的地方实例以下JS对象:
var obj = new WxLogin({
id:"login_container",
appid: "",
scope: "",
redirect_uri: "",
state: "",
style: "",
href: ""
});
2) 第二步:通过code获取access_token
通过code获取access_token
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
3)第三步:通过access_token调用接口
获取access_token后,进行接口调用,
对于接口作用域(scope),能调用的接口有以下:
| 授权作用域(scope) | 接口 | 接口说明 |
|---|---|---|
| snsapi_base | /sns/oauth2/access_token | 通过code换取access_token、refresh_token和已授权scope |
| /sns/oauth2/refresh_token | 刷新或续期access_token使用 | |
| /sns/auth | 检查access_token有效性 | |
| snsapi_userinfo | /sns/userinfo | 获取用户个人信息 |
其中snsapi_base属于基础接口,若应用已拥有其它scope权限,则默认拥有snsapi_base的权限。使用snsapi_base可以让移动端网页授权绕过跳转授权登录页请求用户授权的动作,直接跳转第三方网页带上授权临时票据(code),但会使得用户已授权作用域(scope)仅为snsapi_base,从而导致无法获取到需要用户授权才允许获得的数据和基础功能。
4)获取信息在回调界面中进行登录前处理
通过上面接口,我们可以获得相应的用户身份信息,因此可以结合我们用户数据库进行用户身份的认定和处理,并设置必要的Session或者Cookie信息等,最后定位到我们的应用主界面即可。
C#开发微信门户及应用(41)--基于微信开放平台的扫码登录处理的更多相关文章
- C#开发微信门户及应用(46)-基于Bootstrap的微信门户应用管理系统功能介绍
在前面介绍很多的微信框架,基本上都采用EasyUI的界面来搭建的微信框架,如随笔<C#开发微信门户及应用(8)-微信门户应用管理系统功能介绍>介绍的一样,不过随着微信的H5应用越来越多,因 ...
- C#开发微信门户及应用(45)--微信扫码登录
在前面随笔<C#开发微信门户及应用(41)--基于微信开放平台的扫码登录处理>介绍了基于微信开放平台接口实现的微信扫码直接登录的过程.本篇介绍对扫码登录的一些改进和处理,以便更方便应用在实 ...
- IOS基于新浪微博开放平台微博APP
1.基于新浪微博开放平台APP源码 2.gitHub源代码下载地址 https://github.com/whzhaochao/SinaWeiBoOpen 3.用到的第三放开源库 3.1 RTLab ...
- C#开发微信门户及应用(39)--使用微信JSSDK实现签到的功能
随着微信开逐步开放更多JSSDK的接口,我们可以利用自定义网页的方式来调用更多微信的接口,实现我们更加丰富的界面功能和效果,例如我们可以在页面中调用各种手机的硬件来获取信息,如摄像头拍照,GPS信息. ...
- C#开发微信门户及应用(14)-在微信菜单中采用重定向获取用户数据
我曾经在系列文章中的<C#开发微信门户及应用(11)--微信菜单的多种表现方式介绍>中介绍了微信菜单里面的重定向操作,通过这个重定向操作,我们可以获取一个code值,然后获取用户的open ...
- C#开发微信门户及应用(40)--使用微信JSAPI实现微信支付功能
在我前面的几篇博客,有介绍了微信支付.微信红包.企业付款等各种和支付相关的操作,不过上面都是基于微信普通API的封装,本篇随笔继续微信支付这一主题,继续介绍基于微信网页JSAPI的方式发起的微信支付功 ...
- 微信开放平台开发——网页微信扫码登录(OAuth2.0)
1.OAuth2.0 OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用. 允许用户提供 ...
- 适合新手:从零开发一个IM服务端(基于Netty,有完整源码)
本文由“yuanrw”分享,博客:juejin.im/user/5cefab8451882510eb758606,收录时内容有改动和修订. 0.引言 站长提示:本文适合IM新手阅读,但最好有一定的网络 ...
- 基于 Swoole 的微信扫码登录
随着微信的普及,扫码登录方式越来越被现在的应用所使用.它因为不用去记住密码,只要有微信号即可方便快捷登录.微信的开放平台原生就有支持扫码登录的功能,不过大部分人还是在用公众平台,所以扫码登录只能自行实 ...
随机推荐
- 【译】更快的方式实现PHP数组去重
原文:Faster Alternative to PHP’s Array Unique Function 概述 使用PHP的array_unique()函数允许你传递一个数组,然后移除重复的值,返回一 ...
- 探索C#之虚拟桶分片
阅读目录 背景 虚拟桶(virtual buckets) 实现 总结 背景 关于数据分片讨论最多的是一致性hash,然而它并不是分布式设计中的银弹百试百灵. 在数据稳定性要求比较高的场景下它的缺点是不 ...
- MySQL 常用的UPDATE操作
标签:UPDATE 概述 测试环境:mysql 5.6.21 步骤 创建测试表 CREATE TABLE `product` ( `proID` ) NOT NULL AUTO_INCREMENT C ...
- Windows Azure Storage (19) 再谈Azure Block Blob和Page Blob
<Windows Azure Platform 系列文章目录> 请读者在参考本文之前,预习相关背景知识:Windows Azure Storage (1) Windows Azure St ...
- 《Entity Framework 6 Recipes》翻译系列 (1) -----第一章 开始使用实体框架之历史和框架简述
微软的Entity Framework 受到越来越多人的关注和使用,Entity Framework7.0版本也即将发行.虽然已经开源,可遗憾的是,国内没有关于它的书籍,更不用说好书了,可能是因为EF ...
- java:警告:[unchecked] 对作为普通类型 java.util.HashMap 的成员的put(K,V) 的调用未经检查
java:警告:[unchecked] 对作为普通类型 java.util.HashMap 的成员的put(K,V) 的调用未经检查 一.问题:学习HashMap时候,我做了这样一个程序: impor ...
- 【PRINCE2是什么】PRINCE2认证之七大原则(3)
我们先来回顾一下,PRINCE2七大原则分别是持续的业务验证,经验学习,角色与责任,按阶段管理,例外管理,关注产品,剪裁. 第三个原则:明确定义的角色和职责. 项目离不开人员,错误的人来了,合适的人没 ...
- WCF学习之旅——第一个WCF示例(二)
第四步:通过自我寄宿的方式寄宿服务 WCF服务需要依存一个运行着的进程(宿主),服务寄宿就是为服务指定一个宿主的过程.WCF是一个基于消息的通信框架,采用基于终结点(Endpoint)的通信手段. 终 ...
- 有吧友需要PDF的下载站点,好吧,我这边汇总一下
[经验]谈谈怎么找自己想要的资源吧~ http://www.cnblogs.com/dunitian/p/4715482.html PDF Free Computer, Programming, Ma ...
- C#设计模式系列:享元模式(Flyweight)
当频繁地从数据源读取数据时,读出的内容存在重复,那么需要使用享元模式(Flyweight)来提高内存效率,Flyweight模式将节省更多空间,共享的Flyweight越多,空间节省越大. 1.享元模 ...