日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

写了一个 SSO 单点登录的代码示例给胖友!

發布時間:2025/3/21 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 写了一个 SSO 单点登录的代码示例给胖友! 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

發危~

摘要: 原創出處 http://www.iocoder.cn/Spring-Security/OAuth2-learning-sso/ 「芋道源碼」歡迎轉載,保留摘要,謝謝!

  • 1. 概述

  • 2. 搭建統一登錄系統

  • 3. 搭建 XXX 系統

  • 666. 彩蛋


本文在提供完整代碼示例,可見 https://github.com/YunaiV/SpringBoot-Labs 的 lab-68-spring-security-oauth 目錄。

原創不易,給點個 Star 嘿,一起沖鴨!

1. 概述

在前面的文章中,我們學習了 Spring Security OAuth 的簡單使用。

  • 《芋道 Spring Security OAuth2 入門》

  • 《芋道 Spring Security OAuth2 存儲器》

今天我們來搞波“大”的,通過 Spring Security OAuth 實現一個單點登錄的功能。

可能會有粉絲不太了解單點登錄是什么?單點登錄,英文是?Single Sign On,簡稱為?SSO,指的是當有多個系統需要登錄時,用戶只需要登錄一個統一的登錄系統,而無需在多個系統重復登錄。

舉個最常見的例子,我們在瀏覽器中使用阿里“全家桶”:

求助信:麻煩有認識阿里的胖友,讓他們給打下錢。。。

  • 淘寶:https://www.taobao.com

  • 天貓:https://www.tmall.com

  • 飛豬:https://www.fliggy.com

  • ...

我們只需要在統一登錄系統(https://login.taobao.com)進行登錄即可,而后就可以“愉快”的自由剁手,并且無需分別在淘寶、天貓、飛豬等等系統重新登錄。

登錄系統

?

友情提示:更多單點登錄的介紹,可見《維基百科 —— 單點登錄》。

下面,我們正式搭建 Spring Security OAuth 實現 SSO 的示例項目,如下圖所示:

項目結構

?

  • 創建?lab-68-demo21-authorization-server-on-sso?項目,作為統一登錄系統

    旁白君:機智的胖友,是不是發現這個項目和授權服務器非常相似!!!

  • 創建?lab-68-demo21-resource-server-on-sso?項目,模擬需要登錄的?XXX 系統

    旁白君:機智的胖友,是不是發現這個項目和資源服務器非常相似!!!

2. 搭建統一登錄系統

示例代碼對應倉庫:

  • 統一登錄系統:lab-68-demo21-authorization-server-on-sso

創建?lab-68-demo21-authorization-server-on-sso?項目,作為統一登錄系統

友情提示:整個實現代碼,和我們前文看到的授權服務器是基本一致的。

2.1 初始化數據庫

在?resources/db?目錄下,有四個 SQL 腳本,分別用于初始化 User 和 OAuth 相關的表。

SQL 腳本

?

2.1.1 初始化 OAuth 表

① 執行?oauth_schema.sql?腳本,創建數據庫表結構

drop?table?if?exists?oauth_client_details; create?table?oauth_client_details?(client_id?VARCHAR(255)?PRIMARY?KEY,resource_ids?VARCHAR(255),client_secret?VARCHAR(255),scope?VARCHAR(255),authorized_grant_types?VARCHAR(255),web_server_redirect_uri?VARCHAR(255),authorities?VARCHAR(255),access_token_validity?INTEGER,refresh_token_validity?INTEGER,additional_information?VARCHAR(4096),autoapprove?VARCHAR(255) );create?table?if?not?exists?oauth_client_token?(token_id?VARCHAR(255),token?LONG?VARBINARY,authentication_id?VARCHAR(255)?PRIMARY?KEY,user_name?VARCHAR(255),client_id?VARCHAR(255) );create?table?if?not?exists?oauth_access_token?(token_id?VARCHAR(255),token?LONG?VARBINARY,authentication_id?VARCHAR(255)?PRIMARY?KEY,user_name?VARCHAR(255),client_id?VARCHAR(255),authentication?LONG?VARBINARY,refresh_token?VARCHAR(255) );create?table?if?not?exists?oauth_refresh_token?(token_id?VARCHAR(255),token?LONG?VARBINARY,authentication?LONG?VARBINARY );create?table?if?not?exists?oauth_code?(code?VARCHAR(255),?authentication?LONG?VARBINARY );create?table?if?not?exists?oauth_approvals?(userId?VARCHAR(255),clientId?VARCHAR(255),scope?VARCHAR(255),status?VARCHAR(10),expiresAt?TIMESTAMP?DEFAULT?CURRENT_TIMESTAMP,lastModifiedAt?TIMESTAMP?DEFAULT?CURRENT_TIMESTAMP );

結果如下圖所示:

表結構

?

表作用
oauth_access_tokenOAuth 2.0?訪問令牌
oauth_refresh_tokenOAuth 2.0?刷新令牌
oauth_codeOAuth 2.0?授權碼
oauth_client_detailsOAuth 2.0?客戶端
oauth_client_token?
oauth_approvals?

旁白君:這里的表結構設計,我們可以借鑒參考,實現自己的 OAuth 2.0 的功能。

② 執行?oauth_data.sql?腳本,插入一個客戶端記錄。

INSERT?INTO?oauth_client_details(client_id,?client_secret,?scope,?authorized_grant_types,web_server_redirect_uri,?authorities,?access_token_validity,refresh_token_validity,?additional_information,?autoapprove) VALUES('clientapp',?'112233',?'read_userinfo,read_contacts','password,authorization_code,refresh_token',?'http://127.0.0.1:9090/login',?null,?3600,?864000,?null,?true); “

注意!這條記錄的?web_server_redirect_uri?字段,我們設置為 http://127.0.0.1:9090/login,這是稍后我們搭建的 XXX 系統的回調地址。

  • 統一登錄系統采用 OAuth 2.0 的授權碼模式進行授權。

  • 授權成功后,瀏覽器會跳轉 http://127.0.0.1:9090/login 回調地址,然后 XXX 系統會通過授權碼向統一登錄系統獲取訪問令牌

通過這樣的方式,完成一次單點登錄的過程。

結果如下圖所示:

oauth_client_details?表記錄

?

2.1.2 初始化 User 表

① 執行?user_schema.sql?腳本,創建數據庫表結構

DROP?TABLE?IF?EXISTS?`authorities`; CREATE?TABLE?`authorities`?(`username`?varchar(50)?NOT?NULL,`authority`?varchar(50)?NOT?NULL,UNIQUE?KEY?`ix_auth_username`?(`username`,`authority`) )?ENGINE=InnoDB?DEFAULT?CHARSET=utf8;DROP?TABLE?IF?EXISTS?`users`; CREATE?TABLE?`users`?(`username`?varchar(50)?NOT?NULL,`password`?varchar(500)?NOT?NULL,`enabled`?tinyint(1)?NOT?NULL,PRIMARY?KEY?(`username`) )?ENGINE=InnoDB?DEFAULT?CHARSET=utf8;

結果如下圖所示:

表結構

?

表作用
users用戶
authorities授權表,例如用戶擁有的角色

② 執行?user_data.sql?腳本,插入一個用戶記錄和一個授權記錄。

INSERT?INTO?`authorities`?VALUES?('yunai',?'ROLE_USER');INSERT?INTO?`users`?VALUES?('yunai',?'112233',?'1');

結果如下圖所示:

users?和?authorities?表記錄

?

2.2 引入依賴

創建?pom.xml?文件,引入 Spring Security OAuth 依賴。

<?xml?version="1.0"?encoding="UTF-8"?> <project?xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0?http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>lab-68</artifactId><groupId>cn.iocoder.springboot.labs</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>lab-68-demo21-authorization-server-on-sso</artifactId><properties><!--?依賴相關配置?--><spring.boot.version>2.2.4.RELEASE</spring.boot.version><!--?插件相關配置?--><maven.compiler.target>1.8</maven.compiler.target><maven.compiler.source>1.8</maven.compiler.source></properties><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>${spring.boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><dependencies><!--?實現對?Spring?MVC?的自動配置?--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--?實現對?Spring?Security?OAuth2?的自動配置?--><dependency><groupId>org.springframework.security.oauth.boot</groupId><artifactId>spring-security-oauth2-autoconfigure</artifactId><version>${spring.boot.version}</version></dependency><!--?實現對數據庫連接池的自動化配置?--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency>?<!--?本示例,我們使用?MySQL?--><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.48</version></dependency></dependencies></project>

2.3 配置文件

創建?application.yaml?配置文件,添加數據庫連接池的配置:

spring:#?datasource?數據源配置內容,對應?DataSourceProperties?配置屬性類datasource:url:?jdbc:mysql://127.0.0.1:43063/demo-68-authorization-server-sso?useSSL=false&useUnicode=true&characterEncoding=UTF-8driver-class-name:?com.mysql.jdbc.Driverusername:?root?#?數據庫賬號password:?123456?#?數據庫密碼

2.4 SecurityConfig

創建 SecurityConfig 配置類,通過?Spring Security?提供用戶認證的功能。代碼如下:

@Configuration @EnableWebSecurity public?class?SecurityConfig?extends?WebSecurityConfigurerAdapter?{/***?數據源?DataSource*/@Autowiredprivate?DataSource?dataSource;@Override@Bean(name?=?BeanIds.AUTHENTICATION_MANAGER)public?AuthenticationManager?authenticationManagerBean()?throws?Exception?{return?super.authenticationManagerBean();}@Beanpublic?static?NoOpPasswordEncoder?passwordEncoder()?{return?(NoOpPasswordEncoder)?NoOpPasswordEncoder.getInstance();}@Overrideprotected?void?configure(AuthenticationManagerBuilder?auth)?throws?Exception?{auth.jdbcAuthentication().dataSource(dataSource);}} “

友情提示:如果胖友想要自定義用戶的讀取,可以參考《芋道 Spring Boot 安全框架 Spring Security 入門》文章。

2.5 OAuth2AuthorizationServerConfig

創建 OAuth2AuthorizationServerConfig 配置類,通過?Spring Security OAuth?提供授權服務器的功能。代碼如下:

@Configuration @EnableAuthorizationServer public?class?OAuth2AuthorizationServerConfig?extends?AuthorizationServerConfigurerAdapter?{/***?用戶認證?Manager*/@Autowiredprivate?AuthenticationManager?authenticationManager;/***?數據源?DataSource*/@Autowiredprivate?DataSource?dataSource;@Beanpublic?TokenStore?jdbcTokenStore()?{return?new?JdbcTokenStore(dataSource);}@Overridepublic?void?configure(AuthorizationServerEndpointsConfigurer?endpoints)?throws?Exception?{endpoints.authenticationManager(authenticationManager).tokenStore(jdbcTokenStore());}@Overridepublic?void?configure(AuthorizationServerSecurityConfigurer?oauthServer)?throws?Exception?{oauthServer.checkTokenAccess("isAuthenticated()");}@Beanpublic?ClientDetailsService?jdbcClientDetailsService()?{return?new?JdbcClientDetailsService(dataSource);}@Overridepublic?void?configure(ClientDetailsServiceConfigurer?clients)?throws?Exception?{clients.withClientDetails(jdbcClientDetailsService());}} “

友情提示:如果胖友看不懂這個配置類,回到《芋道 Spring Security OAuth2 存儲器》文章復習下。

2.6 AuthorizationServerApplication

創建 AuthorizationServerApplication 類,統一登錄系統的啟動類。代碼如下:

@SpringBootApplication public?class?AuthorizationServerApplication?{public?static?void?main(String[]?args)?{SpringApplication.run(AuthorizationServerApplication.class,?args);}}

2.7 簡單測試

執行 AuthorizationServerApplication 啟動統一登錄系統。下面,我們使用 Postman 模擬一個 Client,測試我們是否搭建成功

POST?請求 http://localhost:8080/oauth/token 地址,使用密碼模式進行授權。如下圖所示:

密碼模式

成功獲取到訪問令牌,成功!

3. 搭建 XXX 系統

示例代碼對應倉庫:

  • XXX 系統:lab-68-demo21-resource-server-on-sso

創建?lab-68-demo21-resource-server-on-sso?項目,搭建?XXX 系統,接入統一登錄系統實現 SSO 功能。

友情提示:整個實現代碼,和我們前文看到的資源服務器是基本一致的。

3.1 引入依賴

創建?pom.xml?文件,引入 Spring Security OAuth 依賴。

<?xml?version="1.0"?encoding="UTF-8"?> <project?xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0?http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>lab-68</artifactId><groupId>cn.iocoder.springboot.labs</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>lab-68-demo21-resource-server</artifactId><properties><!--?依賴相關配置?--><spring.boot.version>2.2.4.RELEASE</spring.boot.version><!--?插件相關配置?--><maven.compiler.target>1.8</maven.compiler.target><maven.compiler.source>1.8</maven.compiler.source></properties><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>${spring.boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><dependencies><!--?實現對?Spring?MVC?的自動配置?--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--?實現對?Spring?Security?OAuth2?的自動配置?--><dependency><groupId>org.springframework.security.oauth.boot</groupId><artifactId>spring-security-oauth2-autoconfigure</artifactId><version>${spring.boot.version}</version></dependency></dependencies></project>

3.2 配置文件

創建?application.yaml?配置文件,添加?SSO?相關配置:

server:port:?9090servlet:session:cookie:name:?SSO-SESSIONID?#?自定義 Session 的 Cookie 名字,防止沖突。沖突后,會導致 SSO 登錄失敗。security:oauth2:#?OAuth2?Client?配置,對應?OAuth2ClientProperties?類client:client-id:?clientappclient-secret:?112233user-authorization-uri:?http://127.0.0.1:8080/oauth/authorize?#?獲取用戶的授權碼地址access-token-uri:?http://127.0.0.1:8080/oauth/token?#?獲取訪問令牌的地址#?OAuth2?Resource?配置,對應?ResourceServerProperties?類resource:token-info-uri:?http://127.0.0.1:8080/oauth/check_token?#?校驗訪問令牌是否有效的地址

①?server.servlet.session.cookie.name?配置項,自定義 Session 的 Cookie 名字,防止沖突。沖突后,會導致 SSO 登錄失敗。

友情提示:具體的值,胖友可以根據自己的喜歡設置。

②?security.oauth2.client?配置項,OAuth2 Client 配置,對應 OAuth2ClientProperties 類。在這個配置項中,我們添加了客戶端的?client-id?和?client-secret。

③?security.oauth2.client.user-authorization-uri?配置項,獲取用戶的授權碼地址。

在訪問 XXX 系統需要登錄的地址時,Spring Security OAuth 會自動跳轉到統一登錄系統,進行統一登錄獲取授權

而這里配置的?security.oauth2.client.user-authorization-uri?地址,就是之前授權服務器的?oauth/authorize?接口,可以進行授權碼模式的授權。

友情提示:如果胖友忘記授權服務器的?oauth/authorize?接口,建議回看下《芋道 Spring Security OAuth2 入門》的「3. 授權碼模式」小節。

④?security.oauth2.client.access-token-uri?配置項,獲取訪問令牌的地址。

統一登錄系統完成統一登錄并授權后,瀏覽器會跳轉回 XXX 系統的回調地址。在該地址上,會調用統一登錄系統的?security.oauth2.client.user-authorization-uri?地址,通過授權碼獲取到訪問令牌

而這里配置的?security.oauth2.client.user-authorization-uri?地址,就是之前授權服務器的?oauth/token?接口。

⑤?security.oauth2.resource.client.token-info-uri?配置項,校驗訪問令牌是否有效的地址。

在獲取到訪問令牌之后,每次請求 XXX 系統時,都會調用?統一登錄系統的?security.oauth2.resource.client.token-info-uri?地址,校驗訪問令牌的有效性,同時返回用戶的基本信息

而這里配置的?security.oauth2.resource.client.token-info-uri?地址,就是之前授權服務器的?oauth/check_token?接口。


至此,我們可以發現,Spring Security OAuth 實現的 SSO 單點登錄功能,是基于其授權碼模式實現的。這一點,非常重要,稍后我們演示下會更加容易理解到。

3.3 OAuthSsoConfig

創建 OAuthSsoConfig 類,配置接入 SSO 功能。代碼如下:

@Configuration @EnableOAuth2Sso?//?開啟?Sso?功能 public?class?OAuthSsoConfig?{}

在類上添加?@EnableOAuth2Sso?注解,聲明基于 Spring Security OAuth 的方式接入 SSO 功能。

友情提示:想要深入的胖友,可以看看 SsoSecurityConfigurer 類。

3.4 UserController

創建 UserController 類,提供獲取當前用戶的?/user/info?接口。代碼如下:

@RestController @RequestMapping("/user") public?class?UserController?{@RequestMapping("/info")public?Authentication?info(Authentication?authentication)?{return?authentication;}}

3.5 ResourceServerApplication

創建 ResourceServerApplication 類,XXX 系統的啟動類。代碼如下:

@SpringBootApplication public?class?ResourceServerApplication?{public?static?void?main(String[]?args)?{SpringApplication.run(ResourceServerApplication.class,?args);}}

3.6 簡單測試(第一彈)

執行 ResourceServerApplication 啟動 XXX 系統。下面,我們來演示下 SSO 單點登錄的過程。

① 使用瀏覽器,訪問?XXX 系統的 http://127.0.0.1:9090/user/info 地址。因為暫未登錄,所以被重定向到統一登錄系統的 http://127.0.0.1:8080/oauth/authorize?授權地址。

又因為在統一登錄系統暫未登錄,所以被重定向到統一登錄系統的 http://127.0.0.1:8080/login?登錄地址。如下圖所示:

登錄界面

② 輸入用戶的賬號密碼「yunai/1024」,進行統一登錄系統的登錄。登錄完成后,進入統一登錄系統的 http://127.0.0.1:8080/oauth/authorize?授權地址。如下圖所示:

授權界面

③ 點擊「Authorize」按鈕,完成用戶的授權。授權完成后,瀏覽器重定向到?XXX 系統的 http://127.0.0.1:9090/login?回調地址。

在?XX 系統的回調地址,拿到授權的授權碼后,會自動請求統一登錄系統,通過授權碼獲取到訪問令牌。如此,我們便完成了?XXX 系統?的登錄。

獲取授權碼完成后,自動跳轉到登錄前的 http://127.0.0.1:9090/user/info 地址,打印出當前登錄的用戶信息。如下圖所示:

用戶信息

?


如此,我們從統一登錄系統也拿到了用戶信息。下面,我們來進一步將 Spring Security 的權限控制功能來演示下。

3.7 SecurityConfig

創建 SecurityConfig 配置類,添加 Spring Security 的功能。代碼如下:

@Configuration @EnableGlobalMethodSecurity(prePostEnabled?=?true)?//?開啟對 Spring Security 注解的方法,進行權限驗證。 @Order(101)?//?OAuth2SsoDefaultConfiguration?使用了?Order(100),所以這里設置為?Order(101),防止相同順序導致報錯 public?class?SecurityConfig?extends?WebSecurityConfigurerAdapter?{ }

在類上,增加?@EnableGlobalMethodSecurity?注解,開啟對 Spring Security 注解的方法,進行權限驗證。

3.8 DemoController

創建 DemoController 類,提供測試權限的功能的接口。代碼如下:

@RestController @RequestMapping("/demo") public?class?DemoController?{@GetMapping("/admin-list")@PreAuthorize("hasRole('ADMIN')")?//?要求管理員?ROLE_ADMIN?角色public?String?adminList()?{return?"管理員列表";}@GetMapping("/user-list")@PreAuthorize("hasRole('USER')")?//?要求普通用戶?ROLE_USER?角色public?String?userList()?{return?"用戶列表";}}

因為當前登錄的用戶只有?ROLE_USE?角色,所以可以訪問?/demo/user-list?接口,無法訪問?/demo/admin-list?接口。

3.9 簡單測試(第二彈)

執行 ResourceServerApplication?重啟?XXX 系統。下面,我們來演示下 Spring Security 的權限控制功能。

① 使用瀏覽器,訪問 http://127.0.0.1:9090/demo/user-list 地址,成功。如下圖所示:

成功訪問

② 使用瀏覽器,訪問 http://127.0.0.1:9090/demo/admin-list 地址,失敗。如下圖所示:

失敗訪問

?

666. 彩蛋

至此,我們成功使用 Spring Security OAuth 實現了一個 SSO 單點登錄的示例。下圖,是 SSO 的整體流程圖,胖友可以繼續深入理解下:

SSO 流程圖

后續,想要深入的胖友,可以看看 Spring Security OAuth 提供的如下兩個過濾器:

  • OAuth2ClientContextFilter

  • OAuth2ClientAuthenticationProcessingFilter

總結

以上是生活随笔為你收集整理的写了一个 SSO 单点登录的代码示例给胖友!的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。