我的大学

本文转载自徐宥的我的大学 我的大学 虽然标题是”我的大学”,但大学中的一切,其实都和大学前的经历和学习习惯有关。因此,我还是从我小学时的一件对我以后人生,包括大学影响巨大的事情说起吧。 数理化和好老爸 我的小学是在农村里和爷爷奶奶度过的。我的父母住在小镇上,两人平时都要工作,没空照看我和我弟弟。所以,我只有周末和放假才到镇上,和父母弟弟在一起。四年级升五年级那个暑假,我到了镇上,和父母在一起。因为一起抓鱼钓虾的玩伴都在老家,百无聊赖的我开始乱翻父亲的书橱,找书看。某天,我翻出了一本叫做《平面几何一题多解》的书,那是本封面很好看的书。我把整本书翻下来,每个汉字我都认识,但每个符号我都不懂。好奇的我于是问父亲,这个书讲的是什么呀,怎么从来没见过这些奇怪的符号呢? 他就告诉我说,书里讲解的这个东西,叫平面几何。他接着问我说,“平面几何是个很有趣的东西,你想不想学呢?” 我说,当然想啊。那时的我,其实只是一个好奇的小学生,迫切想知道这个书中的图画和符号的意思。我肯定不会想到,这个很随意的决定,改变了我其后的整个人生。 听了我肯定的回答,我父亲立即从书橱里层(我家书太多了,书橱太小,书橱里书分里层外层,外层的书挡住了内层的书脊,我从来都不知道里面还有宝贝)变戏法一般的翻出了本《数理化自学丛书–平面几何》。对于我父亲这一代人来说,《数理化自学丛书》是代表着知识,荣耀和梦想的。我感觉他翻出这本书的时候的动作是虔诚的,但当时的我并不知道我父亲在这套书上寄托的希冀和梦想。我只记得他告诉我,当年这套书,用去了他大半个月工资。就这样,从五年级开始,我就在父亲的指点下,开始蹒跚前进学习《平面几何》。从一开始不知道什么叫 “证明”, 需要他一字一句帮我厘清逻辑关系,到后来全是自学不需要他教,我很快就喜欢上了自学这种学习方式,每天自己看书并且做八道题。暑假过完后,我就回到了爷爷奶奶的老家。父亲让我继续自学,并且布置我一周做八道题。我在爷爷奶奶家,每天放学回来不做家庭作业也不看动画片,就赶紧做一道几何题。做几何题的妙趣,是不融入其中的人不能理解的。比起小学里的抄生字,抄课文这种作业,做几何题是脑力和体力的双重享受。当时,我周围没人可以讨论切磋,全靠自己。遇到不会的题目,我只能自己冥思苦想,或者熬到周末和父亲讨论,因此,常常被一道难题从周一折腾到周日。好在这套书是粉碎四人帮后出的第一版,当年学生的数学水平比不上现在的学生,而这本书又是以自学为主要切入点,所以题目相对也简单,我冥思苦想几天后大体上也能想到解题思路。因此,我能够常常体验百思得解的愉悦感。我觉得,这种时常拜访的愉悦感,让我很早就开始相信独立思考的力量。 每个周末,父亲都用吱吱作响的自行车带我到镇上洗澡理发,然后批改上周我做的几何题。在自行车上的时候,他常常信马由缰,随口说些说些初中物理和初中代数知识,比如看到船就说浮力,看到马就说做功,看到三角形就说余弦定理等等。我也就半懂不懂的听,有时候插几句话,有时候能睡着了,没有丝毫的压力和拘束。很早就被中学数学物理知识装备的一个小学生是可怕的,我那时候觉得知识就是力量,因此我一定要用自己的数学物理知识做一台柴油机,我很自信的认为我懂得做柴油机和机动车的一切知识,说不定还能做出第二类永动机。我爸爸屡次告诉我不可行,而我反过来一直屡次告诉他,你是个没有理想的人。我爸爸不愿意打消我的理想,只是扔给我更多的书,希望能够打击我制造柴油机和永动机的热情,而我的知识理想,在读了更加多的书以后,变得更加的坚固了,我相信,学习知识是我人生第一重要事,有了知识,虽然不一定能做柴油机,但一定能做更多强大的事情。同时,我通过学习几何和其他的一些父亲扔给我的书,开始对自己的学习能力有了自信,我相信,找书自学是学知识的好方法,同时,把题从头到尾做一遍是很好的自学方法。 所以,我带着三个理念进入了大学,第一是什么东西都可以自学,第二是慢即是快,笨笨的做一遍题是学习的捷径;第三是知识理想主义,知识就是力量。而读书学知识能够消除蒙昧,掌握改变世界的力量,所以是一件快乐的事情。 大一,极端自负和极端自卑 我的高考成绩还很不错,高中还拿了一个数学联赛一等奖,所以,我是带着对自己数学知识(为了准备数学竞赛,我看了很多闲书,有很多就是大学数学系的教材)和学习方法的自信满满,和对南大数学系这个相对不好的选择的遗憾和自卑(当时的高考分数可以填报更加好的学校或更加喜欢的专业)来到大学的。当时我的心理状态可以用八个字概括: 极端自负,极端自卑。 这种心态,一直笼罩了我上大学的头两年,而且总是以一季度为周期,在两极之间交替变化。我在学期开始往往很自负,到期中考试左右很自卑,然后再自负,再自卑,不断反复。 在我看来,极端自负这个心态,其实不是因为自信,而是因为极端自卑生出的应激反应–为了掩盖自卑,只好用自负来掩饰。为什么我极端自卑呢,大体来自两个方面,一个是我的成绩排名在高中都是很前的,但是到了大学就 20 名开外了。尽管我觉得自己的数学水平很不错,考试却总是不怎么样,觉得考试考不出真水平。另一个是觉得自己没有在一个自己满意的系。我喜欢动手的工科,当时我觉得比起计算机系和电子系这样的“牛” 系,数学系并不“牛”。可即使在不牛的系,我都不能做到前10,更别说看上去更加牛的计算机系了。为了掩饰这种这种自卑,就自然生出了极端自负。那时候,我上课根本不听讲,理由是“书上的东西太简单了”。为了证明自己智商还可以,我总是坐在最后一排,显示自己并不热心于老师讲课。我这样持续了两年, 以至于到最后, 我连班上每次都坐在前面的几个同学的名字都不知道。这样的心态明明是错的,我却缺少一个很好的动因来改变它。 不过最原始的三个理念还是在的,我告诫自己即使不听讲,也不能浪费时间。所以,我把听课做作业上节省下来的时间,用在了看喜欢的计算机书和学习编程上了。于是,整个大一大二,我凭借着简单的自学的理念,开始了两件事情,敲 《Thinking in Java》(TIJ) 和 《The TeXbook》 上的没一个样例。 敲 TIJ 的机缘其实很简单,我是在软件学院听课的时候看到他们教 Java, 但是他们用的 《Java 大学教程》太贵了,我舍不得买。 我在网上搜了一圈,发现 《Thinking in Java》是一个免费的英文电子书。 于是,我就在数学系的机房,每天下午和晚上,开着一台计算机,屏幕上放着这个电子书,再用我的很土的笔记本,运行着未注册的 JCreator, 一个字母一个字母的敲 TIJ 上面的程序。我很偏激的认为拷贝粘帖的程序记不住,所以每个字母都自己手敲。 就这样,花了一个学期,居然就把所有的程序敲完了,基本上 Java 的方方面面,我也了然于胸了。 敲完 Thinking in Java 之前没几天,我们就期末考试了。那一次考试的试题是 LaTeX 排版的,而不是手写的。 我考试的时候就问监考老师这玩意怎么排版出来的,因为我知道 Word 这个软件做不到这个效果。监考老师除了对我不认真考试表示不满外, 还算仁慈,告诉了我 LaTeX 这个名词。 寒假里,我就买了一本 LaTeX 教程。然后,突然认识到,原来 TeX 居然是我最热爱的 Knuth 的杰作,于是我就疯狂的开始学 TeX。 我的方法还是一样, 敲例子。 记得 TeXbook 上有一个程序, Knuth 让大家自己照着敲入计算机, 然后还很幽默的说,实验证明,只有很少的人会按照他说的敲入这个程序,而这部分人,却是学 TeX 最好的人。看到这里我会心一笑,觉得自己的方法原来也不算笨。从此,一字不漏敲入一本书的程序成了我推荐别人学习语言的最好办法。 我后来大四又敲了 A Byte of Python,前段时间又敲玩了 The Awk Book,都是不到一个月瞬间从初学者成为细节很熟悉顺手拈来使用者。顺着这个方法,大二我把 《组合数学引论》 和上海交通大学出版的一本 《离散数学》 上的题目都做一题不漏做完了。当时选者两本书也没有特别的目的,就觉得这东西应该是计算机的数学基础。这些积累,在大四全部都显现了出来。...

