javascript
Spring Boot + OAuth2 统一认证SSO单点登录
需求:將項(xiàng)目從springSecurity驗(yàn)證登錄改為統(tǒng)一認(rèn)證sso登錄,將原數(shù)據(jù)庫中用戶賬號(hào)、密碼、郵箱信息遷移至統(tǒng)一認(rèn)證端數(shù)據(jù)中,保留原客戶端項(xiàng)目的使用SpringSecurity進(jìn)行權(quán)限角色管理部分
最終選擇spring boot +oauth2 ,用到 @EnableOAuth2Sso注解實(shí)現(xiàn)單點(diǎn)登錄,主要參考:
??Spring Boot+OAuth2,一個(gè)注解搞定單點(diǎn)登錄! - 江南一點(diǎn)雨 (javaboy.org)
本文記錄踩坑與學(xué)習(xí)與實(shí)戰(zhàn)記錄(未更完)
目錄
基礎(chǔ)知識(shí)學(xué)習(xí)
cas和sso(了解):
cas
通過cas實(shí)現(xiàn)單點(diǎn)登錄?
Spring Security
身份認(rèn)證流程解析
自定義用戶密碼驗(yàn)證
Sprint Security 用戶權(quán)限管理
做到一個(gè)用戶只能登錄一次
徹底理解 Cookie、Session、Token
Spring Security基于oauth2的sso單點(diǎn)登錄(最后使用的方式)
?開源框架XXL-SSO
實(shí)戰(zhàn)江南一點(diǎn)雨:
遇到的問題:
用戶權(quán)限管理時(shí)
auth端無法跳轉(zhuǎn)index
一.基礎(chǔ)知識(shí)學(xué)習(xí)
1.1 cas和sso(了解):
【單點(diǎn)登錄】什么是 SSO 與 CAS?_happydecai的博客-CSDN博客_cas和sso
sso是一種框架,cas是實(shí)現(xiàn)sso的一種方法,當(dāng)然,還有其他的方法,例如cookie
1.1.1 cas
從結(jié)構(gòu)上看,CAS 包含兩個(gè)部分: CAS Server 和 CAS Client。CAS Server 需要獨(dú)立部署,主要負(fù)責(zé)對(duì)用戶的認(rèn)證工作;CAS Client 負(fù)責(zé)處理對(duì)客戶端受保護(hù)資源的訪問請(qǐng)求,需要登錄時(shí),重定向到 CAS Server。下圖是 CAS 最
鏈接:單點(diǎn)登錄之CAS原理和實(shí)現(xiàn)_金玉良緣-CSDN博客_cas單點(diǎn)登錄實(shí)現(xiàn)原理
1.1.2 cas和oauth2 的區(qū)別
CAS的單點(diǎn)登錄和oauth2的最大區(qū)別 - 劍握在手 - 博客園
1.1.3. 通過cas實(shí)現(xiàn)單點(diǎn)登錄?
Spring Security 集成CAS實(shí)現(xiàn)單點(diǎn)登錄 - 阿貍哥哥 - 博客園
1.2 Spring Security
security 有認(rèn)證和授權(quán)兩個(gè)功能 以session作為交互
1.2.1 身份認(rèn)證流程解析
最簡(jiǎn)單易懂的Spring Security 身份認(rèn)證流程講解 - 曾俊杰的專欄 - 博客園 (cnblogs.com)
1.2.2 自定義用戶密碼驗(yàn)證
關(guān)于密碼驗(yàn)證源碼解讀寫于0706 · 語雀 (yuque.com)
重寫密碼驗(yàn)證filter:
SpringSecurity的自定義用戶密碼驗(yàn)證 - 洋洋哥 - 博客園 (cnblogs.com)
1.2.3 Sprint Security 用戶權(quán)限管理
1. 在config配置文件中配置:分為hasAuthority(String)、hasRole(String)、hasIpAddress(String)
(2條消息) Spring Security--角色權(quán)限判斷_我和井蓋都笑了博客-CSDN博客_springsecurity 判斷權(quán)限
protected void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers("/api/**").hasAnyRole("ROLE_USER", "ROLE_ADMIN").antMatchers("/admin/**").hasRole("ROLE_ADMIN")// 如果發(fā)來的請(qǐng)求是指定的 IP 就允許訪問// 可以通過 request.getRemoteAddr()獲取 ip 地址。.antMatchers("/api/**").hasIpAddress("localhost").antMatchers("/api/**").hasAuthority("admin").and().logout().deleteCookies("JSESSIONID", oauthCookieName).invalidateHttpSession(true)// 這樣保證在客戶端logout的時(shí)候就在服務(wù)端logout.logoutSuccessUrl("http://{server.ip}/logout").and().authorizeRequests().anyRequest().authenticated();// 保證只有單方登錄,同時(shí)需要在auth端也配置這條,客戶端/logout了同時(shí)就會(huì)在統(tǒng)一認(rèn)證端也執(zhí)行l(wèi)ogouthttp.sessionManagement().maximumSessions(1).expiredUrl("/logout");}2. 使用注解@PreAuthorize 進(jìn)行管理權(quán)限
@PreAuthorize 注解,顧名思義是進(jìn)入方法前的權(quán)限驗(yàn)證,@PreAuthorize 聲明這個(gè)方法所需要的權(quán)限表達(dá)式,例如:@PreAuthorize("hasAuthority('sys:dept:delete')"),
@PreAuthorize 權(quán)限控制的原理 - 簡(jiǎn)書 (jianshu.com)
3.?自定義注解進(jìn)行權(quán)限管理
(2條消息) Java自定義注解實(shí)現(xiàn)權(quán)限管理_小識(shí)的博客-CSDN博客_注解實(shí)現(xiàn)權(quán)限管理
1.2.4 做到一個(gè)用戶只能登錄一次
1. 最大同時(shí)登錄為1,且配置session過期重定位地址,直接將原來登錄處踢出
當(dāng)spring security檢查到session過期后,若未做任何配置,spring security會(huì)返回一個(gè)用戶不友好的頁面,因此我們通常需要設(shè)置一個(gè)地址,當(dāng)spring security檢查到session過期后,將請(qǐng)求重定位到我們的地址上,設(shè)置代碼如下所示:
參考鏈接:
spring scurity session管理 - SegmentFault 思否
2. 當(dāng)再次登錄時(shí)阻止其認(rèn)證而不是強(qiáng)制踢出上一次登錄:
當(dāng)一個(gè)用戶已經(jīng)認(rèn)證過了,在另外一個(gè)地方重新進(jìn)行登錄認(rèn)證,spring security可以阻止其再次登錄認(rèn)證,從而保持原來的會(huì)話可用性;具體的代碼設(shè)置如下所示
http.sessionManager().maximumSession(1).maxSessionsPreventsLogin(true);參考鏈接:?
spring security 關(guān)于 http.sessionManagement().maximumSessions(1);的探究 - 岑惜 - 博客園 (cnblogs.com)
1.2.5 ?Cookie、Session、Token
1. 三者的關(guān)系
springbsecurity 登錄token驗(yàn)證過濾器_徹底理解 Cookie、Session、Token_weixin_39693662的博客-CSDN博客
2. springsecurity session詳解:
參考:
Spring Security 控制Session詳解 - 簡(jiǎn)書 (jianshu.com)
3. springSecurity 修改session中的信息
遇到場(chǎng)景 : 前端通過session獲取當(dāng)前用戶信息,當(dāng)前用戶信息在前端頁面發(fā)生了改變時(shí)(比如用戶update了自己的email屬性);可能數(shù)據(jù)庫里面已經(jīng)update了,而程序沒有重啟或者用戶沒有重新登陸,則session中的值是不會(huì)發(fā)生改變的,即驗(yàn)證的用戶信息也是不變的,前端顯示也并不會(huì)更新
SpringSecurity-日常踩坑,修改session中的用戶信息。 - EalenXie - 博客園 (cnblogs.com)
4. 根據(jù)session獲取用戶名
SpringSecurity-日常踩坑,修改session中的用戶信息。 - EalenXie - 博客園 (cnblogs.com)
1.3 Spring Security基于oauth2的sso單點(diǎn)登錄(最后使用的方式)
1. oauth2 主要目的是為了第三方登錄(例如微信授權(quán)), 提供以token作為訪問權(quán)限
參考:Spring Security基于Oauth2的SSO單點(diǎn)登錄怎樣做? - 程序員大本營
2. 當(dāng)客戶端用security時(shí):(2條消息) 基于Spring Security + OAuth2 的SSO單點(diǎn)登錄(客戶端)_Janche的博客-CSDN博客_oauth2 客戶端登錄
3.? @EnableOAuth2Sso注解實(shí)現(xiàn)單點(diǎn)登錄(在客戶端使用,客戶端用的是security驗(yàn)證登錄)
(最終參考的方案)?
?Spring Boot+OAuth2,一個(gè)注解搞定單點(diǎn)登錄! - 江南一點(diǎn)雨 (javaboy.org)
auth端連接數(shù)據(jù)庫驗(yàn)證用戶賬號(hào)和密碼需要配置datasource config需要配置
客戶端有單獨(dú)的權(quán)限管理,在security中配置,詳見"Sprint Security 用戶權(quán)限管理"
4. 注冊(cè)
spring-security-oauth2(二十二) 重構(gòu)注冊(cè)邏輯_codeing-tiger-CSDN博客_oauth2 注冊(cè)
1.4 開源框架XXL-SSO
分布式單點(diǎn)登錄框架XXL-SSO - 許雪里 - 博客園
實(shí)現(xiàn)時(shí)遇到的問題:
做了很多嘗試把xxl-sso框架和springSecurity框架集成,但客戶端無法獲取用戶信息,無法實(shí)現(xiàn)原因:統(tǒng)一驗(yàn)證那邊驗(yàn)證登錄成功了,兩邊的session統(tǒng)一,但是客戶端項(xiàng)目的security驗(yàn)證沒有通過,而我們需要它的username password攔截器驗(yàn)證通過,才能獲得我們所需要的principal
二. 實(shí)戰(zhàn):
參考項(xiàng)目地址:
https://github.com/lenve/oauth2-samples
clone項(xiàng)目后分別打開oauth2-sso/auth-server(認(rèn)證端)、oauth2-sso/client1(客戶端1)、oauth2-sso/client2(客戶端2),開啟后可以實(shí)現(xiàn)統(tǒng)一認(rèn)證登錄
接下來進(jìn)行一些拓展:
2.1 客戶端登錄成功后跳轉(zhuǎn)index頁面
傳送門:
SpringBoot 登陸后跳轉(zhuǎn)到index頁面_aqing617的博客-CSDN博客
2.2 客戶端登出
客戶端的登出添加配置
http.logout() // .logoutUrl("/logout") // .deleteCookies("s1","JSESSIONID")// 在登出后,是否要清空當(dāng)前session // .invalidateHttpSession(true)// 服務(wù)端登出.logoutSuccessUrl("http://localhost:1111/logout");認(rèn)證端添加的配置:
http.logout();2.3 一個(gè)用戶只允許登錄一次?
需求:每個(gè)用戶在瀏覽器a登錄后,在瀏覽器b再次登錄,此時(shí)要求瀏覽器a 該用戶被踢出
在認(rèn)證端和客戶端都添加配置
http.sessionManagement().maximumSessions(1).expiredUrl("/logout");2.4 認(rèn)證端連接數(shù)據(jù)庫驗(yàn)證用戶信息
原項(xiàng)目中,用戶信息是存在與程序內(nèi)存中的,現(xiàn)添加配置,使得用戶信息存儲(chǔ)于數(shù)據(jù)庫中
1. securityConfig中替換
@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.authenticationProvider(userAuthenticationProvider).userDetailsService(userService).passwordEncoder(passwordEncoder);}2. 添加datasourceConfig,連接數(shù)據(jù)庫????????
通過添加import com.mysql.jdbc.Driver;自動(dòng)在pom文件中添加依賴
搭建單點(diǎn)登錄服務(wù)器,新建數(shù)據(jù)庫用戶表用于用戶驗(yàn)證
3. 注入bean
4. 定義user類,實(shí)現(xiàn)UserDetails接口
5.定義UseDAO
6. 定義UserService實(shí)現(xiàn)UserDetailService接口
7.添加認(rèn)證處理類,即1.中所用的
8. application.properties添加配置,連接數(shù)據(jù)庫
2.5 新增user-center客戶端,用于展示引導(dǎo)鏈接到各個(gè)客戶端
首先在認(rèn)證端新增接口,登錄成功后跳轉(zhuǎn)用戶中心客戶端
@GetMapping("/")public void redirect2UserCenter(HttpServletRequest req, HttpServletResponse resp) throws IOException {resp.sendRedirect("http://localhost:1112");}(未完待續(xù))?
2.6 添加統(tǒng)一認(rèn)證端的注冊(cè)邏輯?
在認(rèn)證端新增注冊(cè)接口,調(diào)用后轉(zhuǎn)發(fā)調(diào)用客戶端接口,在認(rèn)證端數(shù)據(jù)庫和客戶端數(shù)據(jù)庫都添加用戶信息
(未完待續(xù))
2.7 客戶端權(quán)限管理
(未完待續(xù))?
遇到的問題:
(未完待續(xù))
用戶權(quán)限管理時(shí)
嘗試了多種方法解決用戶權(quán)限管理,用security自己的配置(獲取不到aizoo數(shù)據(jù)庫中的權(quán)限信息,只能獲取統(tǒng)一身份認(rèn)證的),@PreAuthorize(同樣的問題),自己寫了攔截器和自定義注解攔截?zé)o果(攔截順序的問題,無法跳轉(zhuǎn)到統(tǒng)一身份認(rèn)證)
auth端無法跳轉(zhuǎn)index,無法直接訪問任何接口
試圖解決統(tǒng)一認(rèn)證服務(wù)器登錄之后無法跳轉(zhuǎn)index的bug,嘗試了后臺(tái)控制跳轉(zhuǎn),報(bào)401錯(cuò)誤(沒有權(quán)限
總結(jié)
以上是生活随笔為你收集整理的Spring Boot + OAuth2 统一认证SSO单点登录的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spring mvc学习(15)Refe
- 下一篇: 第四十八期:你太菜了,竟然不知道Code