会话与API安全 - 下
在大部分时候,我们讨论API的设计时,会从功能的角度出发定义出完善的,易用的API。而很多时候,非功能需求如安全需求则会在很晚才加入考虑。而往往这部分会涉及很多额外的工作量,比如与外部的SSO集成,Token机制等等
在大部分时候,我们讨论API的设计时,会从功能的角度出发定义出完善的,易用的API。而很多时候,非功能需求如安全需求则会在很晚才加入考虑。而往往这部分会涉及很多额外的工作量,比如与外部的SSO集成,Token机制等等
PageObject简介 PageObject是编写UI测试时的一种模式。简而言之,你可以将所有知道页面细节的部分放入到这个对象上,对于编写测试的人来说,一个PageObject代表了一个页面,或者页面上的一个区域(比如搜索框,搜索结果,侧边栏等都可能是一个独立的Object)。这样做的好处分为两个方面: 封装了所有的实现细节(内部的HTML是如何组织的) 对外的接口非常清晰,从而代码更加语义化 我们这里列举一个简单的例子来说明: 我们要测试的场景是:我们在一个搜索应用中,用户输入了ThoughtWorks,我们来判断搜索结果的第一页有10条结果。如果使用原生的capybara,代码大致会如下: visit '/search' fill_in 'Search', :with => 'ThoughtWorks' click_button '#search' expect(find('#result').find('.tips')).to have_content("10") 首先我们进入/search页面,然后在Search中输入了ThoughtWorks关键字,然后点击#search按钮,最后判断#result .tips下有10的字样。 如果使用PageObject,代码则会变成(这个是伪代码): search = SearchBox.new result = SearchResult.new search.type "ThoughtWorks" expect(result.count).to eq(10) site_prism 简介 site_prism是一个构建在capybara之上的用于建模Page Object的gem。使用site_prism可以很语义化的编写Page Object,可以使代码非常易读。 位于顶层的Page对象可以拥有多个Section对象,每个Section可以对应页面上的一些逻辑上的块,比如内容区域,边栏等。对于现在流行的SPA,我们只需要一个Page和若干个Section就足够了。 class MovingHome < SitePrism::Page set_url 'http://localhost:8100/bundles/moving-home' element :container, "#tmsCheckout" section :personal, PersonalSection, "#acc-personal" section :contact, ContactSection, "#acc-contact" end set_url方法制定了如何到达当前页,也是webdriver会实际发送请求的URL。页面本身上可以用element方法来声明一个元素,以及该元素对应的CSS选择器,这样就可以通过元素的名称来访问该选择器对应的HTML元素了。 比如上例中的container,我们在测试中就可以这样来访问它: @moving = MovingHome.new @moving.load @moving.container.should be_visible 而对应的section元素,则声明了一个块的名称,块的类和块的选择器。这样我们就可以通过名称来应用该块了: @moving.personal.name.set "Juntao" expect(@moving).to have_personal expect(@moving).to have_contact have_前缀加块的名称,用来判断该块是否可见(比如display: block)。...
千古谜题 — 中午吃啥? 如果要列出一些日常最频繁的会问/被问的问题的一个列表,吃啥?绝对会排在前三位,对于程序员来说,一样频繁的还有诸如这是谁写的?,***这尼玛啥意思啊?***之类。 吃啥作为一个每天都会面对的问题,我们自然而言会想很多办法,比如随大流,其他人去哪儿我们跟着就行,但是这种方法最大的问题是:大部分人其实都没有很好的想法,大家都很迷茫。作为程序员,一个非常直观的想法就是找出一个列表,然后随机/伪随机的从这个列表中拿出一条来作为推荐。 基本思路 一个基本的思路是这样的,或者说,要开发的软件应该满足这几个基本的需求 维护一个饭店/饭菜的列表 随机的从这个列表中取出一项 每天定时的触发,比如11:30准时提醒 这个工具最终要以弹出窗口等方式来提醒 饭店/饭菜的列表比较容易,比如一个静态的JSON文件: [ { "name": "关中客大碗面" }, { "name": "王华峰肉夹馍" }, { "name": "傻得帽冒菜" }, { "name": "蒸饺" }, { "name": "樊家肉夹馍" }, { "name": "马奴哈羊肉泡馍" }, { "name": "子午路张记肉夹馍" }, { "name": "东滩水盆" } ] 然后我们需要一个小程序来读取这段JSON,并已随机/伪随机的方式返回一个推荐: # encoding: UTF-8 require 'json' def first JSON.parse(File.open("food.json").read).shuffle[0]["name"] end puts "今天去吃#{first}吧?" 测试一下,将上边这个ruby程序运行几次,可以得到一下结果: $ ruby lunch.rb 今天去吃东滩水盆吧? $ ruby lunch.rb 今天去吃子午路张记肉夹馍吧? $ ruby lunch....
一个场景 元编程在所有的Lisp系语言中应该都是一个必备的feature,coommon lisp, scheme等包含该功能自然不在话下,而比较主流的编程语言如JavaScript,python之流,也或多或少的受到了lisp得影响,在面向对象的同时,也嵌入了一些元编程的特性。 而元编程在ruby中,虽然不如在lisp的宏那样灵活/强大,但是对于被“主流”编程语言影响很久的程序员 – 如我,来说,已经非常震撼了。 很多ruby程序员都是通过rails才慢慢接触到ruby本身的,在rails中,ORM是通过强大到无穷大得ActiveRecord来完成的。 一个简单的示例如: class Person < ActiveRecord::Base end 对应的,数据库中有一个Person的表: CREATE TABLE person ( id int(11) NOT NULL auto_increment, name varchar(255), age int, email varchar(255), PRIMARY KEY (id) ); 这样,在使用模型Person的地方,可以很容易的编写这样的代码: juntao = Person.new juntao.name = 'juntao' juntao.age = 28 juntao.email = 'juntao.qiu@gmail.com' juntao.save 也就是说,开发者仅仅需要简单的创建一个与数据库同名的ruby类,然后这个类(Person)只需要继承自ActiveRecord::Base,那么它就自动的获得了很多的功能。这些神奇的功能就是通过ruby的元编程来完成的。 一个ActiveRecord的拙劣模仿 我们在这里将编写一个简单的类InactiveRecord,当有其他类继承自此类时,会完成如ActiveRecord那样的功能,当然第一步我们并没有数据校验之类的功能,只是简单的将数据存储起来即可: 在person.rb文件中 class Person < InactiveRecord::Base end 在address.rb中: class Address < InactiveRecord::Base end 而在使用他们的地方: require './person' require './address' def test juntao = Person....
Grape简介 Grape是一个基于Rack的非常轻量级的框架,用于快速的开发API。一般来说,Rails对于单独的API来说,太过于重量级;而Sinatra虽然足够小巧,但是又没有为开发API提供足够的默认支持(如果从可控制性,灵活性上来说,Sinatra可能更好一些,但是如果有专门的更好用的工具,为什么不用呢?)。 安装非常简便: $ gem install grape 或者使用在自己的Gemfile中,与其他的gem一起搭建API: gem 'grape' 为既有系统添加API 简单一试 之前的一篇介绍ActiveRecord在既有系统中使用的文章中,我使用ActiveRecord为既有的数据库visitor中的三个表(visitor, listGroup, listGroupItem)建立了ruby对应的模型。现在我们可以为这些模型包装一组API,以方便客户端(消费者)可以通过web来访问。 module MySys class API < Grape::API format :json resource :visitors do desc "get all visitor information" get do Visitor.limit(20) end end end end 首先,MySys::API扩展了Grape::API。format定义我们的API会产生JSON格式的输出,resource定义了这一组API是为资源visitors提供的,因此访问API的url为: http://localhost:9292/visitors/ 当然,grape提供一个很方便的设置prefix,可以使得API的路径更有意义: format :json prefix "mysys" url则相应地变为: http://localhost:9292/mysys/visitors/ 处理参数 在对参数的处理上,grape也非常灵活,比如接上例,我们想要获取某一个具体的用户的信息: http://localhost:9292/visitors/8a9d82b13b9786e1013b978766150001 我们可以添加一个新的endpoint: desc "return a visitor" params do requires :visitor_uid, :type => String, :desc => "visitor id" end route_param :visitor_uid do get do Visitor....