September 28, 2021 · 2 min · Egbert Ke

What the heck is the event loop?

前几天看了一个youtube视频,关于JavaScript运行原理的,讲的比较透彻,在此记录一下。 这位老兄为此还写了一个可以实时看到js运行时动画的程序,实属牛逼。 这位老兄的博客地址:http://latentflip.com

September 17, 2021 · 1 min · Egbert Ke

NodeJS架构 - 单线程事件循环模型

这篇译章探究了NodeJS的架构和单线程事件循环模型。我们将在本文中讨论“NodeJS如何在底层工作,它遵循什么类型的处理模型,NodeJS如何使用单线程模型处理并发请求”等内容。 NodeJS 单线程事件循环模型 正如我们刚才说的,NodeJS使用的是“单线程事件循环模型”的架构去处理多个并发的客户端请求的。 有许多Web应用程序技术,如JSP,Spring MVC,ASP.NET等。但所有这些技术都遵循“多线程请求 - 响应”架构来处理多个并发客户端。 我们已经熟悉“多线程请求 - 响应”架构,因为它被大多数Web应用程序框架使用。 但是为什么NodeJS选择了不同的架构来开发Web应用程序。多线程和单线程事件循环体系结构之间的主要区别是什么? NodeJS NodeJS使用“单线程事件循环模型”架构来处理多个并发客户端。然而它是如何真正处理并发客户端请求且不使用多个线程。什么是事件循环模型?我们将逐一讨论这些概念。 在讨论“单线程事件循环”架构之前,首先我们将介绍著名的“多线程请求 - 响应”架构。 传统的Web应用处理模型 任何非NodeJS开发的Web应用程序通常都遵循“多线程请求 - 响应”模型。我们可以将此模型称为请求/响应模型。 客户端向服务器发送请求,然后服务器根据客户端请求进行一些处理,准备响应并将其发送回客户端。 该模型使用HTTP协议。由于HTTP是无状态协议,因此该请求/响应模型也是无状态模型。所以我们可以将其称为请求/响应无状态模型。 但是,此模型使用多线程来处理并发客户端请求。 在讨论这个模型内部之前,首先要看下面的内容。 请求/响应模型处理的步骤: 客户端发送一个请求到Web服务器 Web服务器内部维护一个有限的线程池,以便在客户端请求提供服务 Web服务器处于无限循环中并等待客户端传入请求 Web服务器处理请求步骤: 接收到一个客户端请求 从线程池中选择一个线程 将此线程分配给客户端请求 此线程读取客户端请求,处理客户端请求,执行阻塞的IO操作(如果需要)和准备响应 此线程将准备好的请求发送回Web服务器 Web服务器又将此响应发送到相应的服务器 服务器为所有客户端执行以上步骤,为每一个客户端请求创建一个线程。 图表说明: Client-1, Client-2, …, Client-n是同时发送请求到Web服务器的客户端应用 Web服务器内部维护着一个有限的线程池,线程池中线程数量为m个 Web服务器逐个接收这些请求: Web服务器拾取Client-1的请求Request-1,从线程池中拾取一个线程T-1并将此请求分配给线程T-1 线程T-1读取Client-1的请求Request-1, 并处理该请求 该请求无阻塞IO处理 处理完必要的步骤后准备将Response-1发送回客户端 Web服务器又将此Response-1发送到Client-1 Web服务器拾取Client-2的请求Request-2,从线程池中拾取一个线程T-2并将此请求分配给线程T-2 线程T-2读取Client-2的请求Request-2, 并处理该请求 该请求无阻塞IO处理 处理完必要的步骤后准备将Response-2发送回客户端 Web服务器又将此Response-2发送到Client-2 Web服务器拾取Client-n的请求Request-n,从线程池中拾取一个线程T-n并将此请求分配给线程T-n 线程T-n读取Client-n的请求Request-n, 并处理该请求 Request-n需要大量的阻塞IO和计算操作 线程T-n需要更多时间与外部系统(SQL, File System)交互,执行必要步骤并准备Response-n并将其发送回服务器 Web服务器又将此Response-n发送到Client-n 如果’n’大于’m’(大多数时候,它是真的),则在使用完所有的m个线程之后,剩余的客户端请求会在队列中等待。 如果这些线程中有大量的阻塞IO操作(例如:和数据库、文件系统、外部服务等交互),那么剩余的客户端也会等待更长的时间。 一旦线程池中的线程空闲且可用于下一个任务,服务器就会拾取这些线程并将它们分配给剩余的客户端请求。 每个线程都会使用到许多资源,如内存等。因此,在将这些线程从忙状态转到等待状态之前,它们应该释放所有获取的资源。 请求/响应无状态模型的缺点: 在处理越来越多的并发客户端请求时会变得棘手 当客户端请求增加时,线程也会越来越多,最后它们会占用更多内存。 客户端可能需要等待服务器释放可用的线程去处理其请求 处理阻塞式的IO任务时浪费时间 NodeJS的架构 - 单线程事件循环 NodeJS不遵循请求/响应多线程无状态模型。 它采用单线程与事件循环模型。 NodeJS的处理模型主要基于Javascript基于事件的模型和Javascript回调机制。...

