• 記得這個 gem 有處理該問題 https://github.com/tsechingho/ckeditor-rails

  • Swift 代码片段求解释 at 2014年06月03日

    我的理解:

    第 1 行是宣告这个 func 要返回的是一个「输入是 Int,输出是 Int」的 func

    第 2 行是宣告一个新的 func 其「输入是 Int,输出是 Int」

    最后的 return 就必须回传一个 type 跟 1 所宣告的 func type 有 match 的 func。

    也就是说 1 和 2 的 (Int -> Int) 是分开的,首先 function 要宣告 return type,接著动态产生的 function 也要宣告 type,其 type 要 match return type。把它当一个变数来想就行了。

  • 用过,它的 API 确实是比较难理解,需要用 Stream 的方式去理解。

    最简单的用法是这样:

    http://qiita.com/chitsaou/items/7e059f1ebeedcbcd5703

    Requires Rubyzip 1.1.0+

    Given a data of Zip file that is read from an IO, extract that data into a Hash.

    def unzip(data)
      fin = StringIO.new(data)
    
      entries = {}
    
      ::Zip::InputStream.open(fin) do |fzip|
        while entry = fzip.get_next_entry
          entries[entry.name] = fzip.read
        end
      end
    
      entries
    end
    

    Example:

    entries = unzip(open("http://example.com/archive.zip").read)
    entries["file.txt"] #=> "Hello World\n" (File Content)
    
  • 我上周也分享了一些坑,不过主要是 Ajax 相关的…

    https://speakerdeck.com/chitsaou/angularjs-rails-ajax-pitfalls-and-solutions

  • Category.where(:id => [1,4,5])
    

    如何呢?

  • 虽然离题,但分享一下 Angular 的做法,一样是要第三方插件辅助(称为 Directive)

    https://github.com/vitalets/checklist-model

  • #1 楼 @hooopo #2 楼 @megayu

    谢谢,的确直接存整数会简单许多。

    我试出来再来贴上我的解法供参考…

  • 同问…以前用 sphinx 可以自己写索引规则,用 elasticserach 却找不到怎么做…

  • match ':controller(/:action(/:id(.:format)))'
    

    不要用这个,这是大忌。至于书太旧以至于没修正,你就先跳过吧…

  • Mac 默認的文件系統不分大小寫

    1. box-sizing 是 CSS 的属性,基本上 CSS 属性除非是打错字,否则不会影响基本功能。
    2. box-sizing 目前所有主流浏览器都有支持,除了 Firefox 还需要有 -moz 前缀,估计楼主用的是 Firefox,而 bootstrap 一定会有另一条声明是 -moz-box-sizing ,所以 Firefox 上的 CSS 排版基本上不会有问题。
    3. 如果是 Firefox,它应该会把这个错误归类在 CSS Warning 里面,删 JavaScript 可以消除警告,表示 JavaScript 里面有动态写入 CSS。

    结论:请直接无视这个警告即可。


    现在才知道 RubyChina 会储存草稿…

  • #21 楼 @zhangyuxiu 由於 OAuth 2 裡面的 Code 和 Token 都有「過期」這個機制,若 client 使用過期的 code 要視為攻擊事件,有幾個相對應的處置方式(記得是要把該 code 生成的 token 給撤銷?),而過期的 token 是在 resource server 檢查的,「過期」跟「找不到」是兩回事,要返回不同的 error。

    為了要知道該現存的 code 或 token 是否過期,必須保存原本的值,所以數據不會刪掉,而是由程序來判斷是否過期。

    至於 doorkeeper,裡面似乎沒有利用到緩存系統…

  • RFC 6750 里面规定的是「只送 access_token」,所以你说「不需要送 secret」这是正确的。

    至于签名,由于 client_secret 在 public client 很容易被偷,所以在 client 对 access token 签名并不能防止被偷。

    在 RFC 6749 里面,防范 token 被劫持的方式比较消极,除了 SSL 之外,好像就是对 public client 核发短效期的 token 来对应(几天就失效,降低被偷走的风险),事实上,在 public client,所有数据可以被偷走,在 OAuth 2 里面没有规划绝对防止这个问题的方式。

    注:我不确定 OAuth 2 的 MAC Token 能不能解决你的问题,这份 spec 我没有看。

  • Dash 不是 缓存 下载在本地吗?我觉得它搜索已经够快了,比上网找还快…

  • 日前我分享了「简单易懂的 OAuth 2.0」,以下是那次演讲的 slides,你可以看看,大致上规格书里面的重点我都讲到了

    https://speakerdeck.com/chitsaou/jian-dan-yi-dong-de-oauth-2-dot-0

  • OAuth 2.0 的 spec 也是这样规定的,我来说一下为什么:

    • /authorize 不能提供 secret,因为这里的操作是经过 browser 的,提供 secret 等同于外泄 secret。
    • 有了 secret 就能取得 token,所以 client 要把 secret 当做密码来看待
    • /token 是网站 client 的后端要去取得 token 用的,这里的通道可以保证安全,所以 secret 不会外泄

    另外 secret 只适用于「比较不会被黑的 client」,例如网站后端,这种称为 confidential client,相对应的是 public client,举凡手机应用、桌面应用、JavaScript 应用都算,这种因为很容易就抓出数据,所以 authorization server 就算收到它们的 id + secret 也无法证实它们是真正的 client,因此在这些应用里面,通常是用 implicit flow 来取得 token 的。

  • #34 楼 @zhangyuxiu 回完才看到你在 http://ruby-china.org/topics/15884 也有贴文 :p 应该就是一楼的回答这样子的原因了

  • #34 楼 @zhangyuxiu

    我认为是这样:

    • 索取 Token 这个操作需要真正可以信赖的 client 來执行
    • 在 Authorization Code Grant Flow 里面,是由放在服务器上面的 client 来做(也就是网站的后端程序)
    • 可以通过 Client Authorization 来确认 Client 是真的

    在 Implicit Flow 里面,完全依赖浏览器,Client 无法信赖,虽然可以一步得到 Token,但由于 Client 不可信,以及 Client 里面的数据很容易就能取出(包括 Access Token),所以规格书里面规定,这个流程取得的 Token 时效要很短,并且无法自动 Refresh。

  • #32 楼 @coderek 不會,因為 doorkeeper_for 是半成品,雖然可以動,但要做到像 RFC6750 那樣的標準,還是得自己刻一份

  • #18 楼 @fengxiangzhu Hi, Token 是随机字串,用 SecureRandom.hex 之类的东西产生就行了,重点是 client 如何取得这个 Token。另外,验证 token 的时候,Resource Server 和 Authorization Server 之间本来就没有交互,只是存取同一个数据库而已。

  • #16 楼 @zhangyuxiu 10 分钟是降低这个 code 外泄的风检,若是外泄就可能会让第三者拿到 code 并且换得 token,因为「用 code 换 token」完全无法透过 redirect_uri 确保 token 真的返回到 client 那边,攻击者若是取得 client 的 id 和 secret,完全可以伪造 token request。另一方面,code 长时效也没有实务上的用途,因为在 client 取得 code 之后,就应该马上从后台向验证服务器换得 token,那么拖太久也没有实际的用处,所以就设个 10 分钟。10 分钟我记得是 spec 里面建议的。

    state 参数是 client 要检查的,不论是哪一步,只要认证服务器有返回 state,万一 state 不一致,就必须将其视为有问题,不可以继续处理。我看到 Amazon 的文件 还特别提到 state 可以用 HMAC 算法签过,返回之后再验证签名是否正确。

    谢谢你提问,这样我也可以确定我对 spec 是否瞭解 :)

  • grant code 也是随机产生的。在 authorization code grant flow 里面,client 拿到 code 之后,必须在后台发 POST 向授权服务器换到 token,这个过程必须经过 "client authentication" ,也就是 client 本身必须登入 (login) 到授权服务器,具体方法就是放在 Authorization header 里面。

    你可以看一下我写的 OAuth 2.0 Tutorial: Grape API 整合 Doorkeeper 这篇教程,在 Step 3.2 有示范这个过程。

  • redirect_uri 会在 authorization code grant flow 和 implicit flow 里面用到,这个参数指的是认证服务器在得到 user 同意或拒绝的答案的时候,要转回 client 的 uri,这个 uri 在 client 注册的时候,要预先在认证服务器写下来,可以一个,也可以多个,但若 uri 跟预先注册的不符,则认证服务器不可以转到这个 uri,以免 token 被第三方偷走。预先注册也是用来确保「认证服务器传给 client 的信息,一定是给真正的 client」。

    若在授权流程中不传递 uri,可以直接使用 client 注册时所填写的那唯一一个 uri。

  • #7 楼 @zhangyuxiu

    关于 Access Token 的内容,其实是这样子:token 本身是随机产生的文字,在核发 token 的时候,用一个 JSON 包起来,里面会记载详细的信息,例如:

    {
      "access_token":"XXXXXXXXXXXXXXXXXXXXXX",
      "token_type":"Bearer",
      "expires_in":3600,
      "scope": "abc def ghi",
      "refresh_token":"YYYYYYYYYYYYYYYYYYYYYYY"
    }
    

    Client 要记住的就是这些信息:

    • access_token 是去打 API 的时候要附上的参数
    • token_type 指的是这个 token 的类别,不同的类别有不同的使用方法,bearer 就是 RFC6750 定义的,其他还有 MAC,这个使用的时候似乎需要一堆加密算法,我不是很清楚。
    • expires_in 指的是几秒之后过期,Client 就必须重新向 user 要求授权,或是使用 refersh_token 来刷新
    • scope 表示权限有哪些,这个不一定会出现,若是出现,表示 user 授权的权限和 client 要求的不一致,所以必须提示 client。如果跟请求授权的时候的一样,那就不会附上,因为 client 本来就知道。
    • refresh_token 就是说过期之后可以重新刷新

    资源服务器和授权服务器都有这些信息,可以判断一个 token 是否合法。

    最好是不要在 token 字串附上这些信息,即使是 hash 过的也不好,因为这样子就有机会可以假造 token。要把 token 字串视为一个参照,服务器用这个 token 字串去查到真正的授权内容。

    而 Client 平常在向资源服务器发出 request 的时候,实际上是只使用 access_token:

    https://api.example.com/user/me?access_token=XXXXXXXXXXXXXXXXXXXXXX
    

    至于你说授权服务器或资源服务器会滥用 token,我会说这不是 protocol 设计的目的,它就是定义授权服务器是核发授权、管理授权的机关,而资源服务器是看授权书来决定要不要让你进来的另一个机关。好比说你若要出国,你必须有护照,护照是外交部发的,而到了海关,你要把护照给海关看,海关验证无误才会放行,这里的外交部就是授权服务器,而海关就是资源服务器,它们本来就是一起合作的,不需要考虑外泄的问题。

    真正需要考虑外泄,是 client 本身资料外泄,或是通信中被拦截封包。例如手机上的 app 不论如何都无法防止 token 外泄(可以越狱),所以授权服务器对这种 client(称作 public client)要当作不可信任,即使它送出 client 的帐号密码(在注册 client 的时候,授权服务器会发一组帐密),也不可以完全相信。


    最后你说到 https,凭证可以自己产生,并且虽然规格书里面有规定必须验证凭证链是否无误、有没有被更上级的撤销,但你实作上就把这个验证机制关掉就行,只是依然要检查凭证是否没有改变,这个我不熟,或许可以找找看关于 SSL 凭证验证的文章。

    我说的那些 front-end server 请你先忘掉 :p

    独立域名应该是需要,你可以部署在 heroku 上面,也会有独立域名,例如 abc.herokuapp.com。如果 client 和 server 共用一个域名,例如 www.example.com ,那么 redirect uri 前缀一致就可能有风险,所以最好还是开在不同的域名,host 不同就行了。

  • Resource Server (API) 和 Authorization Server (核发 token 的服务器) 在概念上是分离的,但实作上可以放在一起,我实作的时候就是 API 用 Grape 写,Authorization Server 用 Doorkeeper 盖,所以可以直接去存取 ActiveModel,那如果要分离在不同的 applications (例如 API 用 node.js 刻) ,那就在 API 那边想办法去拉出 token 来验证就好了,这个在 spec 里面没有定义,你可以看是要存取同一个数据库、开另一个服务器在内网拉 token,还是定期两方同步,都是方法。我比较懒,直接存取同一个数据库(其实是同一个 Model)。

    希望这说明有帮到你 :)

  • #28 楼 @zhangyuxiu 刚刚回应了 :)

  • 听到了 OAuth 2 这个关键字,在下只好跳出来了。

    1. Access Token 产生的方法,你若要问的是 token 的文字,那并没有规定,照习惯都是用一串很长的 hash 字串。你若要问的是如何向 client 送出这个 token,那么这是 protocol 里面有定义的,只要照 protocol 跑就没问题。若你要造的是「提供 OAuth 2.0 认证的服务器」,那么直接照 RFC6749 来实作就行。
    2. Resource Server 验证合法性的方法就是去数据库里面拿出 token,看它有没有过期、有没有被撤销 (revoked) ,若「要存取的 resource 需要特定的权限,例如私讯内容」,则 token 上面要有记载相关权限,叫做 scopes。这些都没问题,就放行。最简单的 Token 用法是 Bearer Token (RFC6750) ,它只认 token 字串,不像 MAC Token 需要过一堆加密算法。
    3. OAuth 2.0 强制你要上 https,development 环境就算了,而 production 上 https 的方式就看 Rails 怎么上 https 就怎么上,也有人直接在 front-end server 上 https、后面的 load balancers 走明文的。

    我要厚脸皮地来推荐一下我写的文章: