日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

什么是单点登录(SSO)

發(fā)布時間:2025/3/21 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 什么是单点登录(SSO) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
來源:Java3y(ID:java3y)

一、什么是單點(diǎn)登錄?

單點(diǎn)登錄的英文名叫做:Single Sign On(簡稱SSO)。

初學(xué)/以前的時候,一般我們就單系統(tǒng),所有的功能都在同一個系統(tǒng)上。

所有的功能都在同一個系統(tǒng)上

后來,我們?yōu)榱?strong>合理利用資源和降低耦合性,于是把單系統(tǒng)拆分成多個子系統(tǒng)。

拆分成多個子系統(tǒng)

比如阿里系的淘寶和天貓,很明顯地我們可以知道這是兩個系統(tǒng),但是你在使用的時候,登錄了天貓,淘寶也會自動登錄。

登錄了天貓,淘寶也登錄了

簡單來說,單點(diǎn)登錄就是在多個系統(tǒng)中,用戶只需一次登錄,各個系統(tǒng)即可感知該用戶已經(jīng)登錄。

二、回顧單系統(tǒng)登錄

在我初學(xué)JavaWeb的時候,登錄和注冊是我做得最多的一個功能了(初學(xué)Servlet的時候做過、學(xué)SpringMVC的時候做過、跟著做項(xiàng)目的時候做過…),反正我也數(shù)不清我做了多少次登錄和注冊的功能了…這里簡單講述一下我們初學(xué)時是怎么做登錄功能的。

眾所周知,HTTP是無狀態(tài)的協(xié)議,這意味著服務(wù)器無法確認(rèn)用戶的信息。于是乎,W3C就提出了:給每一個用戶都發(fā)一個通行證,無論誰訪問的時候都需要攜帶通行證,這樣服務(wù)器就可以從通行證上確認(rèn)用戶的信息。通行證就是Cookie

如果說Cookie是檢查用戶身上的”通行證“來確認(rèn)用戶的身份,那么Session就是通過檢查服務(wù)器上的”客戶明細(xì)表“來確認(rèn)用戶的身份的。Session相當(dāng)于在服務(wù)器中建立了一份“客戶明細(xì)表”

HTTP協(xié)議是無狀態(tài)的,Session不能依據(jù)HTTP連接來判斷是否為同一個用戶。于是乎:服務(wù)器向用戶瀏覽器發(fā)送了一個名為JESSIONID的Cookie,它的值是Session的id值。其實(shí)Session是依據(jù)Cookie來識別是否是同一個用戶

所以,一般我們單系統(tǒng)實(shí)現(xiàn)登錄會這樣做:

  • 登錄:將用戶信息保存在Session對象中

    • 如果在Session對象中能查到,說明已經(jīng)登錄

    • 如果在Session對象中查不到,說明沒登錄(或者已經(jīng)退出了登錄)

  • 注銷(退出登錄):從Session中刪除用戶的信息

  • 記住我(關(guān)閉掉瀏覽器后,重新打開瀏覽器還能保持登錄狀態(tài)):配合Cookie來用

我之前Demo的代碼,可以參考一下:

?/***?用戶登陸*/ @PostMapping(value?=?"/user/session",?produces?=?{"application/json;charset=UTF-8"}) public?Result?login(String?mobileNo,?String?password,?String?inputCaptcha,?HttpSession?session,?HttpServletResponse?response)?{//判斷驗(yàn)證碼是否正確if?(WebUtils.validateCaptcha(inputCaptcha,?"captcha",?session))?{//判斷有沒有該用戶User?user?=?userService.userLogin(mobileNo,?password);if?(user?!=?null)?{/*設(shè)置自動登陸,一個星期.??將token保存在數(shù)據(jù)庫中*/String?loginToken?=?WebUtils.md5(new?Date().toString()?+?session.getId());user.setLoginToken(loginToken);User?user1?=?userService.userUpload(user);session.setAttribute("user",?user1);CookieUtil.addCookie(response,"loginToken",loginToken,604800);return?ResultUtil.success(user1);}?else?{return?ResultUtil.error(ResultEnum.LOGIN_ERROR);}}?else?{return?ResultUtil.error(ResultEnum.CAPTCHA_ERROR);}}/***?用戶退出*/ @DeleteMapping(value?=?"/session",?produces?=?{"application/json;charset=UTF-8"}) public?Result?logout(HttpSession?session,HttpServletRequest?request,HttpServletResponse?response?)?{//刪除session和cookiesession.removeAttribute("user");CookieUtil.clearCookie(request,?response,?"loginToken");return?ResultUtil.success(); } /** *?@author?ozc *?@version?1.0 *?<p> *?攔截器;實(shí)現(xiàn)自動登陸功能 */ public?class?UserInterceptor?implements?HandlerInterceptor?{@Autowired private?UserService?userService;public?boolean?preHandle(HttpServletRequest?request,?HttpServletResponse?response,?Object?o)?throws?Exception?{User?sessionUser?=?(User)?request.getSession().getAttribute("user");//?已經(jīng)登陸了,放行if?(sessionUser?!=?null)?{return?true;}?else?{//得到帶過來cookie是否存在String?loginToken?=?CookieUtil.findCookieByName(request,?"loginToken");if?(StringUtils.isNotBlank(loginToken))?{//到數(shù)據(jù)庫查詢有沒有該CookieUser?user?=?userService.findUserByLoginToken(loginToken);if?(user?!=?null)?{request.getSession().setAttribute("user",?user);return?true;}?else?{//沒有該Cookie與之對應(yīng)的用戶(Cookie不匹配)CookieUtil.clearCookie(request,?response,?"loginToken");return?false;}}?else?{//沒有cookie、也沒有登陸。是index請求獲取用戶信息,可以放行if?(request.getRequestURI().contains("session"))?{return?true;}//沒有cookie憑證response.sendRedirect("/login.html");return?false;}} } }

總結(jié)一下上面代碼的思路:

  • 用戶登錄時,驗(yàn)證用戶的賬戶和密碼

  • 生成一個Token保存在數(shù)據(jù)庫中,將Token寫到Cookie中

  • 將用戶數(shù)據(jù)保存在Session中

  • 請求時都會帶上Cookie,檢查有沒有登錄,如果已經(jīng)登錄則放行

三、多系統(tǒng)登錄的問題與解決

3.1 Session不共享問題

單系統(tǒng)登錄功能主要是用Session保存用戶信息來實(shí)現(xiàn)的,但我們清楚的是:多系統(tǒng)即可能有多個Tomcat,而Session是依賴當(dāng)前系統(tǒng)的Tomcat,所以系統(tǒng)A的Session和系統(tǒng)B的Session是不共享的。

系統(tǒng)A的Session和系統(tǒng)B的Session是不共享的

解決系統(tǒng)之間Session不共享問題有一下幾種方案:

  • Tomcat集群Session全局復(fù)制(集群內(nèi)每個tomcat的session完全同步)【會影響集群的性能呢,不建議】

  • 根據(jù)請求的IP進(jìn)行Hash映射到對應(yīng)的機(jī)器上(這就相當(dāng)于請求的IP一直會訪問同一個服務(wù)器)【如果服務(wù)器宕機(jī)了,會丟失了一大部分Session的數(shù)據(jù),不建議】

  • 把Session數(shù)據(jù)放在Redis中(使用Redis模擬Session)【建議

我們可以將登錄功能單獨(dú)抽取出來,做成一個子系統(tǒng)。

抽取出來成為子系統(tǒng)

SSO(登錄系統(tǒng))的邏輯如下:

//?登錄功能(SSO單獨(dú)的服務(wù)) @Override public?TaotaoResult?login(String?username,?String?password)?throws?Exception?{//根據(jù)用戶名查詢用戶信息TbUserExample?example?=?new?TbUserExample();Criteria?criteria?=?example.createCriteria();criteria.andUsernameEqualTo(username);List<TbUser>?list?=?userMapper.selectByExample(example);if?(null?==?list?||?list.isEmpty())?{return?TaotaoResult.build(400,?"用戶不存在");}//核對密碼TbUser?user?=?list.get(0);if?(!DigestUtils.md5DigestAsHex(password.getBytes()).equals(user.getPassword()))?{return?TaotaoResult.build(400,?"密碼錯誤");}//登錄成功,把用戶信息寫入redis//生成一個用戶tokenString?token?=?UUID.randomUUID().toString();jedisCluster.set(USER_TOKEN_KEY?+?":"?+?token,?JsonUtils.objectToJson(user));//設(shè)置session過期時間jedisCluster.expire(USER_TOKEN_KEY?+?":"?+?token,?SESSION_EXPIRE_TIME);return?TaotaoResult.ok(token); }

其他子系統(tǒng)登錄時,請求SSO(登錄系統(tǒng))進(jìn)行登錄,將返回的token寫到Cookie中,下次訪問時則把Cookie帶上:

public?TaotaoResult?login(String?username,?String?password,?HttpServletRequest?request,?HttpServletResponse?response)?{//請求參數(shù)Map<String,?String>?param?=?new?HashMap<>();param.put("username",?username);param.put("password",?password);//登錄處理String?stringResult?=?HttpClientUtil.doPost(REGISTER_USER_URL?+?USER_LOGIN_URL,?param);TaotaoResult?result?=?TaotaoResult.format(stringResult);//登錄出錯if?(result.getStatus()?!=?200)?{return?result;}//登錄成功后把取token信息,并寫入cookieString?token?=?(String)?result.getData();//寫入cookieCookieUtils.setCookie(request,?response,?"TT_TOKEN",?token);//返回成功return?result;}

總結(jié):

  • SSO系統(tǒng)生成一個token,并將用戶信息存到Redis中,并設(shè)置過期時間

  • 其他系統(tǒng)請求SSO系統(tǒng)進(jìn)行登錄,得到SSO返回的token,寫到Cookie中

  • 每次請求時,Cookie都會帶上,攔截器得到token,判斷是否已經(jīng)登錄

到這里,其實(shí)我們會發(fā)現(xiàn)其實(shí)就兩個變化:

  • 將登陸功能抽取為一個系統(tǒng)(SSO),其他系統(tǒng)請求SSO進(jìn)行登錄

  • 本來將用戶信息存到Session,現(xiàn)在將用戶信息存到Redis

3.2 Cookie跨域的問題

上面我們解決了Session不能共享的問題,但其實(shí)還有另一個問題。Cookie是不能跨域的

比如說,我們請求<https://www.google.com/>時,瀏覽器會自動把google.com的Cookie帶過去給google的服務(wù)器,而不會把<https://www.baidu.com/>的Cookie帶過去給google的服務(wù)器。

這就意味著,由于域名不同,用戶向系統(tǒng)A登錄后,系統(tǒng)A返回給瀏覽器的Cookie,用戶再請求系統(tǒng)B的時候不會將系統(tǒng)A的Cookie帶過去。

針對Cookie存在跨域問題,有幾種解決方案:

  • 服務(wù)端將Cookie寫到客戶端后,客戶端對Cookie進(jìn)行解析,將Token解析出來,此后請求都把這個Token帶上就行了

  • 多個域名共享Cookie,在寫到客戶端的時候設(shè)置Cookie的domain。

  • 將Token保存在SessionStroage中(不依賴Cookie就沒有跨域的問題了)

  • 到這里,我們已經(jīng)可以實(shí)現(xiàn)單點(diǎn)登錄了。

    3.3 CAS原理

    說到單點(diǎn)登錄,就肯定會見到這個名詞:CAS (Central Authentication Service),下面說說CAS是怎么搞的。

    如果已經(jīng)將登錄單獨(dú)抽取成系統(tǒng)出來,我們還能這樣玩。現(xiàn)在我們有兩個系統(tǒng),分別是www.java3y.com和www.java4y.com,一個SSOwww.sso.com

    現(xiàn)在我們有三個系統(tǒng)

    首先,用戶想要訪問系統(tǒng)Awww.java3y.com受限的資源(比如說購物車功能,購物車功能需要登錄后才能訪問),系統(tǒng)Awww.java3y.com發(fā)現(xiàn)用戶并沒有登錄,于是重定向到sso認(rèn)證中心,并將自己的地址作為參數(shù)。請求的地址如下:

    • www.sso.com?service=www.java3y.com

    sso認(rèn)證中心發(fā)現(xiàn)用戶未登錄,將用戶引導(dǎo)至登錄頁面,用戶進(jìn)行輸入用戶名和密碼進(jìn)行登錄,用戶與認(rèn)證中心建立全局會話(生成一份Token,寫到Cookie中,保存在瀏覽器上)

    4步過程

    隨后,認(rèn)證中心重定向回系統(tǒng)A,并把Token攜帶過去給系統(tǒng)A,重定向的地址如下:

    • www.java3y.com?token=xxxxxxx

    接著,系統(tǒng)A去sso認(rèn)證中心驗(yàn)證這個Token是否正確,如果正確,則系統(tǒng)A和用戶建立局部會話(創(chuàng)建Session)。到此,系統(tǒng)A和用戶已經(jīng)是登錄狀態(tài)了。

    第五步和第六步

    此時,用戶想要訪問系統(tǒng)Bwww.java4y.com受限的資源(比如說訂單功能,訂單功能需要登錄后才能訪問),系統(tǒng)Bwww.java4y.com發(fā)現(xiàn)用戶并沒有登錄,于是重定向到sso認(rèn)證中心,并將自己的地址作為參數(shù)。請求的地址如下:

    • www.sso.com?service=www.java4y.com

    注意,因?yàn)橹坝脩襞c認(rèn)證中心www.sso.com已經(jīng)建立了全局會話(當(dāng)時已經(jīng)把Cookie保存到瀏覽器上了),所以這次系統(tǒng)B重定向到認(rèn)證中心www.sso.com是可以帶上Cookie的。

    認(rèn)證中心根據(jù)帶過來的Cookie發(fā)現(xiàn)已經(jīng)與用戶建立了全局會話了,認(rèn)證中心重定向回系統(tǒng)B,并把Token攜帶過去給系統(tǒng)B,重定向的地址如下:

    • www.java4y.com?token=xxxxxxx

    接著,系統(tǒng)B去sso認(rèn)證中心驗(yàn)證這個Token是否正確,如果正確,則系統(tǒng)B和用戶建立局部會話(創(chuàng)建Session)。到此,系統(tǒng)B和用戶已經(jīng)是登錄狀態(tài)了。

    系統(tǒng)B的流程圖

    看到這里,其實(shí)SSO認(rèn)證中心就類似一個中轉(zhuǎn)站

    參考資料:

    • https://www.cnblogs.com/EzrealLiu/p/5559255.html

    • http://www.cnblogs.com/ywlaker/p/6113927.html

    • https://blog.csdn.net/javaloveiphone/article/details/52439613

    總結(jié)

    以上是生活随笔為你收集整理的什么是单点登录(SSO)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。