September 8, 2021 · 1 min · Egbert Ke

V8 Ignition:JS 引擎与字节码的不解之缘

http://arewefastyet.com 网站测试并展示了数个 JavaScript 引擎的性能数据,是各家 JS 引擎性能的比武场: 我们看到在这个比武场上,最近 Chrome 出现了多个新条目,其中很多条目都是关于 v8 的 Ignition 新架构的组合,他们是 v8 引擎最近推出的 JS 字节码解释器。 纵览各个 JS 引擎的实现,我们发现基于字节码的实现是主流。例如苹果公司的 JavaScriptCore (JSC) 引擎,2008 年时他们引入了 SquirrelFish(市场名 Nitro),实现了一个字节码寄存器机(Register Machine)。再如 Mozilla 公司的 SpiderMonkey,他们使用字节码的历史更久,可以追溯到 1998 年的 Netscape 4(见 https://dxr.mozilla.org/classic/source/js/src/jsemit.c ),SpiderMonkey 实现的是堆栈机(Stack Machine)。微软的 Chakra 也使用了字节码,他们实现的是寄存器机(Register Machine)。而 v8 之前的做法是比较“脱俗”的,他们跳过了字节码这一层,直接把 JS 编译成机器码。而在刚刚过去的五一假日前夕,v8 5.9 发布了,其中的 Ignition 字节码解释器将默认启动 :https://v8project.blogspot.co.id/2017/04/v8-release-59.html 。v8 自此回到了字节码的怀抱。 这让笔者不禁怀念起 2007 年 Ruby 1.9 的发布。当时 Ruby 1.9 也是第一次引入了字节码,名为 YARV,由笹田耕一领导主导开发完成。当时,Ruby 还在使用松本行弘的初级的解释器实现,亦即,解释器每次遍历代码的抽象语法树(AST)来进行 Ruby 代码的解释执行。而 YARV 则把抽象语法树(AST)先编译成字节码,然后再运行。引入字节码之后,Ruby 的性能得到了显著的提升。 而这次 V8 引入字节码却是向着相反的方向后退。因为之前 v8 选择了直接将 JS 代码编译到机器代码执行,机器码的执行性能已经非常之高,而这次引入字节码则是选择编译 JS 代码到一个中间态的字节码,执行时是解释执行,性能是低于机器代码的。最终的性能测试势必会降低,而不是提高。那么 V8 为什么要做这样一个退步的选择呢?为 V8 引入字节码的动机又是什么呢?笔者总结下来有三条:...

