1. QQ登录原理
当你点击登录页面的qq时候,就会跳转到腾讯,然后通过腾讯的验证后,会跳转到网站会调域(也就是一个网址),这就完成了网站的QQ登录。
2. QQ登录前期准备
2.1. 创建应用
登录QQ互联官网,必须审核通过才可以使用
2.2. 修改回调域并且配置本机host
我们在开发的时候,大部分都是在本地进行测试,那怎么才能访问指定的网站时候,映射到本地呢?
进入目录C:\Windows\System32\drivers\etc
使用命令行进行测试
3. QQ登录流程
-
用户点击网站中QQ登录,跳转到腾讯登录页面,然后用户进行扫码进行登录并且获取授权码
-
后台使用授权码获取token
-
使用token换取openId
-
使用openid和token换取用户信息
4. 接收回调参数,查询QQ信息,绑定用户的思路
思路1:
- 如果是老用户则直接通过openid查询用户信息,登录成功(通过):
- 如果openId不存在,则证明是新用户,让其绑定已有用户或者新注册一个
- 新用户,可以创建新账号,也可以绑定已有账号 (通过)
思路2:
- 必须先注册号账号,在个人中心绑定QQ
5. 用户登录
当用户使用QQ扫码登录后,为了保护数据库,先到缓存中通过openid查找用户信息,如果找到就说明是老用户,直接将用户对象返回即可。
如果在缓存中没有查找用户,就访问数据库,如果查到,就将对象存放到缓存中,然后返回对象,缓存数据结构为【qq:openid:userInfo】
jedis.setex("qq:" + openId + ":userInfo",60*60*24,JSON.toJSONString(user));
6. 当登录成功后,返回路径问题
网站使用了第三方社交登录,有qq,微信,微博等登录方式,无论哪种登录方式,当用户登录成功后,要回到原始路径,比如你点击了订单系统,然后被踢回到登录首页,登录成功时候,向认证中心要token,携带token到原始路径。
本网站登录的原始路径存放很简单,直接将返回的原始地址存放在页面上即可。
主要是第三方登录,登录成功后的返回路径问题
6.1. 京东对使用第三方进行登录的做法
-
在redirect_uri回调路径后面加上uuid推测,京东使用uuid在缓存中查询相应的return_url
-
为什么京东不直接采用拼接return_url参数呢,也许是怕黑客截取修改原始返回路径,修改成黑客自己的钓鱼网站。
-
使用uuid将return_url保存到缓存中,当用户登录成功时候,删除键值对
-
缓存中的数据结构为[user:returnUrl:uuid值]
// 使用键值对存储returnUrl,数据结构为k = user:returnUrl:uuid v = returnUrl值
returnUrlUUID = UUID.randomUUID().toString();
6.2. Bug解决
如果采用上面的uuid方法(之前推论是错误的),当遇到不法分子,使用压力测试工具进行上万次访问你的登录首页时候,由于你的首页后台会生成一个uuid , 并以uuid:返回路径的格式存储到缓存中,导致缓存中会有大量的uuid:返回路径数据,而且我们是没法删除的。
6.3. 使用cookie存放原来路径
这回的做法如下:
当用户访问登录首页的时候,我们只将返回路径存放到首页页面。
用户点击登录后,不直接跳转到腾讯登录页面,先跳转到网站后端并且携带ReturnUrl,然后在后台中进行请求转发,并且这时把ReturnUrl存放到Cookie中,当用户绑定成功后或者登录成功后,就删除相应的cookie。
如果Cookie中没有ReturnUrl就直接跳转到网站首页(有可能是用户删除了Cookie,或者已经过期)
注意:
往浏览器写入cookie,必须是域名,可以设置本地解析,如果使用127.0.0.1,写入失败读取也会失败。比如http://127.0.0.1:8080,如果是这样的域名,是无法操作浏览器的cookie的,你需要进行本地映射成http://user.gmall.com:8080/,这样就可以了
7. 使用已有账号绑定QQ
如果是新用户登录,会跳转到用户绑定页面,当绑定已有账户的时候,需要将accessToken和openId以及用户基本信息保存到数据库中,千万不能将accessToken和openId重要信息带入到页面中,要将accessToken和openId保存到缓存中,其他的也可以,只要不将其带入页面即可。
将用户基本信息保存到缓存中,数据结构为 k-v = qq:uuid: qqloginInfo用户对象转为json字符串,默认6个小时就过期,当QQ绑定已有账号成功后就将其删除。
jedis.setex("qq:" + uuid + ":qqloginInfo" ,60*60*12 , JSON.toJSONString(user));
8. 生成并验证state属性,防止CSRF攻击
使用uuid生成随机的state,然后跳转到腾讯并且带着这个值,当腾讯进行回调的时候,判断该值是否正确(从缓存中获取state)。