前一陣部門要作一個內部討論區,但願能和原有的gitlab集成在一塊兒。php
discuz雖然成熟可是感受不夠高大上,找了幾個ruby的論壇discourse,rabel雖然時髦值夠了可是成熟度又缺了點,最後選了php的question2answer做爲論壇程序,採用iframe的方式嵌入原來的gitlab程序。html
因爲兩個業務在同一個域名下,這裏就放棄了複雜的cas方案;考慮源代碼安全,沒有用cookie存儲用戶信息,最後決定使用共享session的方式實現單點登陸git
gitlab使用devise做爲登陸框架,關於session的配置在config/initilizers/sessions.rb下,默認使用redis方式保存sessionredis
Gitlab::Application.config.session_store( :redis_store, # Using the cookie_store would enable session replay attacks. servers: Gitlab::Application.config.cache_store.last, # re-use the Redis config from the Rails cache store key: '_gitlab_session', secure: Gitlab.config.gitlab.https, httponly: true, path: (Rails.application.config.relative_url_root.nil?) ? '/' : Rails.application.config.relative_url_root )
這裏也能夠改爲在數據庫或者memcached裏存儲,存儲格式與redis相似,很少講了。算法
redis裏key爲session id,value爲序列化後的數據,默認使用的序列化算法爲marshal,理論上只要php讀出內容來就能夠取得session數據了。數據庫
不幸的是,php裏沒有可以直接反序列化marshal對象的的方法。json
最初考慮把marshal改成json方式存儲,須要修改redis-store的一些代碼,主要是覆蓋源代碼中的marshal和unmarshal函數,替換爲json實現。具體能夠參考:Sharing Rails sessions with PHP, ColdFusion, and more!安全
不過用這個方法出現了一些問題:marshal序列話會保存對象的一些meta信息,json是沒有這些信息的,致使反序列化以後的ruby對象與序列化以前不同。ruby
undefined method `sweep' for {"notice"=>"Logged in successfully."}:Hash
在網上搜索好久,一個日文的blog提出瞭解決方案:Rails sessionのシリアライズにJSONが使われない理由: なぜMarshal? JSON/YAMLの罠服務器
主要是在反序列化的時候加了這麼一句:
if original.has_key?('flash') original['flash'] = ActionDispatch::Flash::FlashHash.new.update(original['flash']) end
3.3.折衷的方式
這麼深度的修改對於這個需求彷佛太複雜了,最後仍是決定用簡單些的方式,利用ruby開放一個session的json接口,php經過調用接口得到用戶信息,修改的地方不多:
ruby
class ActiveController < ApplicationController def show render :json => current_user end end
php
if ($_COOKIE['_gitlab_session']) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "http://localhost:8080/active"); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_COOKIE, '_gitlab_session='.$_COOKIE['_gitlab_session']); $filecontent=curl_exec($ch); curl_close($ch); $obj=json_decode($filecontent,true); // handle $obj //...