September 8, 2021 · 2 min · Egbert Ke

v8与webkit的关系

Part11 Chrome页面的绘制(绘制,就是把一个HTML文件变成一个活灵活现的页面展示的过程…),只有一半轮子是Chrome自己做的,还有一部分来自于WebKit,这个Apple打造的Web渲染器。。。 之所以说是一半轮子来源于WebKit,是因为WebKit本身包含两部分主要内容,一部分是做Html渲染的,另一部分是做JavaScript解析的。在Chrome中,只有Html的渲染采用了WebKit的代码,而在JavaScript上,重新搭建了一个NB哄哄的V8引擎。目标是,用WebKit + V8的强强联手,打造一款上网冲浪的法拉利,从效果来看,还着实做的不错。。。 不过,虽说Chrome和WebKit都是开源的,并联手工作。但是,Chrome还是刻意的和WebKit保持了距离,为其始乱终弃埋下了伏笔。Chrome在WebKit上封装了一层,称为WebKit Glue。Glue层中,大部分类型的结构和接口都和WebKit类似,Chrome中依托WebKit的组件,都只是调用WebKit Glue层的接口,而不是直接调用WebKit中的类型。按照Chrome自己文档中的话来说,就是,虽然我们再用WebKit实现页面的渲染,但通过这个设计(加一个间接层…)已经从某种程度大大降低了与WebKit的耦合,使得可以很容易将WebKit换成某个未来可能出现的更好的渲染引擎。。。 Part22 我们知道不同浏览器用的不同的渲染引擎: Tridend(IE)、Gecko(FF)、WebKit(Safari,Chrome,Andriod浏览器) 当然 Chrome 重构了一下 WebKit 然后管它叫 Blink。但是大体架构还是和 WebKit 一致的。 我们看看我们常说的 V8 和 WebKit 有什么关系吧。 下面是 WebKit 的大致结构: 实线框内模块是所有移植的共有部分,虚线框内不同的厂商可以自己实现。 就是说 JS 引擎(JS 虚拟机),WebKit 是默认的是 JSCore,而 Google 则自己实现了一版吊炸天的 V8。 因此虽然同样是WebKit,Safari 用的是 JSCore, Chrome 用的是 V8。 v8与webkit的关系 ↩︎ webkit vs v8 ↩︎

September 8, 2021 · 1 min · Egbert Ke

Ubuntu16.04 编译shadowsocks-libev

记录一下 安装依赖 apt install -y gettext build-essential autoconf pkg-config libtool libpcre3-dev asciidoc xmlto libev-dev libc-ares-dev automake libmbedtls-dev libsodium-dev 下载代码 git clone https://github.com/shadowsocks/shadowsocks-libev.git cd shadowsocks-libev git submodule update --init --recursive //下载子模块 编译 ./autogen.sh ./configure make && make install

August 5, 2021 · 1 min · Egbert Ke

权限系统与RBAC模型概述

