微信网页授权功能实现
微信网页授权功能就是当用户在微信客户端访问第三方网页的时候,通过用户授权可以获取用户的相关信息,如ID、昵称、性别等数据,从而在网页功能中实现一些同具体用户相关的业务逻辑。
一、配置回调域名
这里以测试号为例(普通公众号的方法类似),到微信公众号管理后台,选择“开发者工具-公众平台测试号”,在下方列表中找到“网页服务-网页账号(网页授权获取用户基本信息)”,点击修改,在弹出的对话框中输入自己服务器的域名,微信将用这个域名同服务器交换信息。
二、选择获取用户信息的授权方式
有两种获取用户信息的授权方式,一种叫做“snsapi_base”,也是缺省的授权方式,第二种方式叫做“snsapi_userinfo”。这两种方式的区别是得到的用户数据不一样,第一种只能获取用户的ID,第二种可以获取用户完整的数据。
第一种也叫做静默授权,用户无感知,微信直接回调第三方网页,同时把一些数据传给网页所在的服务器。比如下面要提到的 code。第二种授权需要用户确认,才能进入到第三方网页,如果用户关注了公众号,而且从公众号界面进入第三方网页,比如公众号中的菜单、消息链接等,这时也是静默方式,授权页面不会出现,也将直接进入到第三方的网页。
三、实现流程
1、引导用户进入授权
就是放置授权链接在需要的地方,比如公众号中的菜单、消息中的链接,这个授权链接带有回调第三方网页地址的参数,通过用户授权后,微信会回调这个网址。
两种授权链接分别是:
(1)snsapi_base
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect
(2)snsapi_userinfo
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect
其中的appid可以在公众号管理后台查到,redirect_rui 就是授权后要回调的第三方网页地址,state 可以根据自己需求来设置,微信回调的时候会原封不动地回传这个state参数值,同时还要传送code,后面的操作需要这个code。
2、用户同意授权,获取code
用户同意授权后,微信按照上面设置好的回调地址(第三方网页)进入到相关的网页链接,同时发送 code 和 state 两个数值,其中拿到的 code 用来获取一个访问用户信息的令牌(access_token)。这个 code 有期限,5分钟不使用将过期。
3、获取访问用户信息的令牌(access_token)
使用这个令牌才能拿到用户信息,这个令牌和前面文章中讲到的令牌不一样,这个只是用于网页授权获取用户信息的。
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
其中的 code 参数填写第二步拿到的 code,appid 和 secret 在公众号后台可以查到。该步正确完成后,微信会发送返回结果给服务器,其中包括访问令牌(access_toke)和刷新令牌(refresh_token)。这步返回的结果中也含有用户的 ID 数据。
由于访问令牌有2个小时的有效期,过期后需要重新获取,这就要通过返回的刷新令牌(refresh_token)参数来获取。
https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN
刷新令牌有30天的期限,过期后访问第三方网页获取用户数据就需要重新做用户授权。
4、获取用户信息
通过用户ID(openid)和令牌(access_token)拉取用户数据。
https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
5、其它
判断当前令牌(access_token)是否有效的调用方式是:
https://api.weixin.qq.com/sns/auth?access_token=ACCESS_TOKEN&openid=OPENID
四、实现代码
setupmenu.py #放置授权链接在公众号的菜单上
from wechatpy import WeChatClient
from wechatpy.oauth import WeChatOAuth
from redisclient import redissession
import config
class Menu(object):
def __init__(self):
pass
def create(self):
client = WeChatClient(config.appId, config.secret, session=redissession)
client.menu.create({
"button":[
{
"type":"click",
"name":"微信关注",
"key":"wx_qr_code"
},
{
"type":"click",
"name":"微博关注",
"key":"wb_qr_code"
},
{
"name":"更多精彩",
"sub_button":[
{
"type":"view",
"name":"博客",
"url":"https://www.kflyo.com/"
},
{
"type":"view",
"name":"微博",
"url":"https://weibo.com/kflyo"
},
{
"type":"view",
"name":"关于",
"url":"https://www.kflyo.com/about-me"
},
{
"type":"view",
"name":"微信网页",
"url":WeChatOAuth(config.appId, config.secret, config.redirect_url, "snsapi_userinfo", "xxx").authorize_url
}
]
}
]
})
homepage.py #微信回调网页,获取code、令牌、用户信息等数据。
import web
from wechatpy.oauth import WeChatOAuth
import config
from jssdk import jsSDK
class HomePage:
def GET(self):
code = web.input(code="none").code
state = web.input(state="none").state
nickname = ""
if code!="none" and state=="xxx":
wcoa = WeChatOAuth(config.appId, config.secret, config.redirect_url, "snsapi_userinfo", "xxx")
wcoa.fetch_access_token(code)
if !wcoa.check_access_token():
wcoa.refresh_access_token(wcoa.refresh_token)
resjson = wcoa.get_user_info()
nickname = resjson['nickname'] #用户昵称
render = web.template.render('templates', base='base')
url = web.ctx.home + web.ctx.fullpath
jssdk = jsSDK().getJsSdk(url)
return render.home('Hello world ' + nickname, '首页', jssdk)