程序员过关斩将--要想获取我的用户信息,就得按照规矩来

640?wx_fmt=gif

菜菜君,我又来啦

640
640?wx_fmt=jpeg

又有什么事吗?

640
640?wx_fmt=jpeg

我按照你上篇文章写的JWT的方式已经把网站认证写完了,而且效果还不错

640
640?wx_fmt=jpeg

那恭喜你呀,下次面试又多了一项技能

640
640?wx_fmt=jpeg

不过,现在又有一个问题,我做的系统有一个合作商想要利用我们的用户信息登录他们的系统

640
640?wx_fmt=jpeg

你还要做授权呀?

640
640?wx_fmt=jpeg

是呀,我的思路是让用户在第三方系统的输入账号密码,然后第三方的服务端请求我们服务器来验证正确性

640
640?wx_fmt=jpeg

这样做真的好吗?

640
640?wx_fmt=jpeg

这样做我们的系统改动很小呀,我觉得很好呀

640
640?wx_fmt=jpeg

这样做有很多弊端呀,且听我给你讲个小故事

640
640?wx_fmt=jpeg
640?wx_fmt=gif
640

以下业务场景只针对于Web系统,而且Web页面有后台服务程序的场景。

640

640?wx_fmt=gif
开端
640?wx_fmt=gif
640

那一年,我所在公司的用户量达到了公司成立以来的新高峰,经过多个程序员日日夜夜加班,每个业务系统达到了几乎四个9的稳定性,同时业务在业界也有了一定的知名度。那一天突然有一个合作商登门拜访,提出合作共赢的意向。业务的场景就是我们的系统用户能够在他们系统登录,并能够获取用户一定的信息以便进行一些业务操作。

他们希望我们能够把已存在的用户数据Copy一份导入他们的系统,并且新注册的用户进行单项同步更新。这不是虾扯蛋吗?.....

640?wx_fmt=jpeg

640?wx_fmt=gif
为什么不可行
640?wx_fmt=gif
640

为了实现用户信息互通而达到业务要求,其实方案有很多。如果不是底线情况下,同步用户信息这种方案就是一个外行人,一个扯淡的方案。为什么这么说?首先说信息同步这种方式,如果是单项同步,双方所有相关人员的工作量已经非常之大,一定条件下单项同步升级为双向信息同步,双方的编程人员将会苦不堪言。

另外撇开工作量,用户的信息本质上属于用户的私密信息,一个用户能够把自己的隐私放心的存储在你这里,就说明了对公司的信任度。一旦发生用户信息复制的操作,本质上是对用户的不负责任,道德上,法律上都有所欠缺。

640?wx_fmt=gif
解决方案
640?wx_fmt=gif
640

作为一个技术人员,排除不合理方案,提供在业务可行情况下的技术方案是职责所在,那有没有不用复制用户信息这么low B的方案呢?假设我们所在公司的系统为A,业务的域名为www.A.com,第三方系统为B,业务域名为www.B.com

640

记住我们的最终业务目标:允许我们公司的用户(A系统)在第三方系统(B系统)能够登录,并且能够获取用户一些相关的信息。极限业务情况下,在A系统用户修改了相关信息,并且同步到B系统。

640

解决方案1

640

在第三方系统登录的入口,允许我方用户输入账号密码,然后第三方系统(客户端或者服务端都可以)携带用户输入的账号密码请求我司登录服务器,如果验证通过则返回用户相关信息,第三方系统接收到返回数据,按照自己相关的登录流程进行登录,并且可以存储用户相关的信息。请求的形式和大体的流程如下图所示

http://www.A.com/login?loginname=caicai&pwd=buzhidao

640?wx_fmt=jpeg

640

说实话,我并不推荐这种方案,虽然它比直接复制用户信息要好一些,但是依然问题很大,用户在无形中已经把账号密码或者其他登录凭证泄露给并不信任的第三方系统中,而这可能并非用户想要的结果。

解决方案2

640

以上方案有一个致命的缺点,那就是登录页面是用户并不信任的第三方页面,如果能避免这样的危险,让用户在信任的我方登录,会大大增强用户的信任度。技术方面在我方实现登录实在是容易,唯一需要考虑的是用户登录成功之后如何把用户信息发送给第三方系统。如果采用请求调用的方式(比如:登录成功,我方调用第三方一个接口),技术上可以实现,但是下次再来一个第三方申请这样的业务,我方的调用接口可能会需要修改,所以现在业界比较好的也比较通用的方式是通过地址的跳转来实现。具体流程如下:

1. 用户在第三方点击登录,跳转到我方提供的登录页面,页面URL中带有登录成功跳转的页面地址,并在此页面输入账号密码。

2. 我方根据用户账号密码判断用户正确性,登陆成功,获取用户信息。

3. 然后跳转到第三方提供的登录成功跳转页面,并把用户信息携带过去。

4. 第三方跳转页面接收到用户信息,处理剩余业务,流程结束。

第一步中第三方跳转到我方的登录页面URL如下所示:

http://www.A.com/login?type=userinfo&redirecturi=http://www.B.com/callback

640?wx_fmt=jpeg

解决方案3

640

方案2中登录部分已经和方案1有了本质的区别,虽然仅仅是一个登录方的改变,安全性以及对用户隐私的保护上却有着大大的提升。但是流程中却依然存在着主动传输用户信息,如果有人劫持的话,还是有用户信息泄露的风险。如何避免这样的风险呢?

试想,能否利用其它凭据来代替用户信息呢?当然是可以,这也是现代Web系统实现授权的普遍方式。用户信息取而代之的是一个令牌,而且这个令牌有一定的时效性,只能维持一段时间内有效,这在一定程度上保护了系统数据。第三方系统获取到这个令牌之后,每次获取用户信息都会携带者这个令牌作为凭证,我方的系统同时也只认可这个令牌作为授权的凭证。

http://www.A.com/login?type=token&redirecturi=http://www.B.com/callback

640?wx_fmt=jpeg

640

这里我要顺便说一下,令牌的下发是通过前端(浏览器)的跳转传输给第三方系统,然后第三方系统的前端传输给后端,然后第三方的后端携带令牌获取用户信息,要注意哦,如果是第三方前端页面携带令牌去获取用户信息,毫无安全性而言。

640

方案4

640

方案3其实在很多时候已经足够了,但是有一点需要注意,每个令牌有一定的有效时间,这是设计上的优势,同时也意味着令牌如果被其他人获取到,一样可以窃取用户信息,由于在方案3中令牌的下发实际上还是通过前端(浏览器)来传输的,凡是在前端传输的情况下,就会有泄露的风险,那有没有办法避免在前端传输呢?

640

这里需要提醒一点,要想实现我方用户可以登录第三方系统,并且在保护用户隐私的情况下,在我方登录是必须的。而且我方系统必须颁发给第三方系统一个凭证才能达到第三方获取我方用户的要求。

640
640

既然传输凭证不可避免,于是人们便想到了可以在前端(浏览器)传输一个只有一次有效的凭证,然后第三方后端依据这个凭证去获取令牌,因为服务端的通信要比前端(浏览器)的通信要安全的多。于是方案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

640?wx_fmt=jpeg

升级

640

方案4虽然看上去已经足够好,但是并非完美。

1. 当第三方跳转到我方登录页面的时候,我方并不知道这个第三方是谁,是不是可信任的,所以有必要让我方识别这个第三方是否可以信任。我方在授权第三方的时候可以给每一个第三方颁发一个类似于appid和appkey的数据,appid用来标识每一个我方授权的第三方,而且每一个appid必须注册进行回调的url。这样当第三方跳转到我方登录页面的时候,我方就可以识别出来这个第三方以及回调跳转的url是否有效。

2. 当第三方携带者code去换取token,以及之后携带token去获取用户信息的每次通信,都应该按照我方规则利用appid和appkey进行签名处理,这样我方的服务器端也能够识别出来调用方是否是可信任的。

3. 在用户登录授权的页面,用户可勾选自己授权给第三方的数据内容,这些权限将作用于code以及令牌中。

4. 由于每个令牌都有失效时间,如何更新令牌则会是一个技术点,其实完全可以在下发令牌的同时也下发一个用于更新令牌的令牌,这个令牌随着每次重新下发令牌而更新。

5. 我方用户的信息每次更新的时候,可以把相关的令牌失效,以达到让第三方重新获取用户信息而同步的效果