前言 一年前,我负责的一个项目中需要权限管理。当时凭着自己的逻辑设计出了一套权限管理模型,基本原理与RBAC非常相似,只是过于简陋。当时google了一些权限管理的资料,从中了解到早就有了RBAC这个东西。可惜一直没狠下心来学习。 更详细的RBAC模型非常复杂。本文只做了一些基础的理论性概述。本文资料完全来自互联网。 权限系统与RBAC模型概述 RBAC(Role-Based Access Control )基于角色的访问控制。 在20世纪90年代期间,大量的专家学者和专门研究单位对RBAC的概念进行了深入研究,先后提出了许多类型的RBAC模型,其中以美国George Mason大学信息安全技术实验室(LIST)提出的RBAC96模型最具有系统性,得到普遍的公认。 RBAC认为权限的过程可以抽象概括为:判断【Who是否可以对What进行How的访问操作(Operator)】这个逻辑表达式的值是否为True的求解过程。 即将权限问题转换为Who、What、How的问题。who、what、how构成了访问权限三元组。 RBAC支持公认的安全原则:最小特权原则、责任分离原则和数据抽象原则。 最小特权原则得到支持,是因为在RBAC模型中可以通过限制分配给角色权限的多少和大小来实现,分配给与某用户对应的角色的权限只要不超过该用户完成其任务的需要就可以了。 责任分离原则的实现,是因为在RBAC模型中可以通过在完成敏感任务过程中分配两个责任上互相约束的两个角色来实现,例如在清查账目时,只需要设置财务管理员和会计两个角色参加就可以了。 数据抽象是借助于抽象许可权这样的概念实现的,如在账目管理活动中,可以使用信用、借方等抽象许可权,而不是使用操作系统提供的读、写、执行等具体的许可权。但RBAC并不强迫实现这些原则,安全管理员可以允许配置RBAC模型使它不支持这些原则。因此,RBAC支持数据抽象的程度与RBAC模型的实现细节有关。 RBAC96是一个模型族,其中包括RBAC0~RBAC3四个概念性模型。 基本模型RBAC0定义了完全支持RBAC概念的任何系统的最低需求。 RBAC1和RBAC2两者都包含RBAC0,但各自都增加了独立的特点,它们被称为高级模型。 RBAC1中增加了角色分级的概念,一个角色可以从另一个角色继承许可权。 RBAC2中增加了一些限制,强调在RBAC的不同组件中在配置方面的一些限制。 RBAC3称为统一模型,它包含了RBAC1和RBAC2,利用传递性,也把RBAC0包括在内。这些模型构成了RBAC96模型族。 RBAC模型简述 RBAC0的模型中包括用户(U)、角色(R)和许可权(P)等3类实体集合。 RABC0权限管理的核心部分,其他的版本都是建立在0的基础上的,看一下类图: RBAC0定义了能构成一个RBAC控制系统的最小的元素集合。 在RBAC之中,包含用户users(USERS)、角色roles(ROLES)、目标objects(OBS)、操作operations(OPS)、许可权permissions(PRMS)五个基本数据元素,此模型指明用户、角色、访问权限和会话之间的关系。 每个角色至少具备一个权限,每个用户至少扮演一个角色;可以对两个完全不同的角色分配完全相同的访问权限;会话由用户控制,一个用户可以创建会话并激活多个用户角色,从而获取相应的访问权限,用户可以在会话中更改激活角色,并且用户可以主动结束一个会话。 用户和角色是多对多的关系,表示一个用户在不同的场景下可以拥有不同的角色。 例如项目经理也可以是项目架构师等;当然了一个角色可以给多个用户,例如一个项目中有多个组长,多个组员等。 这里需要提出的是,将用户和许可进行分离,是彼此相互独立,使权限的授权认证更加灵活。 角色和许可(权限)是多对多的关系,表示角色可以拥有多分权利,同一个权利可以授给多个角色都是非常容易理解的,想想现实生活中,当官的级别不同的权限的情景,其实这个模型就是对权限这方面的一个抽象,联系生活理解就非常容易了。 RBAC1,基于RBAC0模型,引入角色间的继承关系,即角色上有了上下级的区别,角色间的继承关系可分为一般继承关系和受限继承关系。一般继承关系仅要求角色继承关系是一个绝对偏序关系,允许角色间的多继承。而受限继承关系则进一步要求角色继承关系是一个树结构,实现角色间的单继承。 这种模型合适于角色之间的层次明确,包含明确。 RBAC2,基于RBAC0模型的基础上,进行了角色的访问控制。 RBAC2模型中添加了责任分离关系。RBAC2的约束规定了权限被赋予角色时,或角色被赋予用户时,以及当用户在某一时刻激活一个角色时所应遵循的强制性规则。责任分离包括静态责任分离和动态责任分离。约束与用户-角色-权限关系一起决定了RBAC2模型中用户的访问许可,此约束有多种。 互斥角色 :同一用户只能分配到一组互斥角色集合中至多一个角色,支持责任分离的原则。互斥角色是指各自权限互相制约的两个角色。对于这类角色一个用户在某一次活动中只能被分配其中的一个角色,不能同时获得两个角色的使用权。常举的例子:在审计活动中,一个角色不能同时被指派给会计角色和审计员角色。 基数约束 :一个角色被分配的用户数量受限;一个用户可拥有的角色数目受限;同样一个角色对应的访问权限数目也应受限,以控制高级权限在系统中的分配。例如公司的领导人有限的; 先决条件角色 :可以分配角色给用户仅当该用户已经是另一角色的成员;对应的可以分配访问权限给角色,仅当该角色已经拥有另一种访问权限。指要想获得较高的权限,要首先拥有低一级的权限。就像我们生活中,国家主席是从副主席中选举的一样。 运行时互斥 :例如,允许一个用户具有两个角色的成员资格,但在运行中不可同时激活这两个角色。 RBAC3,也就是最全面级的权限管理,它是基于RBAC0的基础上,将RBAC1和RBAC2进行整合了,最前面,也最复杂的: 综上为权限管理模型的相关介绍,其实在任何系统中都会涉及到权限管理的模块,无论复杂简单,我们都可以通过以RBAC模型为基础,进行相关灵活运用来解决我们的问题。 RBAC的优缺点 RBAC模型没有提供操作顺序控制机制。这一缺陷使得RBAC模型很难应用关于那些要求有严格操作次序的实体系统。 例如,在购物控制系统中要求系统对购买步骤的控制,在客户未付款之前不应让他把商品拿走。RBAC模型要求把这种控制机制放到模型 实用的RBAC模型的数据库建模 以下模型均来自于互联网 扩展RBAC用户角色权限设计方案 RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联。简单地说,一个用户拥有若干角色,每一个角色拥有若干权限。这样,就构造成“用户-角色-权限”的授权模型。在这种模型中,用户与角色之间,角色与权限之间,一般者是多对多的关系。(如下图) 角色是什么?可以理解为一定数量的权限的集合,权限的载体。例如:一个论坛系统,“超级管理员”、“版主”都是角色。版主可管理版内的帖子、可管理版内的用户等,这些是权限。要给某个用户授予这些权限,不需要直接将权限授予用户,可将“版主”这个角色赋予该用户。当用户的数量非常大时,要给系统每个用户逐一授权(授角色),是件非常烦琐的事情。这时,就需要给用户分组,每个用户组内有多个用户。除了可给用户授权外,还可以给用户组授权。这样一来,用户拥有的所有权限,就是用户个人拥有的权限与该用户所在用户组拥有的权限之和。(下图为用户组、用户与角色三者的关联关系) 在应用系统中,权限表现成什么?对功能模块的操作,对上传文件的删改,菜单的访问,甚至页面上某个按钮、某个图片的可见性控制,都可属于权限的范畴。有些权限设计,会把功能操作作为一类,而把文件、菜单、页面元素等作为另一类,这样构成“用户-角色-权限-资源”的授权模型。而在做数据表建模时,可把功能操作和资源统一管理,也就是都直接与权限表进行关联,这样可能更具便捷性和易扩展性。(见下图) 请留意权限表中有一列“权限类型”,我们根据它的取值来区分是哪一类权限,如“MENU”表示菜单的访问权限、“OPERATION”表示功能模块的操作权限、“FILE”表示文件的修改权限、“ELEMENT”表示页面元素的可见性控制等。 这样设计的好处有二。其一,不需要区分哪些是权限操作,哪些是资源,(实际上,有时候也不好区分,如菜单,把它理解为资源呢还是功能模块权限呢?)。其二,方便扩展,当系统要对新的东西进行权限控制时,我只需要建立一个新的关联表“权限XX关联表”,并确定这类权限的权限类型字符串。 这里要注意的是,权限表与权限菜单关联表、权限菜单关联表与菜单表都是一对一的关系。(文件、页面权限点、功能操作等同理)。也就是每添加一个菜单,就得同时往这三个表中各插入一条记录。这样,可以不需要权限菜单关联表,让权限表与菜单表直接关联,此时,须在权限表中新增一列用来保存菜单的ID,权限表通过“权限类型”和这个ID来区分是种类型下的哪条记录。 到这里,RBAC权限模型的扩展模型的完整设计图如下: 随着系统的日益庞大,为了方便管理,可引入角色组对角色进行分类管理,跟用户组不同,角色组不参与授权。例如:某电网系统的权限管理模块中,角色就是挂在区局下,而区局在这里可当作角色组,它不参于权限分配。另外,为方便上面各主表自身的管理与查找,可采用树型结构,如菜单树、功能树等,当然这些可不需要参于权限分配。 百度百科所示的模型 本文参考文献中的一种设计 辨析:角色与用户组有何区别? 两者的主要差别是:用户组是用户的集合,但不是许可权的集合;而角色却同时具有用户集合和许可权集合的概念,角色的作用把这两个集合联系在一起的中间媒介。 在一个系统中,如果用户组的许可权和成员仅可以被系统安全员修改的话,在这种机制下,用户组的机制是非常接近于角色的概念的。角色也可以在用户组的基础上实现,这有利于保持原有系统中的控制关系。在这种情况下,角色相当于一个策略部件,与用户组的授权及责任关系相联系,而用户组是实现角色的机制,因此,两者之间是策略与实现机制之间的关系。 ACL模型 访问控制列表,是前几年盛行的一种权限设计,它的核心在于用户直接和权限挂钩。...

