前一阵部门要作一个内部讨论区,但愿能和原有的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 //...