微信第三方登陆

 

小程序和公众号获取access_token的接口 相同

此接口每天的调用次数是10000次。

https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/openApi-mgnt/getApiQuota.html

GET https://api.weixin.qq.com/cgi-bin/token

access_token 的有效期目前为 2 个小时,需定时刷新,重复获取将导致上次获取的 access_token 失效;
access_token 的有效期通过返回的 expires_in 来传达,目前是7200秒之内的值,中控服务器需要根据这个有效时间提前去刷新。在刷新过程中,中控服务器可对外继续输出的老 access_token,此时公众平台后台会保证在5分钟内,新老 access_token 都可用,这保证了第三方业务的平滑过渡;

access_token 的存储至少要保留 512 个字符空间;

https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-access-token/getAccessToken.html

 

https请求方式: GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

 

开发者通过某 IP 发起调用->平台返回错误码[89503]并同时下发模板消息给公众号管理员->公众号管理员确认该 IP 可以调用->开发者使用该 IP 再次发起调用->调用成功。

如公众号管理员第一次拒绝该 IP 调用,用户在1个小时内将无法使用该 IP 再次发起调用,如公众号管理员多次拒绝该 IP 调用,该 IP 将可能长期无法发起调用。平台建议开发者在发起调用前主动与管理员沟通确认调用需求,或请求管理员开启 IP 白名单功能并将该 IP 加入 IP 白名单列表。

公众号和小程序均可以使用 AppID 和AppSecret调用本接口来获取access_token。AppID和 AppSecret 可在“微信公众平台 - 开发 - 基本配置”页中获得(需要已经成为开发者,且帐号没有异常状态)。**调用接口时,请登录“微信公众平台 - 开发 - 基本配置”提前将服务器 IP 地址添加到 IP 白名单中,点击查看设置方法,否则将无法调用成功。**小程序无需配置 IP 白名单。

https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html

 

获取授权帐号调用令牌

接口应在服务器端调用,详细说明参见服务端API

接口说明

接口英文名

getAuthorizerAccessToken

功能描述

该接口用于获取授权帐号的authorizer_access_token。authorizer_access_token 有效期为 2 小时,authorizer_access_token 失效时,可以使用 authorizer_refresh_token 获取新的 authorizer_access_token。使用过程中如遇到问题,可在开放平台服务商专区发帖交流。

注意事项

调用方式

HTTPS 调用


POST https://api.weixin.qq.com/cgi-bin/component/api_authorizer_token?component_access_token=ACCESS_TOKEN 
https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/ticket-token/getAuthorizerAccessToken.html
 
 
 

 

摘自:http://blog.csdn.net/jolin678/article/details/50524081 



 

 https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html



准备工作

网站应用微信登录是基于OAuth2.0协议标准构建的微信OAuth2.0授权登录系统。 在进行微信OAuth2.0授权登录接入之前,在微信开放平台注册开发者帐号,并拥有一个已审核通过的网站应用,并获得相应的AppID和AppSecret,申请微信登录且通过审核后,可开始接入流程。

授权流程说明

微信OAuth2.0授权登录让微信用户使用微信身份安全登录第三方应用或网站,在微信用户授权登录已接入微信OAuth2.0的第三方应用后,第三方可以获取到用户的接口调用凭证(access_token),通过access_token可以进行微信开放平台授权关系接口调用,从而可实现获取微信用户基本开放信息和帮助用户实现基础开放功能等。 微信OAuth2.0授权登录目前支持authorization_code模式,适用于拥有server端的应用授权。该模式整体流程为:


1. 第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到第三方网站,并且带上授权临时票据code参数;
2. 通过code参数加上AppID和AppSecret等,通过API换取access_token;【与服务号获取accessToken的接口相同】
3. 通过access_token进行接口调用,获取用户基本数据资源或帮助用户实现基本操作。

获取access_token时序图:

 

 

第一步:请求CODE

第三方使用网站应用授权登录前请注意已获取相应网页授权作用域(scope=snsapi_login),则可以通过在PC端打开以下链接: https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect 若提示“该链接无法访问”,请检查参数是否填写错误,如redirect_uri的域名与审核时填写的授权域名不一致或scope不为snsapi_login。

参数说明

参数是否必须说明
appid 应用唯一标识
redirect_uri 请使用urlEncode对链接进行处理
response_type 填code
scope 应用授权作用域,拥有多个作用域用逗号(,)分隔,网页应用目前仅填写snsapi_login即可
state 用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验