July 14, 2021 · 1 min · Egbert Ke

权限系统设计模型分析(DAC,MAC,RBAC,ABAC)

术语 这里对后面会用到的词汇做一个说明,老司机请直接翻到常见设计模式。 用户 发起操作的主体。 对象(Subject) 指操作所针对的客体对象,比如订单数据或图片文件。 权限控制表 (ACL: Access Control List) 用来描述权限规则或用户和权限之间关系的数据表。 权限 (Permission) 用来指代对某种对象的某一种操作,例如“添加文章的操作”。 权限标识 权限的代号,例如用“ARTICLE_ADD”来指代“添加文章的操作”权限。 常见设计模式 自主访问控制(DAC: Discretionary Access Control) 系统会识别用户,然后根据被操作对象(Subject)的权限控制列表(ACL: Access Control List)或者权限控制矩阵(ACL: Access Control Matrix)的信息来决定用户的是否能对其进行哪些操作,例如读取或修改。 而拥有对象权限的用户,又可以将该对象的权限分配给其他用户,所以称之为“自主(Discretionary)”控制。 这种设计最常见的应用就是文件系统的权限设计,如微软的NTFS。 DAC最大缺陷就是对权限控制比较分散,不便于管理,比如无法简单地将一组文件设置统一的权限开放给指定的一群用户。 Windows的文件权限 强制访问控制(MAC: Mandatory Access Control) MAC是为了弥补DAC权限控制过于分散的问题而诞生的。在MAC的设计中,每一个对象都都有一些权限标识,每个用户同样也会有一些权限标识,而用户能否对该对象进行操作取决于双方的权限标识的关系,这个限制判断通常是由系统硬性限制的。比如在影视作品中我们经常能看到特工在查询机密文件时,屏幕提示需要“无法访问,需要一级安全许可”,这个例子中,文件上就有“一级安全许可”的权限标识,而用户并不具有。 MAC非常适合机密机构或者其他等级观念强烈的行业,但对于类似商业服务系统,则因为不够灵活而不能适用。 RedHat MLS Red Hat: MLS 基于角色的访问控制(RBAC: Role-Based Access Control) 因为DAC和MAC的诸多限制,于是诞生了RBAC,并且成为了迄今为止最为普及的权限设计模型。 RBAC在用户和权限之间引入了“角色(Role)”的概念(暂时忽略Session这个概念): RBAC核心设计 图片来自Apache Directory 如图所示,每个用户关联一个或多个角色,每个角色关联一个或多个权限,从而可以实现了非常灵活的权限管理。角色可以根据实际业务需求灵活创建,这样就省去了每新增一个用户就要关联一遍所有权限的麻烦。简单来说RBAC就是:用户关联角色,角色关联权限。另外,RBAC是可以模拟出DAC和MAC的效果的。 例如数据库软件MongoDB便是采用RBAC模型,对数据库的操作都划分成了权限(MongoDB权限文档): 权限标识 说明 find 具有此权限的用户可以运行所有和查询有关的命令,如:aggregate、checkShardingIndex、count等。 insert 具有此权限的用户可以运行所有和新建数据有关的命令:insert和create等。 collStats 具有此权限的用户可以对指定database或collection执行collStats命令。 viewRole 具有此权限的用户可以查看指定database的角色信息。 … 基于这些权限,MongoDB提供了一些预定义的角色(MongoDB预定义角色文档,用户也可以自己定义角色): 角色 find insert collStats viewRole … read ✔ ✔ … readWrite ✔ ✔ ✔ … dbAdmin ✔ ✔ … userAdmin ✔ … 最后授予用户不同的角色,就可以实现不同粒度的权限分配了。...

