當用戶第一次訪問應用系統1的時候,由於尚未登陸,會被引導到認證系統中進行登陸;根據用戶提供的登陸信息,認證系統進行身份校驗,若是經過校驗,應該返回給用戶一個認證的憑據--ticket;用戶再訪問別的應用的時候就會將這個ticket帶上,做爲本身認證的憑據,應用系統接受到請求以後會把ticket送到認證系統進行校驗,檢查ticket的合法性。若是經過校驗,用戶就能夠在不用再次登陸的狀況下訪問應用系統2和應用系統3了。前端
- 方便用戶 用戶使用應用系統時,可以一次登陸,屢次使用。用戶再也不須要每次輸入用戶名稱和用戶密碼,也不須要牢記多套用戶名稱和用戶密碼。單點登陸平臺可以改善用戶使用應用系統的體驗。
- 方便管理員 系統管理員只須要維護一套統一的用戶帳號,方便、簡單。相比之下,系統管理員之前須要管理不少套的用戶帳號。每個應用系統就有一套用戶帳號,不只給管理上帶來不方便,並且,也容易出現管理漏洞。
- 簡化應用系統開發 開發新的應用系統時,能夠直接使用單點登陸平臺的用戶認證服務,簡化開發流程。單點登陸平臺經過提供統一的認證平臺,實現單點登陸。所以,應用系統並不須要開發用戶認證程序。
若是咱們的站點有不止一個業務,那麼他們可能部署在不一樣的機器上,也每每須要不一樣的域名進行區分。可是全部的業務又都是依賴於一套帳戶體系,那麼咱們這時候須要經過一次登陸解決全部站點的登陸問題,那麼咱們這個時候可使用一個最笨的方法:那就是一次登陸成功,將Cookie寫到根域下,那麼這樣全部的站點就能實現,同一個根域下的Cookie共享,天然實現了「單點登陸」。java
若是是多個根域名,那麼這種狀況下上面的機制就不能實現「單點登陸」了。由於之因此上面能夠實現「單點登陸」的效果。是由於瀏覽器和Http協議的支持。可是對於跨根域的站點之間進行Cookie的共享是比較複雜的。git
- 方法1:登陸成功以後將Cookie回寫到多個域名下。
這種辦法可能十分簡單,你能夠經過後端的response寫,也能夠用前端js去寫,可是必須有對全部須要「單點登陸」的站點進行逐一的寫入。用腳想這種辦法也是行不通的,由於你須要維護一個站點的列表,維護工做十分複雜,同時對於增長站點也會特別痛苦。對於Cookie的銷燬也是十分複雜的,由於仍是要對全部域名下的Cookie進行刪除。也就是說將原來須要作的工做增長了n倍。對於小型站點這種辦法是可取的。github
- 方法2:jsonp
搞過前端的可能都知道用jsonp能夠作跨域的請求,而咱們解決的就是多個域下的統一登陸的問題,好像很瓜熟蒂落的樣子。可是,登陸是Server端作的吧?咱們在Client端作跨域的處理,這怎麼看也不是很合理。同時這種辦法須要很大的維護成本,每一次請求都要去固定的域下取相應的Cookie以後再作請求。想一想維護有頭疼。web
- 方法3 :引入一箇中間態的Server
這種辦法算是一個簡化版的SSO,實現思想也十分的「狡猾」。可是對於小網站作跨域登陸的處理卻十分的有用,具體思路以下:spring
首先,咱們有兩個域名要實現單點登陸,同時咱們須要一箇中間的Server。json
咱們有一個系統域名爲xulingbo.net,當咱們登陸的時候訪問xulingbo.net/wp-login進行登陸,登陸成功以後將Cookie回寫到xulingbo這個域名下。後端
咱們還有一個系統域名爲javaWeb.com,當咱們訪問inside-javaWeb的時候,咱們沒有Cookie,那麼請求跳轉到中間系統jump。此時須要將當前域名帶到參數中便於jump校驗。這個jump系統是在xulingbo域下的即:jump.xulingbo.net。這時候就能拿到以前寫在xulingbo域下的Cookie。跨域
jump系統在收到了xulingbo域下的Cookie以後,取出xulingbo域下的Cookie,並redirect請求jump.inside-javaWeb.net,這個接口也是在jump系統中,請求後jump系統將Cookie回寫到inside-javaWeb域名下,這樣就實現了簡易的單點登陸。 以下圖所示:瀏覽器
可是這種方式不是很靈活,對於數據傳輸的安全性沒有保障,而且在銷燬Cookie的時候無能爲力,只能所有遍歷的銷燬。
- 方法4:基於CAS的SSO系統
CAS全稱爲:Central Authentication Service,是一款不錯的針對web應用的單點登陸框架,包括java,.net,PHP,Prel,Apache,uPortal,Ruby等。。實現的機制不算複雜可是思想十分靈巧。用CAS也能夠快速實現單點登陸。盜圖一張說明sso單個域的登陸和驗證流程:
CAS主要分爲CAS Client 和CAS Server ,其中Client主要是內嵌在須要SSO登陸站點的攔截器或過濾器上。
這樣就能保證當前瀏覽器在站點1的域名下,有站點1的Cookie,同時當前瀏覽器也有CAS Server的Cookie。 接下來看下站點2的登陸:
站點2,在進行登陸時和站點1初次登陸流程一致,可是在訪問CAS Server的時候,因爲當前瀏覽器已經有了CAS Server的Cookie,那麼直接校驗經過返回ticket。 ticket經過302跳轉跳轉到CAS Client上,以後的流程就和站點1是同樣的了。若是此時認證失敗,那麼須要從新走一次登陸的過程。注意的問題: 一、CAS Server的Cookie劫持問題,若是CAS Server的Cookie被劫持掉,那麼就至關於拿到了一切,因此必需要用HTTPS實現這個過程。 二、ticket的使用,ticket只能被使用一次,一次校驗後當即失效。同時須要有時效性,通常5分鐘。最後ticket生成規則要隨機,不能被碰撞出來。 三、對於各自系統本身的Session,也能夠依賴於SSO,這樣就能保證全部的Session規則一致,便於集中控制。
注:運營系統也是採用這種方式處理的 基於當前現狀,單點登陸系統能夠有一下處理
- 調用Soa服務實現登陸登出 缺點:得本身實現判斷用戶是否登陸、session是否過時;缺少權限控制,得本身實現 優勢:實現簡單
- 本身在web服務實現登陸登陸功能 安全性偏低
- 使用Spring Security + Oauth2實現登陸登陸功能 優勢:企業級,安全性高 提供了多種安全驗證方式 能夠處理複雜的權限控制
- Spring Security是什麼?
Spring security 是一個強大的和高度可定製的身份驗證和訪問控制框架,它提供了基於javaEE的企業應有個你軟件全面的安全服務。它是保護基於Spring的應用程序的事實上的標準。主要做用是「認證」和「受權」(或者訪問控制)。 在身份驗證層,Spring Security 的支持多種認證模式。
- 核心功能 一、認證(你是誰) 二、受權(你能幹什麼) 三、攻擊防禦(防止僞造身份)
- 什麼是Spring Security驗證?
- 名詞定義
- OAuth的思路
OAuth在"客戶端"與"服務提供商"之間,設置了一個受權層(authorization layer)。"客戶端"不能直接登陸"服務提供商",只能登陸受權層,以此將用戶與客戶端區分開來。"客戶端"登陸受權層所用的令牌(token),與用戶的密碼不一樣。用戶能夠在登陸的時候,指定受權層令牌的權限範圍和有效期。 "客戶端"登陸受權層之後,"服務提供商"根據令牌的權限範圍和有效期,向"客戶端"開放用戶儲存的資料。
- 運行流程
(A)用戶打開客戶端之後,客戶端要求用戶給予受權。 (B)用戶贊成給予客戶端受權。 (C)客戶端使用上一步得到的受權,向認證服務器申請令牌。 (D)認證服務器對客戶端進行認證之後,確認無誤,贊成發放令牌。 (E)客戶端使用令牌,向資源服務器申請獲取資源。 (F)資源服務器確認令牌無誤,贊成向客戶端開放資源。 不難看出來,上面六個步驟之中,B是關鍵,即用戶怎樣才能給於客戶端受權。有了這個受權之後,客戶端就能夠獲取令牌,進而憑令牌獲取資源。
結合上圖,使用oauth2保護你的應用,能夠分爲簡易的分爲三個步驟
全部獲取令牌的請求都將會在Spring MVC controller endpoints中進行處理,而且訪問受保護 的資源服務的處理流程將會放在標準的Spring Security請求過濾器中(filters)。 下面是配置一個受權服務必需要實現的endpoints: -AuthorizationEndpoint:用來做爲請求者得到受權的服務,默認的URL是/oauth/authorize. -TokenEndpoint:用來做爲請求者得到令牌(Token)的服務,默認的URL是/oauth/token.
- 客戶端的受權模式
客戶端必須獲得用戶的受權(authorization grant),才能得到令牌(access token)。OAuth 2.0定義了四種受權方式。
- 受權碼模式
受權碼模式(authorization code)是功能最完整、流程最嚴密的受權模式。它的特色就是經過客戶端的後臺服務器,與"服務提供商"的認證服務器進行互動。
它的步驟以下:
(A)用戶訪問客戶端,後者將前者導向認證服務器。
(B)用戶選擇是否給予客戶端受權。
(C)假設用戶給予受權,認證服務器將用戶導向客戶端事先指定的"重定向URI"(redirection URI),同時附上一個受權碼。
(D)客戶端收到受權碼,附上早先的"重定向URI",向認證服務器申請令牌。這一步是在客戶端的後臺的服務器上完成的,對用戶不可見。
(E)認證服務器覈對了受權碼和重定向URI,確認無誤後,向客戶端發送訪問令牌(access token)和更新令牌(refresh token)。
下面是上面這些步驟所須要的參數。 A步驟中,客戶端申請認證的URI,包含如下參數:
demo:
GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com
複製代碼
C步驟中,服務器迴應客戶端的URI,包含如下參數: --code:表示受權碼,必選項。該碼的有效期應該很短,一般設爲10分鐘,客戶端只能使用該碼一次,不然會被受權服務器拒絕。該碼與客戶端ID和重定向URI,是一一對應關係。 --state:若是客戶端的請求中包含這個參數,認證服務器的迴應也必須如出一轍包含這個參數。
HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA
&state=xyz
複製代碼
D步驟中,客戶端向認證服務器申請令牌的HTTP請求,包含如下參數:
E步驟中,認證服務器發送的HTTP回覆,包含如下參數:
常見的第三方登陸也是採用這種方法,先請求獲得code,而後再經過code去獲取令牌。
- 簡化模式 簡化模式(implicit grant type)不經過第三方應用程序的服務器,直接在瀏覽器中向認證服務器申請令牌,跳過了"受權碼"這個步驟,所以得名。全部步驟在瀏覽器中完成,令牌對訪問者是可見的,且客戶端不須要認證。
它的步驟以下: (A)客戶端將用戶導向認證服務器。
(B)用戶決定是否給於客戶端受權。
(C)假設用戶給予受權,認證服務器將用戶導向客戶端指定的"重定向URI",並在URI的Hash部分包含了訪問令牌。
(D)瀏覽器向資源服務器發出請求,其中不包括上一步收到的Hash值。
(E)資源服務器返回一個網頁,其中包含的代碼能夠獲取Hash值中的令牌。
(F)瀏覽器執行上一步得到的腳本,提取出令牌。
(G)瀏覽器將令牌發給客戶端。
下面是上面這些步驟所須要的參數。
A步驟中,客戶端發出的HTTP請求,包含如下參數:
下面是一個例子:
GET /authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com
複製代碼
C步驟中,認證服務器迴應客戶端的URI,包含如下參數:
下面是一個例子:
HTTP/1.1 302 Found
Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA
&state=xyz&token_type=example&expires_in=3600
複製代碼
- 密碼模式
密碼模式(Resource Owner Password Credentials Grant)中,用戶向客戶端提供本身的用戶名和密碼。客戶端使用這些信息,向"服務商提供商"索要受權。 在這種模式中,用戶必須把本身的密碼給客戶端,可是客戶端不得儲存密碼。這一般用在用戶對客戶端高度信任的狀況下,好比客戶端是操做系統的一部分,或者由一個著名公司出品。而認證服務器只有在其餘受權模式沒法執行的狀況下,才能考慮使用這種模式。
它的步驟以下:
(A)用戶向客戶端提供用戶名和密碼。
(B)客戶端將用戶名和密碼發給認證服務器,向後者請求令牌。
(C)認證服務器確認無誤後,向客戶端提供訪問令牌。
B步驟中,客戶端發出的HTTP請求,包含如下參數:
-grant_type:表示受權類型,此處的值固定爲"password",必選項。
-username:表示用戶名,必選項。
-password:表示用戶的密碼,必選項。
-scope:表示權限範圍,可選項。
下面是一個例子:
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=johndoe&password=A3ddj3w
複製代碼
C步驟中,認證服務器向客戶端發送訪問令牌,下面是一個例子。
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}
複製代碼
其它的認證介紹參考下面參考地址。
- 客戶端模式 客戶端模式(Client Credentials Grant)指客戶端以本身的名義,而不是以用戶的名義,向"服務提供商"進行認證。嚴格地說,客戶端模式並不屬於OAuth框架所要解決的問題。在這種模式中,用戶直接向客戶端註冊,客戶端以本身的名義要求"服務提供商"提供服務,其實不存在受權問題。
它的步驟以下:
(A)客戶端向認證服務器進行身份認證,並要求一個訪問令牌。
(B)認證服務器確認無誤後,向客戶端提供訪問令牌。
A步驟中,客戶端發出的HTTP請求,包含如下參數:
-granttype:表示受權類型,此處的值固定爲"clientcredentials",必選項。
-scope:表示權限範圍,可選項。
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
複製代碼
認證服務器必須以某種方式,驗證客戶端身份。 B步驟中,認證服務器向客戶端發送訪問令牌,下面是一個例子。
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"example_parameter":"example_value"
}
複製代碼
附上我本身寫的一個spring-security+oauth2項目,可參考使用,反正我本身的項目用上這個了。github.com/jiezaizone/…
另外一種單點登陸方式:Keycloak單點登陸
持續輸出原創文章,這是是劉榮傑的第1篇原創文章