返回说明

用户允许授权后,将会重定向到redirect_uri的网址上,并且带上code和state参数

redirect_uri?code=CODE&state=STATE

若用户禁止授权,则重定向后不会带上code参数,仅会带上state参数

redirect_uri?state=STATE

请求示例

登录一号店网站应用 https://passport.yhd.com/wechat/login.do 打开后,一号店会生成state参数,跳转到 https://open.weixin.qq.com/connect/qrconnect?appid=wxbdc5610cc59c1631&redirect_uri=https%3A%2F%2Fpassport.yhd.com%2Fwechat%2Fcallback.do&response_type=code&scope=snsapi_login&state=3d6be0a4035d839573b04816624a415e#wechat_redirect
解码后的微信重定向URL:
https://open.weixin.qq.com/connect/qrconnect?appid=wxbdc5610cc59c1631&redirect_uri=https://passport.yhd.com/wechat/callback.do&response_type=code&scope=snsapi_login&state=3d6be0a4035d839573b04816624a415e#wechat_redirect

微信用户使用微信扫描二维码并且确认登录后,PC端会跳转到 https://passport.yhd.com/wechat/callback.do?code=CODE&state=3d6be0a4035d839573b04816624a415e
为了满足网站更定制化的需求,我们还提供了第二种获取code的方式,支持网站将微信登录二维码内嵌到自己页面中,用户使用微信扫码授权后通过JS将code返回给网站。
JS微信登录主要用途:网站希望用户在网站内就能完成登录,无需跳转到微信域下登录后再返回,提升微信登录的流畅性与成功率。

网站内嵌二维码微信登录JS实现办法:

步骤1:在页面中先引入如下JS文件(支持https):

http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js

步骤2:在需要使用微信登录的地方实例以下JS对象:

 var obj = new WxLogin({
 self_redirect:true,
 id:"login_container", 
 appid: "", 
 scope: "", 
 redirect_uri: "",
  state: "",
 style: "",
 href: ""
 });

参数说明

参数是否必须说明
self_redirect true:手机点击确认登录后可以在 iframe 内跳转到 redirect_uri,false:手机点击确认登录后可以在 top window 跳转到 redirect_uri。默认为 false。
id 第三方页面显示二维码的容器id
appid 应用唯一标识,在微信开放平台提交应用审核通过后获得
scope 应用授权作用域,拥有多个作用域用逗号(,)分隔,网页应用目前仅填写snsapi_login即可
redirect_uri 重定向地址,需要进行UrlEncode
state 用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验
style 提供"black"、"white"可选,默认为黑色文字描述。详见文档底部FAQ
href 自定义样式链接,第三方可根据实际需求覆盖默认样式。详见文档底部FAQ

第二步:通过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

参数说明

参数是否必须说明
appid 应用唯一标识,在微信开放平台提交应用审核通过后获得
secret 应用密钥AppSecret,在微信开放平台提交应用审核通过后获得
code 填写第一步获取的code参数
grant_type 填authorization_code

返回说明

正确的返回:

{ 
"access_token":"ACCESS_TOKEN", 
"expires_in":7200, 
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID", 
"scope":"SCOPE",
"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}

 

参数说明

参数说明
access_token 接口调用凭证
expires_in access_token接口调用凭证超时时间,单位(秒)
refresh_token 用户刷新access_token
openid 授权用户唯一标识
scope 用户授权的作用域,使用逗号(,)分隔
unionid 当且仅当该网站应用已获得该用户的userinfo授权时,才会出现该字段。

错误返回样例:

{"errcode":40029,"errmsg":"invalid code"}

刷新access_token有效期

access_token是调用授权关系接口的调用凭证,由于access_token有效期(目前为2个小时)较短,当access_token超时后,可以使用refresh_token进行刷新,access_token刷新结果有两种:

1. 若access_token已超时,那么进行refresh_token会获取一个新的access_token,新的超时时间;
2. 若access_token未超时,那么进行refresh_token不会改变access_token,但超时时间会刷新,相当于续期access_token。

refresh_token拥有较长的有效期(30天),当refresh_token失效的后,需要用户重新授权。

请求方法

获取第一步的code后,请求以下链接进行refresh_token:

https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN

参数说明

参数是否必须说明
appid 应用唯一标识
grant_type 填refresh_token
refresh_token 填写通过access_token获取到的refresh_token参数

返回说明

正确的返回:

{ 
"access_token":"ACCESS_TOKEN", 
"expires_in":7200, 
"refresh_token":"REFRESH_TOKEN", 
"openid":"OPENID", 
"scope":"SCOPE" 
}

 

参数说明

参数说明
access_token 接口调用凭证
expires_in access_token接口调用凭证超时时间,单位(秒)
refresh_token 用户刷新access_token
openid 授权用户唯一标识
scope 用户授权的作用域,使用逗号(,)分隔

错误返回样例:

{"errcode":40030,"errmsg":"invalid refresh_token"}

注意:

1、Appsecret 是应用接口使用密钥,泄漏后将可能导致应用数据泄漏、应用的用户数据泄漏等高风险后果;存储在客户端,极有可能被恶意窃取(如反编译获取Appsecret);
2、access_token 为用户授权第三方应用发起接口调用的凭证(相当于用户登录态),存储在客户端,可能出现恶意获取access_token 后导致的用户数据泄漏、用户微信相关接口功能被恶意发起等行为;
3、refresh_token 为用户授权第三方应用的长效凭证,仅用于刷新access_token,但泄漏后相当于access_token 泄漏,风险同上。

建议将secret、用户数据(如access_token)放在App云端服务器,由云端中转接口调用请求。

第三步:通过access_token调用接口

获取access_token后,进行接口调用,有以下前提:

1. access_token有效且未超时;
2. 微信用户已授权给第三方应用帐号相应接口作用域(scope)。

对于接口作用域(scope),能调用的接口有以下:

授权作用域(scope)接口接口说明
snsapi_base /sns/oauth2/access_token 通过code换取access_token、refresh_token和已授权scope
snsapi_base /sns/oauth2/refresh_token 刷新或续期access_token使用
snsapi_base /sns/auth 检查access_token有效性
snsapi_userinfo /sns/userinfo 获取用户个人信息

其中snsapi_base属于基础接口,若应用已拥有其它scope权限,则默认拥有snsapi_base的权限。使用snsapi_base可以让移动端网页授权绕过跳转授权登录页请求用户授权的动作,直接跳转第三方网页带上授权临时票据(code),但会使得用户已授权作用域(scope)仅为snsapi_base,从而导致无法获取到需要用户授权才允许获得的数据和基础功能。 接口调用方法可查阅《微信授权关系接口调用指南》

F.A.Q

  1. 什么是授权临时票据(code)? 答:第三方通过code进行获取access_token的时候需要用到,code的超时时间为10分钟,一个code只能成功换取一次access_token即失效。code的临时性和一次保障了微信授权登录的安全性。第三方可通过使用https和state参数,进一步加强自身授权登录的安全性。

  2. 什么是授权作用域(scope)? 答:授权作用域(scope)代表用户授权给第三方的接口权限,第三方应用需要向微信开放平台申请使用相应scope的权限后,使用文档所述方式让用户进行授权,经过用户授权,获取到相应access_token后方可对接口进行调用。

  3. 网站内嵌二维码微信登录JS代码中style字段作用? 答:第三方页面颜色风格可能为浅色调或者深色调,若第三方页面为浅色背景,style字段应提供"black"值(或者不提供,black为默认值),则对应的微信登录文字样式为黑色。相关效果如下:

若提供"white"值,则对应的文字描述将显示为白色,适合深色背景。相关效果如下:

4.网站内嵌二维码微信登录JS代码中href字段作用? 答:如果第三方觉得微信团队提供的默认样式与自己的页面样式不匹配,可以自己提供样式文件来覆盖默认样式。举个例子,如第三方觉得默认二维码过大,可以提供相关css样式文件,并把链接地址填入href字段

.impowerBox .qrcode {width: 200px;}
.impowerBox .title {display: none;}
.impowerBox .info {width: 200px;}
.status_icon {display: none}
.impowerBox .status {text-align: center;} 

相关效果如下:

 

基于微信做第三方登陆时的操作:
https://open.weixin.qq.com/

 

 

这几天开发要用到微信授权的功能,所以就研究了一下。可是微信开放平台接入指南里有几个地方写的不清不楚。在此总结一下,以便需要的人。

很多微信公众平台的应用如果移植到app上的话就需要微信授权登陆了。

  1.       目前移动应用上微信登录只提供原生的登录方式,需要用户安装微信客户端才能配合使用。也就是如果第三方应用需要微信授权登陆的话就必须在本机上安装了微信。而后续授权登陆或调用接口之类的相当于app和微信两个应用之间通话。

1、首先需要注册微信开放平台,然后获取开发者认证。审批通过之后再创建一个移动应用同样还是需要审批。通过之后就可以给这个应用添加微信授权登陆以及相应功能了。这里移动应用审批通过之后会给你两个参数,一个叫AppId,一个叫Secret。这两个参数在后面用的到。

补充:写这篇文章有一段时间了。在这补充下大家容易出问题的几个地方。

1)大家在创建移动应用的时候注意的地方。

