菜菜君,我又来啦php
又有什么事吗?前端
我按照你上篇文章写的JWT的方式已经把网站认证写完了,并且效果还不错程序员
那恭喜你呀,下次面试又多了一项技能web
不过,如今又有一个问题,我作的系统有一个合做商想要利用咱们的用户信息登陆他们的系统面试
你还要作受权呀?编程
是呀,个人思路是让用户在第三方系统的输入帐号密码,而后第三方的服务端请求咱们服务器来验证正确性后端
这样作真的好吗?浏览器
这样作咱们的系统改动很小呀,我以为很好呀安全
这样作有不少弊端呀,且听我给你讲个小故事服务器
如下业务场景只针对于Web系统,并且Web页面有后台服务程序的场景。
那一年,我所在公司的用户量达到了公司成立以来的新高峰,通过多个程序员日日夜夜加班,每一个业务系统达到了几乎四个9的稳定性,同时业务在业界也有了必定的知名度。那一天忽然有一个合做商登门拜访,提出合做双赢的意向。业务的场景就是咱们的系统用户可以在他们系统登陆,并可以获取用户必定的信息以便进行一些业务操做。
他们但愿咱们可以把已存在的用户数据Copy一份导入他们的系统,而且新注册的用户进行单项同步更新。这不是虾扯蛋吗?.....
为了实现用户信息互通而达到业务要求,其实方案有不少。若是不是底线状况下,同步用户信息这种方案就是一个外行人,一个扯淡的方案。为何这么说?首先说信息同步这种方式,若是是单项同步,双方全部相关人员的工做量已经很是之大,必定条件下单项同步升级为双向信息同步,双方的编程人员将会苦不堪言。
另外撇开工做量,用户的信息本质上属于用户的私密信息,一个用户可以把本身的隐私放心的存储在你这里,就说明了对公司的信任度。一旦发生用户信息复制的操做,本质上是对用户的不负责任,道德上,法律上都有所欠缺。
做为一个技术人员,排除不合理方案,提供在业务可行状况下的技术方案是职责所在,那有没有不用复制用户信息这么low B的方案呢?假设咱们所在公司的系统为A,业务的域名为www.A.com,第三方系统为B,业务域名为www.B.com
记住咱们的最终业务目标:容许咱们公司的用户(A系统)在第三方系统(B系统)可以登陆,而且可以获取用户一些相关的信息。极限业务状况下,在A系统用户修改了相关信息,而且同步到B系统。
解决方案1
在第三方系统登陆的入口,容许我方用户输入帐号密码,而后第三方系统(客户端或者服务端均可以)携带用户输入的帐号密码请求我司登陆服务器,若是验证经过则返回用户相关信息,第三方系统接收到返回数据,按照本身相关的登陆流程进行登陆,而且能够存储用户相关的信息。请求的形式和大致的流程以下图所示
http://www.A.com/login?loginname=caicai&pwd=buzhidao
说实话,我并不推荐这种方案,虽然它比直接复制用户信息要好一些,可是依然问题很大,用户在无形中已经把帐号密码或者其余登陆凭证泄露给并不信任的第三方系统中,而这可能并不是用户想要的结果。
解决方案2
以上方案有一个致命的缺点,那就是登陆页面是用户并不信任的第三方页面,若是能避免这样的危险,让用户在信任的我方登陆,会大大加强用户的信任度。技术方面在我方实现登陆实在是容易,惟一须要考虑的是用户登陆成功以后如何把用户信息发送给第三方系统。若是采用请求调用的方式(好比:登陆成功,我方调用第三方一个接口),技术上能够实现,可是下次再来一个第三方申请这样的业务,我方的调用接口可能会须要修改,因此如今业界比较好的也比较通用的方式是经过地址的跳转来实现。具体流程以下:
1. 用户在第三方点击登陆,跳转到我方提供的登陆页面,页面URL中带有登陆成功跳转的页面地址,并在此页面输入帐号密码。
2. 我方根据用户帐号密码判断用户正确性,登录成功,获取用户信息。
3. 而后跳转到第三方提供的登陆成功跳转页面,并把用户信息携带过去。
4. 第三方跳转页面接收到用户信息,处理剩余业务,流程结束。
第一步中第三方跳转到我方的登陆页面URL以下所示:
http://www.A.com/login?type=userinfo&redirecturi=http://www.B.com/callback
解决方案3
方案2中登陆部分已经和方案1有了本质的区别,虽然仅仅是一个登陆方的改变,安全性以及对用户隐私的保护上却有着大大的提高。可是流程中却依然存在着主动传输用户信息,若是有人劫持的话,仍是有用户信息泄露的风险。如何避免这样的风险呢?
试想,可否利用其它凭据来代替用户信息呢?固然是能够,这也是现代Web系统实现受权的广泛方式。用户信息取而代之的是一个令牌,并且这个令牌有必定的时效性,只能维持一段时间内有效,这在必定程度上保护了系统数据。第三方系统获取到这个令牌以后,每次获取用户信息都会携带者这个令牌做为凭证,我方的系统同时也只承认这个令牌做为受权的凭证。
http://www.A.com/login?type=token&redirecturi=http://www.B.com/callback
这里我要顺便说一下,令牌的下发是经过前端(浏览器)的跳转传输给第三方系统,而后第三方系统的前端传输给后端,而后第三方的后端携带令牌获取用户信息,要注意哦,若是是第三方前端页面携带令牌去获取用户信息,毫无安全性而言。
方案4
方案3其实在不少时候已经足够了,可是有一点须要注意,每一个令牌有必定的有效时间,这是设计上的优点,同时也意味着令牌若是被其余人获取到,同样能够窃取用户信息,因为在方案3中令牌的下发实际上仍是经过前端(浏览器)来传输的,凡是在前端传输的状况下,就会有泄露的风险,那有没有办法避免在前端传输呢?
这里须要提醒一点,要想实现我方用户能够登陆第三方系统,而且在保护用户隐私的状况下,在我方登陆是必须的。并且我方系统必须颁发给第三方系统一个凭证才能达到第三方获取我方用户的要求。
既然传输凭证不可避免,因而人们便想到了能够在前端(浏览器)传输一个只有一次有效的凭证,而后第三方后端依据这个凭证去获取令牌,由于服务端的通讯要比前端(浏览器)的通讯要安全的多。因而方案4应运而生:
1. 用户跳转到我方登陆页面进行登陆。
2. 我方验证用户用户名密码无误,产生一个有效次数为1而且必定时间内有效的code,并携带着这个code跳转到第三方的回调页面
3. 第三方回调页面,收到code参数,传输给后端程序。
4. 第三方后端程序收到code参数,携带着code调用我方接口
5. 我方验证code有效性,若是有效则返回令牌信息
6. 第三方收到令牌信息,携带令牌信息调用我方接口获取用户信息
7. 我方验证token有效性,若是有效则返回用户信息
8. 以后的每次调用都携带者token进行访问,code就算被人获取到已经不起做用
http://www.A.com/login?type=code&redirecturi=http://www.B.com/callback
升级
方案4虽然看上去已经足够好,可是并不是完美。
1. 当第三方跳转到我方登陆页面的时候,我方并不知道这个第三方是谁,是否是可信任的,因此有必要让我方识别这个第三方是否能够信任。我方在受权第三方的时候能够给每个第三方颁发一个相似于appid和appkey的数据,appid用来标识每个我方受权的第三方,并且每个appid必须注册进行回调的url。这样当第三方跳转到我方登陆页面的时候,我方就能够识别出来这个第三方以及回调跳转的url是否有效。
2. 当第三方携带者code去换取token,以及以后携带token去获取用户信息的每次通讯,都应该按照我方规则利用appid和appkey进行签名处理,这样我方的服务器端也可以识别出来调用方是不是可信任的。
3. 在用户登陆受权的页面,用户可勾选本身受权给第三方的数据内容,这些权限将做用于code以及令牌中。
4. 因为每一个令牌都有失效时间,如何更新令牌则会是一个技术点,其实彻底能够在下发令牌的同时也下发一个用于更新令牌的令牌,这个令牌随着每次从新下发令牌而更新。
5. 我方用户的信息每次更新的时候,能够把相关的令牌失效,以达到让第三方从新获取用户信息而同步的效果
6. 我方登陆页面以及供第三方调用的全部接口都应该采用https协议,并要求全部的第三方回调页面必须也所有采用https,这能有效的仿制恶性劫持。
不知道菜菜把不清楚author2.0 受权的同窗教会了没有,若是还不清楚,请私信菜菜