背景
公司一直使用confluence來(lái)進(jìn)行內(nèi)部知識(shí)管理。老板突然想用飛書,然后讓我將confluence與飛書打通。因此開(kāi)始了解confluence和飛書的打通問(wèn)題。
confluence sso 基礎(chǔ)知識(shí)
Jira和Confluence集成了Atlassian自己開(kāi)的一套SSO系統(tǒng)——Seraph。Seraph是由Atlassian開(kāi)發(fā)的非常簡(jiǎn)單,可插入的J2EE 網(wǎng)頁(yè)安全應(yīng)用框架,它被廣泛使用在Atlassian的產(chǎn)品中。
Seraph允許你寫自定義的認(rèn)證器,來(lái)將confluence/jira與你的系統(tǒng)來(lái)打通。
下圖是Confluence認(rèn)證的流程圖,大體流程如下:
- 嘗試通過(guò)request的passord和密碼登錄
- 嘗試通過(guò)已經(jīng)存在的session進(jìn)行登錄
- 嘗試通過(guò) cookie登錄
- 嘗試通過(guò)http ba認(rèn)證登錄

由于Authenticator.login(request, response, username, password, rememberMe)這個(gè)方法出現(xiàn)了三次,看起來(lái)有點(diǎn)復(fù)雜。所以它已經(jīng)被分解到了自己的子流程中。如下為登錄的子流程:

支持的認(rèn)證方法
如上述流程圖所示,默認(rèn)的Seraph認(rèn)證支持四種認(rèn)證方法:
- 請(qǐng)求參數(shù)。
os_username和os_password。 - session屬性儲(chǔ)存登錄用戶。
- cookie存儲(chǔ)
username和password(remember me登錄) - 通過(guò)標(biāo)準(zhǔn)的http頭進(jìn)行Http ba認(rèn)證
每個(gè)方法按上述流程圖的順序進(jìn)行嘗試。前面的方法成功登錄后,會(huì)略過(guò)后續(xù)的登錄流程。某個(gè)登錄失敗后,會(huì)依次嘗試后續(xù)的方法直到所有的都失敗。此時(shí),用戶被認(rèn)為是“匿名用戶”,并按Confluence中的匿名用戶的權(quán)限進(jìn)行處理。我們需要覆蓋該方法,并在后面加上對(duì)應(yīng)的與飛書的http認(rèn)證就可以了。
參照源代碼可以看出,Seraph支持基于角色的認(rèn)證,但是這個(gè)在confluence中僅被用來(lái)鑒權(quán) /admin/ URL的訪問(wèn)權(quán)限(如果要使用飛書的管理員,可以用這個(gè))。
代碼流程講解
在系統(tǒng)中,上述的代碼流程在com.atlassian.confluence.user.ConfluenceAuthenticator中,我們?nèi)绻枰远xhttp認(rèn)證,需要如下的流程:
- 寫一個(gè)類,繼承自
com.atlassian.confluence.user.ConfluenceAuthenticator, 覆蓋其getUser方法, 參考代碼seraph。(注意,示例中繼承的類是DefaultAuthenticator, 這個(gè)是在confluence 2.2及以下才可以,其余的請(qǐng)繼承com.atlassian.confluence.user.ConfluenceAuthenticator) - 將代碼打包成jar放置于
confluence安裝目錄/WEB-INF/lib/下(或者將類放入WEB-INF/classes/下,我沒(méi)試過(guò)是否OK)。 - 打開(kāi)
confluence安裝目錄/WEB-INF/classes/seraph-config.xml, 修改如下內(nèi)容:
<security-config>
<parameters>
<init-param>
<param-name>login.url</param-name>
<!--把登錄url改為飛書的登錄鏈接,appid填你的網(wǎng)頁(yè)app的appid-->
<param-value>https://open.feishu.cn/open-apis/authen/v1/index?redirect_uri=${originalurl}&app_id=&state=</param-value>
</init-param>
<init-param>
<param-name>link.login.url</param-name>
<!--鏈接同上-->
<param-value>https://open.feishu.cn/open-apis/authen/v1/index?redirect_uri=${originalurl}&app_id=&state=</param-value>
</init-param>
<!-- 其它配置省略,不用動(dòng)-->
</parameters>
<!-- 其它配置省略,不用動(dòng)-->
<!--
修改認(rèn)證器的class, 指向自己寫的子類
<authenticator class="com.atlassian.confluence.user.ConfluenceAuthenticator"/>
-->
<authenticator class="com.example.test.xxConfluenceAuthenticator"/>
<!-- 其它配置省略 -->
</security-config>
- 保存,并重啟confluence。登錄后,系統(tǒng)會(huì)跳轉(zhuǎn)到飛書登錄頁(yè)。
- 這種情況下,confluence的首頁(yè)會(huì)變?yōu)轱w書的登錄頁(yè),我們可以通過(guò)飛書來(lái)登錄了。但是還有個(gè)問(wèn)題,confluence并不會(huì)關(guān)掉之前的用戶名密碼登錄,用戶還是可以訪問(wèn)那個(gè)頁(yè)面。我們可以在nginx下加上對(duì)應(yīng)的處理,來(lái)關(guān)掉這個(gè)頁(yè)面的訪問(wèn)(apache自行按對(duì)應(yīng)規(guī)則處理):
location /login.action {
// 釘釘,飛書等的登錄跳回時(shí),會(huì)帶上code作為登錄憑證,普通用戶不會(huì)。因此直接將所有不帶code訪問(wèn)login的請(qǐng)求rewrite
if ($args !~ code=){
rewrite ^ http://xx.com/;
}
}
總結(jié)
整體流程很簡(jiǎn)單,基本就是寫個(gè)認(rèn)證的子類,然后把配置中的類指向我們寫的子類即可。麻煩的部分是如何構(gòu)建一個(gè)confluence的開(kāi)發(fā)測(cè)試環(huán)境,并且如何調(diào)用confluence的類,這一部分,下次再寫吧。