上面图片是申请移动应用时候的第二步,令我想不明白的是很多开发者还不知道应用包名和应用签名指的是什么。。。。。。。。

包名是你manifest文件里面顶层的那个package啊。

就是这个东西啊,这个东西啊少年。

2)应用签名。好吧我真不想啰嗦了。应用签名就是你同过ks文件得到的那个应用签名。如果你不知道如何获得这个签名。请按下面步骤走:

1,先把你的应用程序打包安装在你的手机上。

2,下载官网上提供的签名生成工具并安装在手机上。下面这个地方下载:

3、打开签名生成工具输入你的app的包名就生成你的应用签名了。

补充完毕。。。(对于上面这点补充我真不想多回答了。PS:我的昵称留下了QQ我很无辜啊。。。大家有问题上班时间别问好吗,哥心软不忍心拒绝啊,尤其有妹子问的时候啊。。。坟蛋)

2、在需要微信授权的项目中导入微信的第三方JAR包,这个在微信开放平台接入指南里面说的很清楚,不再啰嗦。

3、注册到微信:


这一步也没什么课解释的,相当于两人要联系的时候先打通了电话,然后开始沟通。这一步在需要和微信通话的界面之前注册了就行。我的是在欢迎界面注册的。

4、开始和微信通话

首先和微信通话之前,要在项目代码中新建一个Activity,并提供相应的回调方法供微信调用。但是这一点在接入指南上写的就不清不楚导致我浪费了好几个小时。一下内容是我在接入指南里复制来的。

a. 在你的包名相应目录下新建一个wxapi目录,并在该wxapi目录下新增一个WXEntryActivity类,该类继承自Activity(例如应用程序的包名为net.sourceforge.simcpux,则新添加的类如下图所示)

 

并在manifest文件里面加上exported属性,设置为true。

一定要注意上面这句话:在你的包名相应目录下新建一个wxapi目录。说的是在包名相应目录下建一个wxapi目录。也就是是包名目录的子目录,千万不要直接在src下面建个包就完了。(粗心这毛病害死人啊。)

然后再这个包下面建一个类:

WXEntryActivity  Activity  IWXAPIEventHandler{  

  
 IWXAPI api;  
      
  onCreate(Bundle savedInstanceState) {  
          
.onCreate(savedInstanceState);  
        setContentView(R.layout.flash_activity);  
, Property.wxLoginInfo.getAppid(), );  
        api.handleIntent(getIntent(), );</span>  
  
      onReq(BaseReq arg0) {  
  
          
  
      onResp(BaseResp resp) {  
 Bundle();  
         (resp.errCode) {  
 BaseResp.ErrCode.ERR_OK:  
  
//      resp.toBundle(bundle); //      Resp sp = new Resp(bundle); //      String code = sp.code;<span style="white-space:pre"> //      或者   
;  
:  
;  
        }  
}  

 


注意:上面是获取code。现在最新的官方jar包好像不支持获得code了。直接就能得到token,省略了获取code 这一步。所以方法不变,大家取的时候直接resp.token就行了。不用再去取code了。但是,但是,这样直接拿到token了好像按照官方文档上的方法就不能获得openid了。我也没尝试有什么新的方法,反正是jar包更新了但是文档还没更新,大家弄不成功的话可以先用旧的jar和上面获取code的方法。点击下载旧版jar包
这是那个WXEntityAcitivity的部分代码。结合接入指南,大家应该都看的懂。

然后开始和微信通话,

= =>{   
 SendAuth.Req();  
req.scope = ;  
;  
api.sendReq(req);  
}  

 

这一步就是和微信要code。执行了这一段代码之后。微信会调用刚才WXEntityActivity类里面的onResp()方法。并且把code返回来了。见上面那一段代码。获取到code之后就可以通过code获取access_token了。

请求以下链接获取access_token:

 

https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

这步和微信通信获得access_token就是普通的访问链接。 用httpClient就行了,而不是接入指南里说的那个和微信通信的方法onReq().然后还是这样的方式通过access_token.就可以调用接口获得用户基本信息了。具体返回参数什么的接入指南里面说的很清楚。至此微信授权基本是成功了。

不过在开发的过程中要注意一下debug keystore。就是Window->Preferences->Android->Build里面。

这里,我们要添加Custom debug keystore。上面的那个debug keystore不会和微信通信。

而我们添加的这个keystore 也要符合一些规范所以要改一改。

那就是keystore的密码改为:android

其中,my.keystore是要修改的证书文件,执行后会提示输入证书的当前密码,和新密码以及重复新密码确认。这一步需要将密码改为android

alias的名称要改为:androiddebugkey

android 这一步中,my_name是证书中当前的alias,-destalias指定的是要修改为的alias,这里按规矩来,改为androiddebugkey!这个命令会先后提示输入keystore的密码和当前alias的密码。

keystore的alias密码也改为:android

keytool -keypasswd -keystore my.keystore -alias androiddebugkey

这一步执行后会提示输入keystore密码,alias密码,然后提示输入新的alias密码,同样,按规矩来,改为android!

这样修改完keystore之后把这个keystore放到上面ADT的custom debug keystore里面。就可以直接调试微信相关的功能了。

大概就这几点吧。 

 
http://blog.csdn.net/qq247890212/article/details/40822481 

 

微信扫码登录功能实现

原因:很简单,公司的账号登录需要用到微信扫码登录与QQ的登录功能,所以,在做好了微信的扫码登录之后,本人就写这篇微信扫码登录功能实现的教程

教程开始

需要用到的网站:

  1. https://open.weixin.qq.com/  微信开放平台
  2. https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=a655e356d87d4d330ed5cbaf1324389741826089&lang=zh_CN  微信开放平台文档


网站加入微信第三方登陆,申请OAuth应用的入口:

准备工作:

1. 首先当然登录这个微信开放平台啦,不然怎么做扫码登录的功能

2. 新建一个应用

 

3. 新建完应用后是这样子的

 

4. 进行开发者认证,1年300RMB,之前开发的时候没有进行开发者认证,微信那边一直说我有错误,后面又google又百度的,直到认证后,才正常开发

5. 设置回调地址,这里的地址相当于回调域名,可以不用详细到访问的方法内(例:http://www.baidu.com)

 

准备工作完成,正式开发

 

1. 写一个获取服务器返回数据的自定义函数或者使用PHP的 file_get_content 函数

这里的自定义函数的使用CURL

PHP CURL
//php curl(GET)请求
public function curlGet($url){
    if(empty($url)){
        return false;
    }
    $output = '';

    $ch = curl_init();
    $str =$url;
    curl_setopt($ch, CURLOPT_URL, $str);
    curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true );
    $output = curl_exec($ch);
    return $output;
}

 

2. 浏览器打开网址,这个网址是一张二维码图片,二维码的信息则是你创建的应用信息

网址:https://open.weixin.qq.com/connect/qrconnect?appid=appid&redirect_uri=redirect_uri&response_type=code&scope=snsapi_login&state=state

参数是否必须说明
appid 应用中的APPID
redirect_uri 这是回调地址,先要在授权回调域设置回调的域名地址,然后这里填写的是回调域名下需要访问的方法(这里需要使用编码 URL 字符串函数urlencode())
response_type 是     code固定参数
scope snsapi_login 固定参数, 这里有多个参数,可以用 ‘ , ’分隔,当前仅仅做微信登录,则填写snsapi_login这个参数
state 可以不填,用于防止csrf攻击,你发送什么参数,服务器则返回什么参数给你

 

3. 用微信的扫一扫获取二维码中的code参数

参数说明
code code参数
state 用于防止csrf攻击,你发送什么参数,服务器相应返回什么参数给你

 

4. 发送ACCESS_TOKEN获取请求

使用 curlGet() 自定义函数访问以下网址

https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

 

参数是否必须说明
appid 应用中的APPID
secret 应用中的AppSecret
code 上一步所获得的code参数
grant_type authorization_code 固定参数

 

5. 获取ACCESS_TOKEN参数

参数说明
access_token 接口调用凭证
expires_in access_token接口调用凭证超时时间
refresh_token 用户刷新access_token
openid 授权用户唯一标识
scope snsapi_login 固定参数,用户授权的作用域,使用逗号(,)分隔
unionid 已获得该用户的userinfo授权时,才会出现该字段。

 

6. 发送获取OPENID请求

使用 curlGet() 自定义函数访问以下网址

https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID

参数是否必须说明
access_token 接口调用凭证
openid 授权用户唯一标识

 

7. 获取用户信息

参数说明
openid 授权用户唯一标识
nickname 微信用户呢称
sex 性别
province 省份
city 城市
country 国家
headimgurl 微信头像地址   最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空
privilege 用户特权信息,json数组
unionid 用户统一标识。针对一个微信开放平台帐号下的应用,同一用户的unionid是唯一的

结语

到这里你已经成功的获取到你微信的对外信息了,你可以根据公司的开发需求开发出你所需要的微信扫码登录功能

https://my.oschina.net/u/3554366/blog/1506955

 


IM的扫码登录功能如何实现?一文搞懂主流的扫码登录技术原理  

1、引言

扫码登录这个功能,最早应该是微信的PC端开始搞,虽然有点反人类的功能(不扫码也没别的方式登录),但不得不说还是很酷的。

下面这张图,不管是IM开发者还是普通用户,应该很熟悉:

 

于是,搞IM产品的老板和产品经理们,从此又多了一个要抛给程序员们的需求——“为什么微信有扫一扫登录,而我们的没有?”。

好吧,每次只要是微信有的功能,IM程序员们想甩锅,难度就有点大了,必竟老板们都都会想当然认为,微信有的“我”的IM产品里也得有。

既然无法回避,那就只能老老实实搞懂技术原理,然后自已使劲撸吧。

本文将简要的介绍扫码登录功能的技术实现逻辑,并实际结合淘宝、微信的扫码登录功能,学习和研究大厂主流应用的技术实现思路。

2、基本技术原理

2.1 扫码登录功能到底是什么样的?

首先介绍下什么是扫码登录。现在大部分同学手机上都装有微信、qq和淘宝这一类的软件。而这些app都有他们相对应的网页端。为了让用户在使用他们的网页时登录更加方便和安全,使用手机扫一扫就可以登录的服务,就显的自然而然了。

几个主流大厂应用扫码登录时的界面效果如下:

有很多小伙伴可能会感到很神奇,网页上只是显示了个二维码,它怎么就知道是哪个手机扫到了二维码,并且进行登录的呢?而且,登录完成以后,还能直接把用户信息显示给用户,真的是很神奇啊。

2.2 扫码登录功能的完整技术逻辑

1)网页端与服务器的配合逻辑:

接下来就是对于这个服务的详细实现。

首先用户打开网站的登录页面的时候,向浏览器的服务器发送获取登录二维码的请求。服务器收到请求后,随机生成一个uuid,将这个id作为key值存入redis服务器,同时设置一个过期时间,再过期后,用户登录二维码需要进行刷新重新获取。

同时,将这个key值和本公司的验证字符串合在一起,通过二维码生成接口,生成一个二维码的图片(二维码生成,网上有很多现成的接口和源码,这里不再介绍)。然后,将二维码图片和uuid一起返回给用户浏览器。

浏览器拿到二维码和uuid后,会每隔一秒向浏览器发送一次,登录是否成功的请求。请求中携带有uuid作为当前页面的标识符。这里有的同学就会奇怪了,服务器只存了个uuid在redis中作为key值,怎么会有用户的id信息呢? 

这里确实会有用户的id信息,这个id信息是由手机服务器存入redis中的。具体请继续阅读“手机端与服务器的配合逻辑”。

2)手机端与服务器的配合逻辑:

话说,浏览器拿到二维码后,将二维码展示到网页上,并给用户一个提示:请掏出您的手机,打开扫一扫进行登录。

用户拿出手机扫描二维码,就可以得到一个验证信息和一个uuid(扫描二维码获取字符串的功能在网上同样有很多demo,这里就不详细介绍了)。

由于手机端已经进行过了登录,在访问手机端的服务器的时候,参数中都回携带一个用户的token,手机端服务器可以从中解析到用户的userId(这里从token中取值而不是手机端直接传userid是为了安全,直接传userid可能会被截获和修改,token是加密的,被修改的风险会小很多)。手机端将解析到的数据和用户token一起作为参数,向服务器发送验证登录请求(这里的服务器是手机服务器,手机端的服务器跟网页端服务器不是同一台服务器)。

服务器收到请求后,首先对比参数中的验证信息,确定是否为用户登录请求接口。如果是,返回一个确认信息给手机端。

手机端收到返回后,将登录确认框显示给用户(防止用户误操作,同时使登录更加人性化)。用户确认是进行的登录操作后,手机再次发送请求。服务器拿到uuId和userId后,将用户的userid作为value值存入redis中以uuid作为key的键值对中。

3)登录成功时的逻辑:

然后,浏览器再次发送请求的时候,浏览器端的服务器就可以得到一个用户Id,并调用登录的方法,声成一个浏览器端的token,再浏览器再次发送请求的时候,将用户信息返回给浏览器,登录成功。这里存储用户id而不是直接存储用户信息是因为,手机端的用户信息,不一定是和浏览器端的用户信息完全一致。