July 14, 2021 · 2 min · Egbert Ke

单点登录SSO原理

背景 在企业发展初期,企业使用的系统很少,通常一个或者两个,每个系统都有自己的登录模块,运营人员每天用自己的账号登录,很方便。 但随着企业的发展,用到的系统随之增多,运营人员在操作不同的系统时,需要多次登录,而且每个系统的账号都不一样,这对于运营人员 来说,很不方便。于是,就想到是不是可以在一个系统登录,其他系统就不用登录了呢?这就是单点登录要解决的问题。 单点登录英文全称Single Sign On,简称就是SSO。它的解释是:在多个应用系统中,只需要登录一次,就可以访问其他相互信任的应用系统。 如图所示,图中有4个系统,分别是Application1、Application2、Application3、和SSO。Application1、Application2、Application3没有登录模块,而SSO只有登录模块,没有其他的业务模块,当Application1、Application2、Application3需要登录时,将跳到SSO系统,SSO系统完成登录,其他的应用系统也就随之登录了。这完全符合我们对单点登录(SSO)的定义。 技术实现 在说单点登录(SSO)的技术实现之前,我们先说一说普通的登录认证机制。 如上图所示,我们在浏览器(Browser)中访问一个应用,这个应用需要登录,我们填写完用户名和密码后,完成登录认证。这时,我们在这个用户的session中标记登录状态为yes(已登录),同时在浏览器(Browser)中写入Cookie,这个Cookie是这个用户的唯一标识。下次我们再访问这个应用的时候,请求中会带上这个Cookie,服务端会根据这个Cookie找到对应的session,通过session来判断这个用户是否登录。如果不做特殊配置,这个Cookie的名字叫做jsessionid,值在服务端(server)是唯一的。 同域下的单点登录 一个企业一般情况下只有一个域名,通过二级域名区分不同的系统。比如我们有个域名叫做:a.com,同时有两个业务系统分别为:app1.a.com和app2.a.com。我们要做单点登录(SSO),需要一个登录系统,叫做:sso.a.com。 我们只要在sso.a.com登录,app1.a.com和app2.a.com就也登录了。通过上面的登陆认证机制,我们可以知道,在sso.a.com中登录了,其实是在sso.a.com的服务端的session中记录了登录状态,同时在浏览器端(Browser)的sso.a.com下写入了Cookie。那么我们怎么才能让app1.a.com和app2.a.com登录呢?这里有两个问题: Cookie是不能跨域的,我们Cookie的domain属性是sso.a.com,在给app1.a.com和app2.a.com发送请求是带不上的。 sso、app1和app2是不同的应用,它们的session存在自己的应用内,是不共享的。 那么我们如何解决这两个问题呢?针对第一个问题,sso登录以后,可以将Cookie的域设置为顶域,即.a.com,这样所有子域的系统都可以访问到顶域的Cookie。我们在设置Cookie时,只能设置顶域和自己的域,不能设置其他的域。比如:我们不能在自己的系统中给baidu.com的域设置Cookie。 Cookie的问题解决了,我们再来看看session的问题。我们在sso系统登录了,这时再访问app1,Cookie也带到了app1的服务端(Server),app1的服务端怎么找到这个Cookie对应的Session呢?这里就要把3个系统的Session共享,如图所示。共享Session的解决方案有很多,例如:Spring-Session。这样第2个问题也解决了。 同域下的单点登录就实现了,但这还不是真正的单点登录。 不同域下的单点登录 同域下的单点登录是巧用了Cookie顶域的特性。如果是不同域呢?不同域之间Cookie是不共享的,怎么办? 这里我们就要说一说CAS流程了,这个流程是单点登录的标准流程。 上图是CAS官网上的标准流程,具体流程如下: 用户访问app系统,app系统是需要登录的,但用户现在没有登录。 跳转到CAS server,即SSO登录系统,以后图中的CAS Server我们统一叫做SSO系统。 SSO系统也没有登录,弹出用户登录页。 用户填写用户名、密码,SSO系统进行认证后,将登录状态写入SSO的session,浏览器(Browser)中写入SSO域下的Cookie。 SSO系统登录完成后会生成一个ST(Service Ticket),然后跳转到app系统,同时将ST作为参数传递给app系统。 app系统拿到ST后,从后台向SSO发送请求,验证ST是否有效。 验证通过后,app系统将登录状态写入session并设置app域下的Cookie。 至此,跨域单点登录就完成了。以后我们再访问app系统时,app就是登录的。接下来,我们再看看访问app2系统时的流程。 用户访问app2系统,app2系统没有登录,跳转到SSO。 由于SSO已经登录了,不需要重新登录认证。 SSO生成ST,浏览器跳转到app2系统,并将ST作为参数传递给app2。 app2拿到ST,后台访问SSO,验证ST是否有效。 验证成功后,app2将登录状态写入session,并在app2域下写入Cookie。 这样,app2系统不需要走登录流程,就已经是登录了。SSO,app和app2在不同的域,它们之间的session不共享也是没问题的。 有的同学问我,SSO系统登录后,跳回原业务系统时,带了个参数ST,业务系统还要拿ST再次访问SSO进行验证,觉得这个步骤有点多余。他想SSO登录认证通过后,通过回调地址将用户信息返回给原业务系统,原业务系统直接设置登录状态,这样流程简单,也完成了登录,不是很好吗? 其实这样问题时很严重的,如果我在SSO没有登录,而是直接在浏览器中敲入回调的地址,并带上伪造的用户信息,是不是业务系统也认为登录了呢?这是很可怕的。 总结 单点登录(SSO)的所有流程都介绍完了,原理大家都清楚了。总结一下单点登录要做的事情: 单点登录(SSO系统)是保障各业务系统的用户资源的安全 。 各个业务系统获得的信息是,这个用户能不能访问我的资源。 单点登录,资源都在各个业务系统这边,不在SSO那一方。 用户在给SSO服务器提供了用户名密码后,作为业务系统并不知道这件事。 SSO随便给业务系统一个ST,那么业务系统是不能确定这个ST是用户伪造的,还是真的有效,所以要拿着这个ST去SSO服务器再问一下,这个用户给我的ST是否有效,是有效的我才能让这个用户访问。 本文转载自阿里云社区

