背景
项目需同时支持微信、QQ三方认证登录和短信验证登录,平台要求必须绑定手机号。本次接入的是三方移动应用接入,网站或公众号接入大同小异
接入环境
spring security oauth2
相关配置参考:
Security oauth2 demo
https://github.com/athc/hippo/tree/master/oauth2-security
数据库设计
一个表存平台用户信息,一个表用来存第三方的用户信息,第三方用户信息逻辑关联平台用户信息
third_user_info
第三方信息表
//区分平台
@ApiModelProperty("1qq 2 wx")
val userType: Int = -1,
//同一appId下唯一的标识,接入的是腾讯所以存的openId
@ApiModelProperty("openId")
val openId: String = "",
//token可以选存,具体根据平台允许调用次数考虑
@ApiModelProperty("token")
val token: String = "",
@ApiModelProperty("用户id")
val userId: Long = 0L,
@ApiModelProperty("三方返回用户数据")
@Column(length = 1024)
val detail: String = "",
user_info
用户信息表
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@ApiModelProperty("ID")
val id: Long = 0L,
@ApiModelProperty("账号密码")
val account: String = "",
@ApiModelProperty("密码")
val pwd: String = "",
实现逻辑
服务端是前后分离,所以第三方登录最终目的就是给用户发token,具体是实现逻辑如下:
app内需要放置第三方登录按钮,实际上是给一个跳转三方认证的一个链接,用户同一登录后会返回一个code
拿着这个code,到服务端换取平台token
-
后端实现
通过code,获取第三方token
通过第三方用户token获取用户信息
伪代码
fun loginWx(param: LoginParam): OAuth2AccessToken {
//获取token
getWxToken(param.code).let {
//查询用户是否登录过
val thirdUser = thirdUserDomain.findByOpenId(it.openid)
if (null != thirdUser) {
//获取三方用户信息
getWxUser(it)
//登录过 更新用户信息 这里还没关联上平台用户信息
thirdUserDomain.update(ThirdUser())
//发 token
return signInHelper.signIn(Client.CORE, usr, client.authorities, client.scope)
} else {
//获取三方用户信息
getWxUser(it).run {
//没登录过 保存用户信息 这里还没关联上平台用户信息
thirdUserDomain.save(ThirdUser())
//发 token
return signInHelper.signIn(Client.CORE, this.nickname, client.authorities, client.scope)
}
}
}
}
保存用户信息颁发平台token,第一次登录发的token还没绑定手机号,所以第三方登录后还需要绑定手机
强制绑定手机号,颁发新的token
需要颁发新token是因为第一次三方认证登录颁发token是根据第三方账号作为用户名发布只有绑定手机的权限,新的token根据绑定的手机作为账号颁发具有全部用户权限
//查询第三方用户信息
val thirdUser = thirdUserDomain.findByAccount(SecurityUtils.usr)
//创建平台用户
userDomain.create(User()).let {
//关联用户ID
thirdUserDomain.update(thirdUser.copy(userId = it.id))
//过期原token
signInHelper.logout()
//颁发新的token
return signInHelper.signIn(client.clientId, it.mobile, client.authorities, client.scope)
}
参考:微信开放平台文档