4)详细的技术原理总结如下图所示: 

3、淘宝的扫码登录技术实现

本节我们以淘宝的扫码登录为例,来实际研究分析一下淘宝的扫码登录实现逻辑。

登录界面 https://login.taobao.com/member/login.jhtml 传回来的参数为:

然后请求(GET)报文是这样的:

https://qrlogin.taobao.com/qrcodelogin/qrcodeLoginCheck.do?lgToken=2c3b4d53ef0513787bf4ce711ea5ba53&defaulturl=&_ksTS=1540106757739_2804&callback=jsonp2805

关键的就是lgToken,是网页的唯一ID,当打开了二维码登录的时候,网页在轮询(应该是长轮询long polling)调用接口去请求服务器。

如果没有扫码,返回的为: 

如果扫了的话则会返回:

{

    "code": "10001",

    "message": "mobile scan QRCode success",

    "success": true

}

长时间没有扫码的话,网页端会停止轮询,二维码失效!

当手机端确认登录后,接口返回的是:

{ "code": "10006", "success": true, "url": "https://login.taobao.com/member/loginByIm.do?uid=cntaobaoxxx&token=ff82fc0d1d395a33d3b38ec5a4981336&time=1530179143250&asker=qrcodelogin&ask_version=1.0.0&defaulturl=https://www.taobao.com&webpas=0b7aed2d43f01825183e4a49c6cae47d1479929926"}

表示登录成功,当然手机端与服务端在点击"确认登录"之间的交互可能就是这样:网页端生成的lgToken去请求服务端,服务端记住了这个lgToken并认为登录了,当网页端再次轮询请求接口时,就返回真正的登录态Token,网页端此时就可以凭着这个Token来登录了。

详细的技术逻辑如下图所示:

4、微信的扫码登录技术实现

4.1 技术原理流程图

 

微信的网页版访问地址是:https://wx.qq.com/,有兴趣也可以自行深入研究。

4.2 实际的技术实现逻辑

1)获取唯一的uuid, 以及包含uid信息的二维码:

// 获取uuid

getUUID: function() {

    vare = t.defer();

    returnwindow.QRLogin = {},

    $.ajax({

        url: i.API_jsLogin,

        dataType: "script"

    }).done(function() {

        200 == window.QRLogin.code ? e.resolve(window.QRLogin.uuid) : e.reject(window.QRLogin.code)

    }).fail(function() {

        e.reject()

    }),

    e.promise

}

2)浏览器轮询服务器,获取扫码状态:

// 查看扫码状态

checkLogin: function(e, a) {

    varn = t.defer()

        , a = a || 0;

    returnwindow.code = 0,

    window.checkLoginPromise = $.ajax({

        url: i.API_login + "?loginicon=true&uuid="+ e + "&tip="+ a + "&r="+ ~newDate,

        dataType: "script",

        timeout: 35e3

    }).done(function() {

        newRegExp("/"+ location.host + "/");

        if(window.redirect_uri && window.redirect_uri.indexOf("/"+ location.host + "/") < 0)

            returnvoid (location.href = window.redirect_uri);

        vare = {

            code: window.code,

            redirect_uri: window.redirect_uri,

            userAvatar: window.userAvatar

        };

        n.resolve(e)

    }).fail(function() {

        n.reject()

    }),

    n.promise

}

3)根据服务器返回的扫码状态,进行相应的操作:

* 408 扫码超时:如果手机没有扫码或没有授权登录,服务器会阻塞约25s,然后返回状态码 408 -> 前端继续轮询 

* 400 二维码失效:大约5分钟的时间内不扫码,二维码失效  

* 201 已扫码:如果手机已经扫码,服务器立即返回状态码和用户的基本信息 (window.code=201,window.code.userAvator="..."),-> 前端继续轮询  

