一、 问题
有时候,在微信客户端外点击一个链接:
1.会提示此链接必须在微信客户端访问,这是为什么呢?
2.在微信客户端中访问第三方网页,为什么会出现一个页面,上面要获取你的个人信息,让你确定后才能进入呢?
二、解答这两个问题之前,我们先了解一点微信开发的规范。(此处参看微信公众平台开发文档)
为了识别用户,每个用户针对每个公众号会产生一个安全的OpenID,如果需要在多公众号、移动应用之间做用户共通,则需前往微信开放平台,将这些公众号和应用绑定到一个开放平台账号下,绑定后,一个用户虽然对多个公众号和应用有多个不同的OpenID,但他对所有这些同一开放平台账号下的公众号和应用,只有一个UnionID,可以在用户管理-获取用户基本信息(UnionID机制)文档了解详情。
关于网页授权回调域名的说明
1、在微信公众号请求用户网页授权之前,开发者需要先到公众平台官网中的“开发 – 接口权限 – 网页服务 – 网页帐号 – 网页授权获取用户基本信息”的配置选项中,修改授权回调域名。请注意,这里填写的是域名(是一个字符串),而不是URL,因此请勿加 http:// 等协议头;
2、授权回调域名配置规范为全域名,比如需要网页授权的域名为:www.qq.com,配置以后此域名下面的页面http://www.qq.com/music.html 、 http://www.qq.com/login.html 都可以进行OAuth2.0鉴权。但http://pay.qq.com 、 http://music.qq.com 、 http://qq.com无法进行OAuth2.0鉴权
3、如果公众号登录授权给了第三方开发者来进行管理,则不必做任何设置,由第三方代替公众号实现网页授权即可
关于网页授权的两种scope的区别说明
1、以snsapi_base为scope发起的网页授权,是用来获取进入页面的用户的openid的,并且是静默授权并自动跳转到回调页的。用户感知的就是直接进入了回调页(往往是业务页面)
2、以snsapi_userinfo为scope发起的网页授权,是用来获取用户的基本信息的。但这种授权需要用户手动同意,并且由于用户同意过,所以无须关注,就可在授权后获取该用户的基本信息。
3、用户管理类接口中的“获取用户基本信息接口”,是在用户和公众号产生消息交互或关注后事件推送后,才能根据用户OpenID来获取用户基本信息。这个接口,包括其他微信接口,都是需要该用户(即openid)关注了公众号后,才能调用成功的。
关于网页授权access_token和普通access_token的区别
1、微信网页授权是通过OAuth2.0机制实现的,在用户授权给公众号后,公众号可以获取到一个网页授权特有的接口调用凭证(网页授权access_token),通过网页授权access_token可以进行授权后接口调用,如获取用户基本信息;
2、其他微信接口,需要通过基础支持中的“获取access_token”接口来获取到的普通access_token调用。
关于UnionID机制
1、请注意,网页授权获取用户基本信息也遵循UnionID机制。即如果开发者有在多个公众号,或在公众号、移动应用之间统一用户帐号的需求,需要前往微信开放平台(open.weixin.qq.com)绑定公众号后,才可利用UnionID机制来满足上述需求。
2、UnionID机制的作用说明:如果开发者拥有多个移动应用、网站应用和公众帐号,可通过获取用户基本信息中的unionid来区分用户的唯一性,因为同一用户,对同一个微信开放平台下的不同应用(移动应用、网站应用和公众帐号),unionid是相同的。
关于特殊场景下的静默授权
1、上面已经提到,对于以snsapi_base为scope的网页授权,就静默授权的,用户无感知;
2、对于已关注公众号的用户,如果用户从公众号的会话或者自定义菜单进入本公众号的网页授权页,即使是scope为snsapi_userinfo,也是静默授权,用户无感知。
三、问题解答
问题一:
言归正传,首先解答下第一个问题,很简单,因为开发的时候,咱们都会知道,开发的是不是微信端页面(哈哈)。要求在微信里打开的,可能需要获取微信头像,所在地区等参数。如果在浏览器里面直接打开的话,这些参数获取不到,可能后面的程序就没法往下执行,所以要求用微信客户端打开。
是不是微信客户端打开,就是判断打开链接的浏览器是什么的呗,这里只需要用js判断一下就行了,下面是代码,顺带赠送,安卓和ios客户端的判断,网上一搜也是一大把。
//判断是否为微信 function Is_WeiXin() { var ua = window.navigator.userAgent.toLowerCase(); if (ua.match(/MicroMessenger/i) == 'micromessenger') { return true; } else { return false; } } //判断是否为安卓 function Is_Android() { var u = navigator.userAgent; var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1; //android终端 return isAndroid; } //判断是否为IOS function Is_Ios() { var u = navigator.userAgent; var isiOS = !!u.match(/(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端 return isiOS; }
if (IsWeiXin) { document.getElementById("message").className = "flxed"; } else { if (IsAndroid || IsIos) { if (IsAndroid) { self.location.href =Url_Android; return; } if (IsIos) { self.location.href = Url_Ios; return; } } else { alert("我们暂时没有可供您设备运行的版本,感谢您的支持!"); return; } }
问题二:
关于这个问题,这就涉及到微信网页授权,如果你一直不理解,我建议,你把我上面的标题二,认真多读个几遍,书读百遍其义自见,一点都不假,关键你得用心读下去,或者看开发文档(https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842),拿走不谢。
具体而言,网页授权流程分为四步:
1、引导用户进入授权页面同意授权,获取code
2、通过code换取网页授权access_token(与基础支持中的access_token不同)
3、如果需要,开发者可以刷新网页授权access_token,避免过期
4、通过网页授权access_token和openid获取用户基本信息(支持UnionID机制)
第一步:用户同意授权,获取code
下图为scope等于snsapi_userinfo时的授权页面:
用户同意授权后,如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE。
code说明 : code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。
第二步:通过code换取网页授权access_token
首先请注意,这里通过code换取的是一个特殊的网页授权access_token,与基础支持中的access_token(该access_token用于调用其他接口)不同。公众号可通过下述接口来获取网页授权access_token。如果网页授权的作用域为snsapi_base,则本步骤中获取到网页授权access_token的同时,也获取到了openid(用户的唯一标识),snsapi_base式的网页授权流程即到此为止。
尤其注意:由于公众号的secret和获取到的access_token安全级别都非常高,必须只保存在服务器,不允许传给客户端。后续刷新access_token、通过access_token获取用户信息等步骤,也必须从服务器发起。
请求方法 获取code后,请求以下链接获取access_token: https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code 正确时返回的JSON数据包如下: { "access_token":"ACCESS_TOKEN", "expires_in":7200, "refresh_token":"REFRESH_TOKEN", "openid":"OPENID", "scope":"SCOPE" } 错误时微信会返回JSON数据包如下(示例为Code无效错误): {"errcode":40029,"errmsg":"invalid code"}
第三步:刷新access_token(如果需要)
由于access_token拥有较短的有效期,当access_token超时后,可以使用refresh_token进行刷新,refresh_token有效期为30天,当refresh_token失效之后,需要用户重新授权。
请求方法 获取第二步的refresh_token后,请求以下链接获取access_token: https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN 正确时返回的JSON数据包如下: { "access_token":"ACCESS_TOKEN", "expires_in":7200, "refresh_token":"REFRESH_TOKEN", "openid":"OPENID", "scope":"SCOPE" }
第四步:拉取用户信息(需scope为 snsapi_userinfo)
如果网页授权作用域为snsapi_userinfo,则此时开发者可以通过access_token和openid拉取用户信息了。
请求方法 http:GET(请使用https协议) https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN 附:检验授权凭证(access_token)是否有效 请求方法 http:GET(请使用https协议) https://api.weixin.qq.com/sns/auth?access_token=ACCESS_TOKEN&openid=OPENID
以上说了这么多,小结一下,以下逻辑,认为是用户首次登陆。
第一步:点击url链接,判断用户是否登录(方法:根据查找本地是否有基础的access_token)
第二步:如果查到基础的access_token(一个凭证),则已经登录,就跳转到相应的页面
如果没有找到token,则没有登录过。
第三步:没有登录过:
1. 授权,拉取微信code,(方法:问题二的第一步)
2.截取到code,调接口,将code返回给后端。
3.后端拿到code,换取特殊的网页授权access_token(问题二的第二步,本步骤中获取到网页授权access_token的同时,也获取到了openid(用户的唯一标识),问题二的第三步和第四步均可执行)
4.后端根据openId,判断此用户是否在用户系统(即是否注册过)
a、在用户系统。返回给前端基础的access_token,前端将基础的access_token存在本地(本地有了基础的access_token,下次登录即可直接跳转目的页),跳转页面
b、不在用户系统。后端返给前端该用户的openId,输入手机号和验证码,调接口,把openId,手机传给后台,后台将信息存入用户系统,生成一个基础的access_token凭证,返回给前端,前端存储,跳转页面,接下来Ajax请求API时,带上token,过滤器校验token,通过就返回数据,展示数据,未通过就返回错误码提示错误信息