6. 我方登录页面以及供第三方调用的所有接口都应该采用https协议,并要求所有的第三方回调页面必须也全部采用https,这能有效的仿制恶性劫持。

640?wx_fmt=png

不知道菜菜把不清楚author2.0 授权的同学教会了没有,如果还不清楚,请私信菜菜

640?wx_fmt=gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/313676.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

E. Surprise me!(莫比乌斯反演 + 虚树 DP)

E. Surprise me! ∑i1n∑j1nϕ(aiaj)d(i,j)设paii∑i1n∑j1nϕ(ij)d(pi,pj)∑i1n∑j1nϕ(i)ϕ(j)ϕ(gcd⁡(i,j))gcd⁡(i,j)d(pi,pj)∑d1ndϕ(d)∑i1nd∑j1ndϕ(id)ϕ(jd)d(pid,pjd)[gcd⁡(i,j)1]∑d1ndϕ(d)∑k1ndμ(k)∑i1nkd∑j1nkdϕ(ikd)ϕ(jkd)d(pikd,pjkd)Tkd∑T1n(∑i1n…

Hibernate 的缓存机制

** 1、Hibernate 应用程序中按照缓存的范围,可以将缓存分为三类 ** (1.1)事务范围缓存(单Session,即一级缓存) 事务范围的缓存只能被当前事务访问,每个事务都有各自的缓存。缓存的生命周期依…

.NET分布式大规模计算利器-Orleans(一)

写在前面Orleans是基于Actor模型思想的.NET领域的框架,它提供了一种直接而简单的方法来构建分布式大规模计算应用程序,而无需学习和应用复杂的并发或其他扩展模式。我在2015年下半年开始应用Orleans,当时公司的交易系统采用的架构就是基于Orl…

吉哥系列故事——恨7不成妻(数位 DP)

吉哥系列故事——恨7不成妻 ∑i1n(presuc)2∑i1npre2suc22presucnpre2∑suc22pre∑suc\sum_{i 1} ^{n}(pre suc) ^ 2\\ \sum_{i 1} ^{n} pre ^ 2 suc ^ 2 2 \times pre \times suc\\ n \times pre ^ 2 \sum suc ^ 2 2 \times pre \sum suc\\ i1∑n​(presuc)2i1∑n​pre…

Hibernate与MyBatis对比

1、Hibernate与MyBatis简单介绍 Hibernate 是当前最流行的O/R mapping框架,它来自于 sf.net,现在已经成为Jboss的一部分。 Mybatis 是另外一种优秀的O/R mapping框架。目前属于apache的一个子项目。 MyBatis 参考资料官网:http://www.mybat…

Hive-DML详解(超详细)

文章目录 前言HiveQL的数据操作语言(DML)1. 插入数据1.1 直接插入固定值1.2 插入查询结果 2. 更新数据3. 删除数据3.1 删除整个分区 4. 查询数据4.1 基本查询4.2 条件筛选4.3 聚合函数 总结 前言 本文将介绍HiveQL的数据操作语言(DML&#x…

从单机应用到微服务,用户认证走几步?

用户认证指在用户访问服务的时候确认用户的身份,受限于HTTP无状态的特性,应用开发者需要自行实现用户认证相关功能。通常是用户登录时服务端生成通行证返回给客户端,客户端在接下来的请求中携带通行证,然后服务端通过校验该通行证…

P5175 数列(矩阵快速幂)

P5175 数列 anb(xan−1yan−2)2x2an−12y2an−222xyan−1an−2x2an−12y2an−222xyan−2(xan−2yan−3)x2an−12y2an−222xy(xan−22yan−2an−3)a_n ^ b \left(x \times a_{n - 1} y \times a_{n - 2}\right) ^ 2\\ x ^ 2 \times a_{n - 1} ^ 2 y ^ 2 \times a_{n - 2} ^ 2…

Spring bean 的初始化

先mark: https://www.cnblogs.com/yxh1008/p/6012230.html Bean的多种初始化、destory方法执行顺序 https://segmentfault.com/a/1190000014105687 https://blog.csdn.net/caihaijiang/article/details/8629725 Spring bean的初始化过程 https://www.jianshu.com…

编写优雅代码,从挖掉恶心的if/else 开始

背景长话短说, 作为开发人员经常需要根据条件灵活查询数据库,不管你是用rawsql 还是EFCore, 以下类似伪代码大家都可能遇到:特别是在大数据产品或者物联网产品中,字段甚多;if/else 写到死,一边写…

Spring bean 初始化顺序

InitializingBean, init-method 和 PostConstruct 1、概述 从接口的名字上不难发现,InitializingBean 的作用就是在 bean 初始化后执行定制化的操作。 Spring 容器中的 Bean 是有生命周期的,Spring 允许在 Bean 在初始化完成后以及 Bean 销毁前执行特…

不要666升级版(数位DP,三次方和)

不要666升级版 ∑(presuc)2npre22pre∑suc∑suc2\sum(pre suc) ^ 2\\ n \times pre ^ 2 2 \times pre \sum suc \sum suc ^ 2\\ ∑(presuc)2npre22pre∑suc∑suc2 ∑(presuc)3∑(pre33pre2suc3presuc2suc3)npre33pre2∑suc3pre∑suc2∑suc3\sum (pre suc) ^ 3\\ \sum \left…

.NET Conf 2019 大会上发布.NET Core 3.0

北京时间今天凌晨如期在.NET Conf 上发布.NET Core 3.0,Keynotes 由Scott Hunter 主演,主要围绕.NET Core 3.0的新特性和社区展开。多功能性是.Net Core 成为我们的生活一部分的最好解释。如果您是Web开发人员还是想开发桌面或移动应用程序,如果您是游戏…

Spring AOP实现原理

先说结论: Spring AOP采用的是JDK动态代理 CGLIB动态代理模式。当当前类为接口的实现时,采用JDK动态代理,否则用CGLIB、 1、AOP 的存在价值 在传统 OOP 编程里以对象为核心,整个软件系统由系列相互依赖的对象所组成&#xff0c…

J. Product of GCDs(莫比乌斯反演)(2021牛客暑期多校训练营2)

Product of GCDs ∏d1nd∑[gcd⁡(s1d,s2d,…,skd)1]∏d1nd∑i1ndμ(i)Cf[id]k\prod_{d 1} ^{n} d ^{\sum[\gcd(\frac{s_1}{d}, \frac{s_2}{d}, \dots, \frac{s_k}{d}) 1]}\\ \prod_{d 1} ^{n} d ^{\sum\limits_{i 1} ^{\frac{n}{d}} \mu(i) C_{f[id]} ^{k}}\\ d1∏n​d∑[g…

微软推出Python免费在线教程视频

开源中国曾报道过最近微软针对 Python 初学者,推出了一套免费的教程视频。这套视频名为 Python for Beginners,该在线教学视频由微软高级项目经理 Christopher Harrison、以及微软 AI Gaming 的商业开发经理 Susan Ibach 共同讲解,在课程中加…

徒手实现Spring的IOC

Mark https://www.jianshu.com/p/9fe5a3c25ab6 https://juejin.im/post/5abe75f351882577b45f2336 https://blog.csdn.net/u012373815/article/details/74937913 https://xilidou.com/2018/01/08/spring-ioc/ IOC原理介绍: http://www.importnew.com/14751.htm…

HDU6956-Pass!(2021杭电多校一)(BSGS)

Pass! f(1)0,f(2)n−1,f(t)(n−2)f(t−1)(t−1)f(t−2)f(1) 0, f(2) n - 1, f(t) (n - 2) \times f(t - 1) (t - 1) \times f(t - 2)f(1)0,f(2)n−1,f(t)(n−2)f(t−1)(t−1)f(t−2),考虑对通项两边同时加一个xf(t−1)x \times f(t - 1)xf(t−1)。 可以得到f(t…

推荐neter常用优秀开源项目系列之一

.net社区有很多优秀的开源项目,我们今天先推荐6个开源项目;1.MassTransitMassTransit 是一个自由、开源、轻量级的消息总线, 用于使用. NET 框架创建分布式应用程序。MassTransit在现有消息传输上提供了一组广泛的功能, 从而使开发人员能够友好地使用基于…

spring四种依赖注入方式

平常的java开发中,程序员在某个类中需要依赖其它类的方法,通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理。 spring提出了依赖注入的思想,即依赖不由程序员控制,而是通过spring…