微信公众平台的账号分为服务号、订阅号、企业号3种类型。而个人类型的订阅号在开发功能上有很多的限制。比如自定义菜单、oauth2.0接口等。其中,自定义菜单功能可以通过命令交互
的方式来代替。
OAuth2.0接口可以实现用户通过微信公众号访问网页的时候获取用户的openid、个人信息等。但是个人订阅号微信平台不提供这个接口,其实很多时候我们只需要得到用户的openid就可以
了。
我们知道,用户在通过微信平台和我们进行消息交互的时候,我们通过微信平台传来的xml数据包进行数据获取。这个xml数据包包含有一个FromUserName的参数,就是指的用户的openid。
于是我们可以通过这一原理来传递用户访问网页时候的openid。
以下是具体步骤:
一、用户提出获取网页网址的请求。
我们的账户类型是订阅号,无法通过菜单来实现。所以只能通过被动的方式传递信息。用户发送“查询网址”的消息给微信平台后,微信平台顺手将消息封装成一定格式的xml传递给我们的
服务器。我们的服务器就得到这个“查询网址”的命令,知道用户想获取网页地址。于是随机生成一个密码,把这个密码存入数据库中。接下来将密码和openid加密后作为网页的参数和网
址一起回传给微信平台,微信平台再将消息回复给用户。过程如下图所示:
二、用户点击网址
用户点击这个带有加密参数的网址,服务器网页接收到用户的请求后,先将参数进行解密,分解为openid和密码2个部分。首先验证密码是否正确,如果不正确,则拒绝访问,要求用户重新回复“查询网址”命令生成网址。如果密码正确,则密码失效,重新生成一个密码写入session和数据库,接下来就通过session进行验证,并且我们也得到了用户的openid。密码一次失效机制防止没关注的用户访问。如下图:

三、存在的问题
我们通过密码和session来验证用户,openid通过微信平台的消息互发来获取。要访问网址要求用户必须和我们的消息交互程序交互一次,以获得用户的openid和密码,密码一次失效的机制也能防止用户转发消息来冒充身份。那么,这就存在一个问题,如果用户通过合法的关注渠道得到网址后,不去访问网址,直接将网址转发给别人,那么我们获取到的openid就不是这个用户本身。但是这可以算作是一种授权行为,因为关注的用户有转发的动作。
四、asp版部分代码
1、生成网址:
<%
'得到用户的openid和获取网址的意图,方法参考:http://www.yufeng.org.cn/view_article.asp?id=26
set rsw=server.CreateObject("adodb.recordset")
rsw.open "select webmima from [users] where weixinhao='"&weixinhao&"'",conn,1,3 'weixinhao即用户的openid,通过xml数据获取。
if rsw.recordcount<1 then
stringback="nouser"
else
randomize()
strrnd=int(10000000+89999999*rnd()) '生成8位随机密码写入数据库中
rsw("webmima")=cstr(strrnd)
rsw.update
strrnd=base64(weixinhao&strrnd) '将openid和mima用base64加密,也可以自定义加密解密算法
stringback="请点击:http://www.yufeng.org.cn/nav.asp?authcode="&server.URLEncode(strrnd)&"(一次有效,再次访问须重新生成)" '将加密后的字符作为参数加入网
址中,用URLEncode可以将一些保留url字符编码
end if
rsw.close
set rsw=nothing
'接下来是回传给微信平台的代码,参考:http://www.yufeng.org.cn/view_article.asp?id=26
%>
2、身份验证:
<%
session("weixinhao")=sqlcheck(session("weixinhao"))
session("webmima")=sqlcheck(session("webmima"))
if session("weixinhao")="" or session("webmima")="" then
'进入系统,首先验证session是否存在,以及是否合法。
'如果session不存在,则需要看是否有authcode被request到,如果有request到,则通过以下代码进行验证
authcode=request("authcode")
if authcode="" then
founderr=true
else
authcode=base64jiemi(authcode) 'base64解密,也可以自定义加密解密算法
authcode=sqlcheck(authcode) '对传递来的参数进行过滤,防止sql注入等恶意代码
if len(authcode)<>36 then 'openid有28位,我们采用的密码是8位随机码,所以这里判断是否等于36
founderr=true
else
weixinhao=left(authcode,28) '分别获得openid和随机密码
webmima=right(authcode,8)
set rs=server.CreateObject("adodb.recordset")
rs.open "select webmima from [users] where weixinhao='"&weixinhao&"' and webmima='"&webmima&"'",conn,1,3
if rs.recordcount>0 then
'如果验证成功,则当前webmima失效,重新生成webmima写入数据库和session中
isequ=true
do while isequ
'这个循环用来保证重新生成的webmima不能和原来的webmima相同
randomize()
strrnd=int(10000000+89999999*rnd())
if strrnd<>webmima then
webmima=strrnd
exit do
end if
loop
rs("webmima")=webmima '将生成的密码重新写回数据库,即密码一次失效。
rs.update
session("weixinhao")=weixinhao '并且将openid和webmima写入session中,用来在其他页面中验证。
session("webmima")=webmima
else
founderr=true
end if
rs.close
set rs=nothing
end if
end if
else
founderr=true
end if
if founderr then
'返回出错信息,让用户重新获取
response.write "请通过微信回复“查询网址”重新生成网址后访问。"
else
'后续处理代码
end if
%>