^

为JAVAFX项目接入微信公众号扫码绑定功能

开发背景

我的项目Un1kPoc发行了测试版本。这意味着在测试期间,一切数据上报、漏洞信息获取都得走我的API。

由此我们需要做授权控制,并且授权控制也可以在团队管理中起到“分级”的功能。所以这个功能从设计之初就被我作为核心的部分加了进去。使用的是邮箱+32位随机密钥。用户从接口获取数据时,判断两要素合法性,获取对应权限,之后再判断需要获取的漏洞列表和需要获取的漏洞信息。

这样做的好处就是,密钥和邮箱的判定过程取决你服务端API的部署情况。如果是内网API一样可以做到授权控制。坏处就是用户操作比较麻烦,需要索取密钥邮箱并填写配置。由于需要知道密钥所有者的信息,必须填写邮箱字段来确定身份(如果给授权信息添加使用者的次信息,参数越多,使用起来会更加麻烦)。邮箱可以是临时邮箱,在判定使用者身份时,必须通过填写问卷发送邮件带授权码的形式进行,需要额外写一个自动发信的功能来简化流程,但这也不能够根本解决临时邮箱的问题。完全可以授权了,后期即使邮件不可用,也一样可以通过授权认证。

我之前写过一个项目,depysso。它的流程是通过微信公众号的扫码认证后拿到openid,后续在后台比对绑定的账号,再设置session赋予权限。想了一想un1kpoc公网版本貌似也可以做到这样,无非是需要解决扫码后的事件罢了。他的好处就是,扫码后可以直接绑定openid到后台,赋予权限,并且微信官方有api可以检测openid是否合法防止伪造,也能够定位到微信身份。最重要的是操作简单,

我在百度和谷歌都没有找到过关于javafx有关写扫码登录或者授权的功能,或者是自己打开方式不太对,代码写了一个多小时,就当作一个记录吧。

实现原理

原理其实都差不多,在web的授权认证逻辑中,处理方式如下:

1.通过接口拿到ticket

2.通过微信接口根据ticket获取二维码

3.用户扫码后,回调给服务器ticket和openid 设置session

4.服务器插入openid与ticket 并通过接口 使用ticket可以查询扫码情况(有记录就是被扫码 否则就是没扫码)

5.前端轮询或者长链接判断是否被扫码 扫码了就跳转后台(此时session已经被设置了 可以进入后台)

按照这个原理,我需要思考一下javafx客户端的实现方法。

实现方法

1,2步相同。使用代码将图片渲染到imageview组件上

image.png

我打算通过点击一个item后触发一个controller 通过数据库获取openid来判断 用户是否已经绑定了微信公众号

image.png

具体流程如下:

1.用户判定没有绑定公众号,进入视图渲染,在控制器初始化获取一个ticket,以及相应的二维码

2.起一个扫码检测的轮询线程,每两秒发送ticket到服务器判断是否被扫码了

3.如果响应时openid而不是0,就获取这个openid保存数据库,然后替换二维码图片为扫码成功、结束等图片

看着挺简单的,其实还是有一些问题。在我发起轮询线程后,设置了几个条件才会继续检测:

1.控制器的openid值为空(代表没有触发回调,也就是扫码的event不正确,不是微信扫码)

2.时间到了60s

为什么需要这样设计呢?其实也是资源消耗的问题,如果用户进入了扫码绑定的界面,但是忘记操作了。那么后台会一直轮询检测,访问我的服务器接口,从而消耗我accesstoken的使用次数。一两个人还可以,如果人数一多,资源根本不够用。所以当时间到一分钟的时候,需要点击按钮重新获取一个二维码重新开启一个扫码检测线程。

为了配合一分钟超时机制,所以在公众号产生ticket时,我给他设置了60s超时,使得超过一分钟的二维码无法被扫码。

所以我给线程做了计数器,每次轮询访问一次接口,计数器+2(因为线程的等待时间时2s,可以自己设置),当count=60时,while循环结束。

image.png

代码中,我把按钮的可视设置为true,同理,点击按钮后设置为false,这样用户只能在过期的时候点击按钮。

image.png

点击按钮后,重新起一个线程和获取二维码。

如果是用户扫码了,也就是轮询接口获取到了openid,那么就不满足openid不为空的条件,也会停止线程。

image.png

然后扫码后把图片替换成别的即可。

image.png

一方面是更新本地数据库,另一方面是往api插入openid,判断是否存在,设置最低权限。调整高权限还是需要管理员去后台更改,如果要搞什么卡密模式也是可以的,但不在讨论范围内。

但是这还是有个问题,在我们不扫码的时候。如果用户想关闭窗口,退出程序,是无法完全关闭的。控制台会显示持续运行,因为60s没有到,线程就没有结束。

所以我们需要设置一个标志checkstatus,并且线程持续的条件是这个status为true。默认为true,什么时候是false呢?当然是关闭的时候是false啦。设置了这个参数,那么就可以不把count作为条件判断,到60s超时的时候设置成false即可。

image.png

我们把控制器初始化的时候保存到factory里,直接修改他的公共属性为false。那么就会不满足判定条件而停止线程,防止用户需要等60s才可以完全关闭程序。

接入公众号意味着更多的可能性,更少的认证方式。仅需要一个openid就可以实现用户授权与用户身份管控,并不是吃饱了没事干才有的想法。即使用户获取到了我的数据插入接口,也无法插入不合法,非我公众号的openid来绕过扫码验证。

image.png

除非用户主动泄漏openid,不然其他人也不能够伪造获取漏洞列表与对应信息。

这还意味着用户需要关注公众号,之后可以通过公众号来实现一些webhook推送、组内协同。举个例子,接入un1klog公众号推送

image.png

在pocshare功能内,直接指定组内人员推送消息与分享poc。

还有更多更多的功能,需要之后再去实现啦。