* 200 已授权:如果手机点击了确认登录,服务器返回200及token -> 前端停止轮询, 获取到token,重定向到目标页 

具体的代码示例如下:

// 根据服务器返回的扫码状态,进行相应的操作

functiono(c) {

    switch(c.code) {

    case200:

        t.newLoginPage(c.redirect_uri).then(function(t) {

            varo = t.match(/<ret>(.*)<\/ret>/)

                , r = t.match(/<script>(.*)<\/script>/)

                , c = t.match(/<skey>(.*)<\/skey>/)

                , s = t.match(/<wxsid>(.*)<\/wxsid>/)

                , l = t.match(/<wxuin>(.*)<\/wxuin>/)

                , d = t.match(/<pass_ticket>(.*)<\/pass_ticket>/)

                , f = t.match(/<message>(.*)<\/message>/)

                , u = t.match(/<redirecturl>(.*)<\/redirecturl>/);

            returnu ? void (window.location.href = u[1]) : o && "0"!= o[1] ? (alert(f && f[1] || "登录失败"),

            i.report(i.AUTH_FAIL_COUNT, 1),

            void location.reload()) : (e.$emit("newLoginPage", {

                Ret: o && o[1],

                SKey: c && c[1],

                Sid: s && s[1],

                Uin: l && l[1],

                Passticket: d && d[1],

                Code: r

            }),

            void (a.getCookie("webwx_data_ticket") || n.report(n.ReportType.cookieError, {

                text: "webwx_data_ticket 票据丢失",

                cookie: document.cookie

            })))

        });

        break;

    case201:

        e.isScan = !0,

        n.report(n.ReportType.timing, {

            timing: {

                scan: Date.now()

            }

        }),

        t.checkLogin(e.uuid).then(o, function(t) {

            !t && window.checkLoginPromise && (e.isBrokenNetwork = !0)

        });

        break;

    case408:

        t.checkLogin(e.uuid).then(o, function(t) {

            !t && window.checkLoginPromise && (e.isBrokenNetwork = !0)

        });

        break;

    case400:

    case500:

    case0:

        vars = a.getCookie("refreshTimes") || 0;

        s < 5 ? (s++,

        a.setCookie("refreshTimes", s, .5),

        document.location.reload()) : e.isNeedRefresh = !0;

        break;

    case202:

        e.isScan = !1,

        e.isAssociationLogin = !1,

        a.setCookie("login_frequency", 0, 2),

        window.checkLoginPromise && (window.checkLoginPromise.abort(),

        window.checkLoginPromise = null),

        r()

    }

    e.code = c.code,

    e.userAvatar = c.userAvatar,

    a.log("get code", c.code)

}

4.3 小结

微信网页端扫码登录时,轮询的数据返回采用的是JSONP的形式,这是为了解决跨域问题。如对JSONP不了解的,可以阅读《详解Web端通信方式的演进:从Ajax、JSONP 到 SSE、Websocket》一文的“三、JSONP”这一节。

微信网页端扫码登录时,轮询采用了后台根据扫码情况阻塞前台请求,优化轮询及减少前端的无效轮询。这种技术,请详见《新手入门贴:史上最全Web端即时通讯技术原理详解》一文中的“解决方案3.2:长轮询(long-polling)”这一节,

5、本文小结

扫码登录这个功能,现在已经不只出现有IM应用里,各种带有移动端的线上网站也都有了这个功能,所以本文中介绍的技术原理并不局限于只用于实现IM应用中的扫码登录。

另外,为了方便抓取真实的数据进行分析研究,本文中的PC端案例分析是针对的是网页端,但实际上如果你的PC端是富客户端(也就是.exe、.dmg这样的安装版),原理也是一样的,而且还不需要考虑浏览器里的跨域问题等。

阅读本文时,可能涉及到传统的Web端即时通讯技术(为了扫码登录的实时性),比如长轮询等,如果您对这些技术还不太了解的话,可以系统学习一下即时通讯网整理的有关Web端即时通讯方面的资料。比如从这两篇文章开始:《新手入门贴:详解Web端即时通讯技术的原理》、《Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE》。(本文同步发布于:http://www.52im.net/thread-2892-1-1.html

https://my.oschina.net/u/4231722/blog/3154805

 

posted @ 2016-12-16 17:46  沧海一滴  阅读(1321)  评论(0编辑  收藏  举报