June 30, 2021 · 1 min · Egbert Ke

MySQL 如何对order by优化

对于order by的优化,MySQL若可以利用索引的有序性进行排序,则优先使用索引进行排序,这种情况的执行效率是最快的;若无法有效利用索引的情况下,MySQL主要有3排序种算法对其进行优化每个算法都有一定的适用场景。 一、 利用索引排序 B-tree索引可以很好的支持单点查询、范围查询、有序性查询。所以对于order by 的排序查询,我们可以利用B-tree的有序性来有效的利用索引进行排序查询。当然,如果可以利用索引进行排序对我们的SQL查询本身也是有一定的要求限制的。 1.1 利用索引排序的特点 排序列必须有B-tree索引 如果为多表关联查询,排序列必须是对驱动表字段的排序 1.2、示例 ##建表语句,sbtest3与sbtest4表字段与索引一致,sbtest3的表数据量为30000,sbtest4的表数据量为60000 CREATE TABLE `sbtest4` ( `id` int(11) NOT NULL AUTO_INCREMENT, `k` int(11) NOT NULL DEFAULT '0', `c` char(120) NOT NULL DEFAULT '', `pad` char(60) NOT NULL DEFAULT '', PRIMARY KEY (`id`), KEY `k_4` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=62768 DEFAULT CHARSET=utf8mb4 ##单表排序查询 ##order by字段为B-tree索引字段,可以看到执行计划有效利用了索引进行排序查询 root@mysql57 13:25: [db2]> explain select * from sbtest4 t4 order by t4.k desc limit 5; +----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-------+ | 1 | SIMPLE | t4 | NULL | index | NULL | k_4 | 4 | NULL | 5 | 100....

June 20, 2021 · 4 min · Egbert Ke