《码农翻身》读书笔记之浪潮之巅的Web
这是我的后端读书笔记系列文章的第三篇,选取的是最近刚刚圈粉的知名博主刘欣创作的《码农翻身》。
本文内容主要根据知名博主刘欣一作《码农翻身》的内容总结而来,本书的内容风趣幽默,讲解计算机理论原理也是十分透彻,由于书中常常以小故事的形式出现,为了方便学习和回顾,我把它们进行了一些改编和整理,便于自己和跟多人阅读。
本篇文章主要讲述的书中的第三章“浪潮之巅的Web”。
本文首发于我的个人博客:https://h2pl.github.io/
同时发表在csdn技术博客上:https://blog.csdn.net/a724888
也欢迎来我的GitHub中交流学习:https://github.com/h2pl/
Web的起源
很早以前http还没有出现,html也尚未问世,人们最多就是发送一下邮件,用ftp传递文件这些基本的功能。后来为了更好地进行资源共享和展示,出现了html文本,可以在上面展示各种内容。与之一起出现的是浏览器,浏览器可以解析html文本,渲染出页面。
只有html文本还不够,必须要解决通信和互联网访问的需求,于是url用于定位自愿,而HTTP协议也应运而生,很好地支持了互联网资源的访问。http服务器也相应产生,比如Apache。
世界开始互联,www万维网把这些小网连成了大网,实现了世界的互联。
两个程序的爱情故事
本地的进程通信采用的是共享内存等机制,速度较快效率也高。操作系统保证通信的正确性和同步。
而两台机器上的进程通信则必须使用网络传输,基于socket的进程通信也十分常见,客户端需要完成三次握手,然后进行io请求和接收。
socket会绑定端口号和ip进行服务监听,但是有的机器安装防火墙以后禁止了很多端口的访问,于是我们可以使用应用层协议比如http来绕过防火墙,因为它一般是监听80端口,且使用url作为endpoint来访问,不会被防火墙拦截。
web服务的描述方式有多种,除了应用于浏览器的html以外。
我们还可以用它来传输其他数据,比如进行服务调用。
这时候可以采用webservice的wsdl和soap,但是这个协议的数据太臃肿冗余了,还是用HTTP加json数据格式的方式进行传输最为方便高效。
一个故事讲完HTTPS
网络上的通信是明文通信,每个报文都可能被截取。
HTTP加密发展历程:
对称加密
可以使用加密算法加密明文,然后发送密钥给接收方,让其使用密钥进行解密。
但是密钥会被窃取或者替换,根本不安全。
非对称加密
上述使用对称加密的方法不安全,于是我们可以用非对称加密来保证安全,非对称加密使用公钥加密,私钥解密,公钥是公开的,丢失也无妨。
两者结合
上述方法虽好,但是非对称加密比对称加密慢百倍,于是可以结合两种加密方式,非对称加密传输密钥,然后用这个密钥进行对称加密。
中间人劫持
虽然上述方式不错,但是非对称加密中的公钥可能被攻击者替换,客户端用被替换的公钥进行加密,攻击者就可以获取报文内容了。
那么我们需要保证公钥没被替换,可以攘服务端到公正中心注册,证书中心颁发一个证书,包含着可信服务方的公钥。
数字签名
虽然证书保证公钥的可靠,但是证书传输过程中仍然可能被篡改,必须保证证书没有被修改,可以让认证中心CA对证书中的消息摘要(一般是一些头部信息)进行加密,形成数字签名,客户端验证此签名解密后的摘要和自己生成的摘要是否一样,就知道是否有被篡改了。
CA证书
事实上中间人还是可以伪装成CA来派发假的证书或者公钥,所以我们必须要知道CA的真实性。其实在操作系统和浏览器已经内置了一些CA证书,这些顶层的CA证书可以验证其他CA证书的真伪,所以有时候浏览器才会提示该证书可能不安全,这就是因为内置CA证书不认识这些外来证书。
HTTPS流程
浏览器发起https请求
服务端发送数字证书给客户端
浏览器用预置CA验证证书,提示风险
浏览器得到公钥,生成随机数,用公钥加密该随机数,发给服务端
服务端用私钥解密获得浏览器的随机数,用该随机数作为密钥和客户端进行对称加密通信
机房夜话(单点登录sso和cas)
cookie,session与token
多个系统如何实现一个系统登录,其他系统也自动登录呢。
首先想到的是,session用于保存登录状态,用cookie保存sessionid。
我们只要在访问其他系统的时候也带上cookie,是不是就能登陆成功呢。
这个方案有两个问题:
1 cookie不能跨域
2 即使使用二级域名来避免跨域,不同系统中的session互不相干,没有共享。
共享session
既然上面提到需要共享session,那我们那每个系统都访问session服务即可,session服务可以用redis来实现。
然而,异构的系统,语言可能不同,共享session的方式可能导致不兼容的问题,这也不是最好的方案。
使用token
token与session不同,只是一个特殊字符串,不需要保存在服务端,当用户登陆成功时服务端加密用户信息生成token,返回cookie给客户端,客户端保存cookie。
token里一般包含用户信息和签名,这部分数据还要进行一次加密。这样的话服务端通过解密算法得到用户信息和签名,对用户信息再进行一次加密,对比两个签名是否相同就可以知道该token是否是真的了。
这个办法不错,但是有一个问题,每个系统中的用户id可能都不同,生成的token也不同,并且每个系统的加密算法还必须一致,很不灵活。
cas单点登录实现
1 首先我们需要一个注册中心
2 对于每个系统的登陆请求,都会转发到这个注册中心上。
3 在注册中心登陆成功后,注册中心建立一个session,并且给浏览器一个cookie(这个cookie可以让浏览器下次访问注册中心时无须再登陆)。除此之外,还有很重要的一步,就是执行请求转发,redirect到之前对系统的访问请求,同时携带了一个注册中心生成的ticket。
4 这个ticket就是客户端访问其他系统的钥匙了。为什么呢。因为请求到达对方系统时,对方也会转发该请求到注册中心上,并且询问该ticket是否是注册中心所发,注册中心说是的,此时对方系统就会为客户端建立一个session,表示该用户已经登陆了,当然对方系统也会返回一个cookie给客户端,下次访问该系统时不需要再通过注册中心了。
5 当需要访问另一个系统B时,我们已不必再次在注册中心登录了,因为已经有了注册中心的cookie,直接访问系统B,B转发给注册中心,验证通过即可。
单点登出:
既然有单点登录,那么单点登出也是必不可少的,一个用户从任一系统登出,就要通知注册中心,删除session和客户端的cookie。还要通知各个系统把该用户相关的session进行删除。这样才能真正地实现退出。
从密码到token,一个有关授权的故事
第三方登录的实现
现在越来越多的app和web应用支持使用第三方渠道登录,比如微信,qq等等,但实际上第三方登录并不会让app应用真的得到你的用户密码。那么它是怎么做到的呢。
第三方登录首先是请求app登录,然后跳转到登录页面比如qq,然后输入用户名密码发送登陆请求,qq登录服务接收请求并且发送重定向请求,url中携带token字符串。
该token字符串是用户登录成功后qq服务提供的身份标识,app通过此token就可以到腾讯服务器获取该用户的qq基本信息了。
但是由于token加在url中明文传输不太安全,可能会被截获然后冒名登录。
OAuth认证方式
上述方式存在安全隐患,于是我们设想出了不在url中携带token,而是先让qq服务接受登录请求后先返回一个code认证码放在url中,app应用再通过这个code码,重新发送请求到认证服务器,本次发送不经过浏览器,所以获得到的token比较安全,并且code认证码可以设置有效时间,过期后不能使用,同时,code兑换token的请求只能执行成功一次,成功后code码自动删除。保证了一次登录的成功,避免重复登录和伪造登录。
后端风云
为了加快访问速度和缓解数据库压力,采用缓存比如Redis,为了克服单机瓶颈,开始从单机部署进化到多机部署。
多机部署需要请求分发,nginx可以做到这一点。
分布式方案:
1 nginx
nginx负责处理静态请求以及负载均衡,基本是无状态的,所以高可用只需要用keepalived即可实现主从部署。
2 Tomcat 服务器
Tomcat服务器采用集群就可以实现高可用,但是数据一致性需要额外保证,使用Redis存储session这类数据就可以保证集群的高可用。
3 Redis
服务器访问Redis集群需要进行主从部署,使用一致性hash进行分片。也可以使用hash slot也就是hash槽进行分片,Redis cluster就是根据这个方法进行集群部署的。每个节点都可以提供服务,只不过数据是分散存储的。
4 Mysql
MySQL可以使用主从复制进行部署,并且读写分离。
soa到微服务
soa太笨重了,类似webservice这样的服务使用wsdl和soap这样复杂的数据格式。
微服务则一般基于tcp自定义协议进行rpc调用,也可以使用http + json的方式传输数据,使用restful风格的api。
微信公众号【Java技术江湖】一位阿里 Java 工程师的技术小站。(关注公众号后回复”Java“即可领取 Java基础、进阶、项目和架构师等免费学习资料,更有数据库、分布式、微服务等热门技术学习视频,内容丰富,兼顾原理和实践,另外也将赠送作者原创的Java学习指南、Java程序员面试指南等干货资源)