基於OAUTH2的統一認證的例項解析

2021-09-03 07:47:40 字數 4475 閱讀 9413

sso與多平台登入

sso一般用於同一單位的多個站點的登陸狀態保持,技術上一般參考cas協議;多平台登入一般是oauth體系的協議,有多種認證模式但是不具備會話管理和狀態保持。

不過從本質上講,我覺得兩者都是通過可信的第三方進行身份驗證,如果說同一單位的多個子系統共同只圍繞乙個第三方賬戶(可以稱為認證中心)進行多平台登入驗證,那麼在第三方平台登入後再訪問其他**,效果和統一登入是差不多的。此外,oauth2還有個好處就是可以實現跨平台的登入管理,因為他的認證過程不依賴於session和cookie,比如對於移動端裝置,以及在前後端分離後這種登入認證方式也可以起到很大作用。

這篇文章裡我就著結合之前專案中整合過的oauth2來講一講這種登入認證的過程。專案是基於shiro+altu實現,參考方案mkk/oauth2-shiro - 碼雲 - 開源中國 。

oauth2的基本概念

在oauth中至少是有使用者,應用伺服器,認證伺服器這幾個角色在互動。oauth的作用就是讓"客戶端"安全可控地獲取"使用者"的授權,與"應用伺服器"進行互動。

使用者通過瀏覽器訪問乙個應用,比如我要上慕課網學習。

**要求我登入,我選擇使用qq登入,這裡的qq登入就是那個認證伺服器。

這個時候慕課提供的qq登入鏈結會把我帶到qq登入頁面

在qq的登入頁面完成登入後,選擇授權,也就是允許慕課網獲取我的資料。

這個時候我們看到瀏覽器經過幾次跳轉後返回慕課網,這個時候我們已經完成了登入。

重點在於幾次跳轉的過程中,慕課網和qq登入的服務之間還有過幾次互動。

我們選擇了授權的時候qq登入伺服器會根據慕課跳轉到qq時候給出的重定向鏈結返回給慕課網乙個code,這個code代表qq的登入伺服器認可慕課網這個應用伺服器的這個請求是合法的予以放行.

慕課這個時候就會用這個code再次向qq登入服務發起請求服務令牌(token)。

拿到這個令牌之後,接下來慕課需要使用者的一些基本資訊時就可以通過在向qq服務提交的請求頭里帶上這個令牌,令牌驗證通過就可以拿到使用者資源。

這一部分的操作是應用伺服器和驗證伺服器之間的互動,這個過程對使用者是透明的。這個過程中慕課網是不需要知道使用者的賬號密碼也可以完成對使用者身份的認證,這個token就可以用來標識使用者資源。

官方的執行流程圖是這樣的:

上述講的是oauth2中支援的授權碼(code)方式的認證流程,也是其支援的四種認證方式裡最複雜的,其他的三種種包括:

簡化模式(implicit),(在redirect_uri 的hash傳遞token; auth客戶端執行在瀏覽器中,如js,flash)

密碼模式(resource owner password credentials),將使用者名稱,密碼傳過去,直接獲取token;

客戶端模式(client credentials),無使用者,使用者向客戶端註冊,然後客戶端以自己的名義向'服務端'獲取資源;

詳細的oauth2資料參考理解oauth 2.0|阮一峰的網路日誌

分別適用不同場景,複雜度也比授權碼模式要低,所以這裡就只說說授權碼模式的具體過程。

code方式認證例項

假設現在有乙個應用伺服器跑在我本機8000埠,認證伺服器在8090埠。在需要使用者登入時候把使用者帶到以下的乙個url.

http://localhost:8090/oauth/authorize?response_type=code&scope=read write&client_id=test&redirect_uri=http://localhost:8000/login&state=09876999
我們注意到幾個重要的引數:

下面是驗證伺服器接受這個請求的控制器關鍵**:

首先拿到這個請求以後根據請求的引數將其封裝成乙個oauthauthxrequest,基本就是把請求過來的引數,方法繫結便於使用。這是由oltu提供的oauthrequest的進一步封裝。

然後判斷這個請求的授權的型別是否是code,也就是判斷下請求引數的response_type是否為code,可以看到目前製作了兩種型別的授權。

然後根據對應的授權型別,構造對應的方法處理器。下面是handle的實現介面:

public void handle() throws oauthsystemexception, servletexception, ioexception 

//判斷使用者是否登入過,根據session判斷。因此多個應用使用同乙個授權服務的話,是可以直接跳過登入步驟的也就實現了單點登入的效果。如果沒有登入的話,這一步的請求會被重定向至登入頁面。(登入也得隱藏域會帶上這些引數)

if (gologin())

//這個請求如果是從登入頁面提交過來的,那麼就提交使用者的登入,這個框架中交給shiro去做登入相關的操作。

if (submitlogin())

return;

}//與登入類似,也是提交使用者批准或拒絕了許可權請求

return;

}//以上任意一步沒有通過都是授權失敗會進行相應處理,如果都通過了就發放code碼。

handleresponse();

}

http://localhost:8000/login?code=bca654ab6133ab3cbc55bb751da93b1c&state=09876999
可以看到帶回了返回的引數,以及原樣返回的狀態碼。

應用伺服器這時候拿到返回的code去換token,發起如下的乙個請求:

localhost:8090/oauth/token?client_id=test&client_secret=test&grant_type=authorization_code&code=bca654ab6133ab3cbc55bb751da93b1c&redirect_uri=http://localhost:8000/login&scope=read%20write&state=09876999
與之前請求類似只是多了乙個code欄位,去驗證客戶端的合法性。

驗證伺服器會在收到code以後去查詢是否有支援這種code的處理器,如果有則發放token。

for (oauthtokenhandler handler : handlers) ' handle oauthtokenxrequest: {}", handler, tokenrequest);

handler.handle(tokenrequest, response);

return;

}}

初始化支援的handler

private void initialhandlers()
驗證通過後應用伺服器會接受到包含token的乙個json資料:

這個token是有一定的有效期的,在服務端會快取這個token以便下一次查詢,應用客戶端也應該保留這個token,訪問受限資源時候需要帶上這個token去驗證身份。

比如請求乙個api如下:

curl -i -x get \

-h "authorization:bearer 33dbfc80f5659c6fdec73a044ff724c3" \

'http://localhost:8090/api/test'

資源伺服器上使用shiro做安全驗證,配置oauth2對應的realms即可:

在這個reamls中根據token去查到使用者資訊,再去分發對應的資源。

自此便完成了整個oauth2的流程。

這個流程中認證服務系統需要配置三張資料表:

專案是基於shiro+altu實現,參考方案mkk/oauth2-shiro - 碼雲 - 開源中國 ,更詳細的內容,可以去讀讀shengzhao li開源的**

總結

本文簡單介紹了幾種統一認證的解決方案,然後詳細介紹了oauth2的認證流程,並結合例項詳細介紹了code授權的流程。儘管oauth2被廣泛用於多平台登入解決方案,我覺得在設定cookie、session共享之後也可以被應用於單點登入的解決方案。

在使用oauth2做前後端分離時遇到的兩個跨域問題的解決方案可以參考我的兩篇部落格

OAuth2的一些改變

以前最煩的就是 xx和我說你咋不支援 oauth 啊?那是標準啊,多通用啊?同學,標準是啥?中國還有個饅頭標準,直徑大於多少還不算是饅頭呢!其實早在我做開放平台時,oauth 的確實有了,但是當時也就是個草案,不過也是一群大牛公司的人在那兒搗鼓,但是當時沒有乙個真正的開放平台大牛公司的人在做這個 我...

OAuth2的一些改變

以前最煩的就是xx和我說你咋不支援oauth啊?那是標準啊,多通用啊?同學,標準是啥?中國還有個饅頭標準,直徑大於多少還不算是饅頭呢!其實早在我做開放平台時,oauth的確實有了,但是當時也就是個草案,不過也是一群大牛公司的人在那兒搗鼓,但是當時沒有乙個真正的開放平台大牛公司的人在做這個 我認為雅虎...

前後端分離基於Oauth2的SSO單點登入怎樣做?

單點登入顧名思義就是在多個應用系統中,只需要登入一次,就可以訪問其他相互信任的應用系統,免除多次登入的煩惱 本文主要介紹跨域間的前後端分離專案怎樣實現單點登入,並且與非前後端分離的差異在那裡?需要解決什麼問題?前後端分離的核心概念是後端僅返回前端所需的資料,不再渲染html頁面,前端html頁面通過...