之前一直计划给现在系统加上第三方登录的功能,最近终于是有了时间去研究实现
因为逻辑实在有些繁琐,下面的记录尽量挑些重点来讲了,有些没提到的,各位自行去找其他文章结合地看吧,然后也没啥图片补充
授权步骤
首先先介绍Oauth2的授权步骤
- 在第三方平台上创建账号,申请对应的服务开通得到appkey,appid等数据
- 在第三方平台上在设置回调地址A
- 构建第三方授权地址B,用户访问此地址B,会进入到第三方平台(如QQ)的快捷登录页面
- 用户在第3步同意授权,第三方平台会将相关用户参数拼接到我们的回调地址A,并让网页重定向,我们系统从而就可以得到用户的第三方id(接口是我们写的)
- 我们系统可以根据此id,获取到
access_token
,再由access_tooken
去获取用户的昵称,头像等基本信息 - 之后根据上述信息,走注册或登录流程
注册的话,将上面的一些基本信息入库即可,关键的就是id
然后可以通过id去数据库查询是否存在有用户,存在有用户则跳转登录流程,否则就进入注册流程
上面说的id,对于一般oauth2的流程来说,就是openid
而因为QQ第三方平台是区分网站应用和app应用,如果使用openid,会导致Web系统和APP应用的id对应不上,所以这里注意要使用unionID
下面如果是针对QQ说的openId,都是指的unionId
需要取申请unionid的权限,如下图所示:
由于我是使用了JustAuth这个库,具体获取信息的逻辑已经帮我们做好,我们只需要调用接口,具体使用可以看官方文档
补充说下: QQ的网页应用的基本信息在审核通过之后最好不要随便修改,改个logo(没点保存)都会进入审核状态,贼离谱,我之前就是要开发联调,不小心动到了,都要去重新审核,搞得我没法测试也是无语…
功能实现(PC软件)
上面讲明了Oauth2的授权流程,下面讲解下我的思路
PC软件想要实现QQ登录,可以借用Webview,打开上面第3步里的地址B即可
这里需要提下: 第3步的地址B,可以通过前端(客户端)拼接获取或者通过服务器后端接口返回
我这里是选择了服务器后端接口去处理得到授权地址,之后得到授权地址后,再让PC软件的webview去打开页面地址
这里,就有个问题,我们如何获得用户信息?
实际上,用户信息是服务器后端拿到access token之后再去调用第三方平台(QQ)提供的API才拿到的
真正的网站应用这个处理注册或登录的流程就是在服务端去做处理了
但我们的不是网站应用,这个注册或登录流程得放在软件上做,那么我们的软件就得获取到用户的相关信息,并判断用户是否注册,再进行相关的页面展示(如直接登录成功或跳转到注册页)
这里我选择通过网页回传数据给客户端(即webview里的js交互通信)
在上述步骤的第4步中,当重定向完成,跳转到我们服务端的回调地址A后,我们将此回调地址A最终返回一个html网页数据(并将得到的第三方平台的用户信息都写在这个网页上)
这里我是写到了js中,因为我们要通过js进行数据交互(实际上我就是给了一个js变量)
之后,我们客户端的webview,监听网页加载是否完成,然后执行
JSON.stringify()
方法,将js变量转为string字符串数据,即可拿到数据了之后的判断是否注册的逻辑,则是调用了服务端的一个根据openId查询用户是否存在的API接口即可得到结果
下面的部分代码(JavaFx中的webview数据交互):
webview {
engine.loadWorker.stateProperty().addListener { observable: ObservableValue<out Worker.State>?, oldState: Worker.State?, newState: Worker.State ->
if (newState == Worker.State.SUCCEEDED) {
val result = kotlin.runCatching {
// 调用 JavaScript 代码
val result = engine.executeScript("""
JSON.stringify(myData)
""".trimIndent())
result
}
result.getOrNull()?.let {
//根据openid调用自己的接口,判断是否注册
//跳转逻辑处理页面
}
}
}
urlPro.onChange {
it?.let {
println("加载url: $it")
engine.load(it)
}
}
}
urlPro是个可观察对象,是调用了获取授权地址的接口之后再通知数据变更,之后就会进入到上面的onChange方法,从而让weview加载第三方平台授权地址的url
PS: 数据库设计方面就比较简单,就是用户表多了2个字段,一个是openid,一个是第三方平台昵称,没想着搞多个表
Github的和上面的同理,这里不再赘述
处理注册和绑定
上面也提到,客户端拿到了第三方用户信息(如openId等),之后通过调用服务端的接口,从而得知当前用户是否是已注册的
如果是注册过的,则直接调用登录接口C(这个接口也是由服务端提供,是根据openId快捷登录)
因为我是做了两个平台的支持,所以登录接口C要求客户端需要传入openId后,还需要传入一个字段,用来标明是哪个平台的,之后服务端那边才好去根据信息去查询用户信息,从而完成登录的流程
PS:当然,上面说的那个回调地址A也是如此,也需要传入一个字段(参数是追加到url后面的,这样到时候去各平台上就比较方便),具体的JustAuth里也有提到
如果没有注册,则会进入到注册的页面,并让用户再填写信息,调用注册接口时候会将第三方数据传入,之后注册的时候就已经包含了第三方平台的信息
从大厂的,这里实际上应该是直接完成注册逻辑了,然后之后就是提示用户绑定手机号了,然后修改密码什么的,都可以在个人中心里去修改,不用用户注册的时候输入
因为我感觉上述的逻辑交互太麻烦了,我这里不采用这种了
我这边就是进入注册页,让用户输入邮箱,密码等信息完成注册流程
如果是针对于普通注册用户,可以给他们提供一个绑定第三方账号的功能,我是放在了个人中心页
绑定也是比较简单,和上述说的流程差不多,也是先获取到用户第三方的授权信息,之后再调用一个绑定第三方账号的接口完成操作即可(实际上就是把数据库里那个openId和昵称数据存下就ok了)
当然,也要提供解绑功能,解绑则是重置下openId和昵称两个字段
功能实现(Android版软件)
如果是Github,和上面的同理,也是通过webview去拿取数据集即可,这里就不再赘述
但是QQ是区分了APP端的,APP端需要使用SDK,所以Android版软件可以使用SDK来获取第三方用户信息(openId,昵称等)
注意: 这里和上面PC一样,是使用unionId
同样流程,去QQ互联中心去创建一个应用,需要注意的是,填写信息的时候,需要填写应用包名和签名(单个应用可以绑定6组包名和签名)
这里不得不吐槽一下,QQ那边提供了一个获取签名的软件,但是这个软件在高版本的系统上使用存在问题,无法扫描到我自己开发的APP
最后还是去找了微信那边的提供的获取签名工具获取的
补充
之后功能上线后,看到存在一些错误的日志,原因是用户昵称是那种表情或者是特别字符,将用户表和对应的字段字符集更改即可(我这里是通过Navicat软件来改的)
评论区