舊的Spring Security OAuth已停止維護,全面擁抱最新解決方案Spring SAS

Spring Authorization Server 替換 Shiro 指引

背景

  • Spring 團隊正式宣佈 Spring Security OAuth 停止維護,該項目將不會再進行任何的迭代

  • 目前 Spring 生態中的 OAuth2 授權服務器是 Spring Authorization Server 已經可以正式生產使用
  • 作爲 SpringBoot 3.0 的最新權限方案,JeecgBoot springboot3_sas分支,已經完成了採用Spring Authorization Server 替換 Shiro工作。

JeecgBoot SAS分支

  • Date: 2024-01-17
  • 技術棧: SpringBoot3+ Spring Authorization Server+jdk18

源碼下載:

登錄對接

jeecg 基於Spring Authorization Server擴展了四種登錄實現,加上默認提供的四種,共計有8種登錄方式,額外還有OpenID Connect模式。本文不講解授權碼模式、客戶端模式、刷新碼模式、設備碼模式、OpenID Connect模式,只會講解jeecg實際應用了的四種擴展模式,其它模式請查閱Spring Authorization Server官方原文。

https://docs.spring.io/spring-authorization-server/reference/overview.html

注意:OpenID Connect應當僅爲認證階段使用,不可作爲權限校驗階段使用。

密碼模式和APP模式

密碼模式在Oauth2.1協議中被放棄,Spring Authorization Server並沒有對該模式提供實現,該實現是基於Spring Authorization Server提供的擴展入口實現的。

密碼模式實現源碼:package org.jeecg.config.security.password;

APP模式實現源碼:package org.jeecg.config.security.app;

密碼模式與APP模式實現完全一致,不過防止額外需求偏差,所以進行了分開實現。

請求地址:{baseUrl} /oauth2/token

請求方法:POST

請求頭:

請求頭名稱 請求頭值
Authorization Basic base64(clientId:clientSecret)(此處需要自行替換)
Content-Type application/x-www-form-urlencoded

請求參數:

參數名稱 參數值
grant_type password/app (password爲PC端使用,app爲移動端使用)
username 用戶名
password 密碼

響應內容:

參數名稱 參數含義
access_token 訪問token,在被限制訪問的接口請求中添加Authorization: Bearer access_token
refersh_token 刷新token,用於刷新碼模式獲取新的access_token
userInfo 當前登錄用戶信息
... 其它內容不作詳解,請查看源碼

phone模式

phone模式用於手機+驗證碼登錄場景。

phone模式實現源碼:package org.jeecg.config.security.phone;

請求地址:{baseUrl} /oauth2/token

請求方法:POST

請求頭:

請求頭名稱 請求頭值
Authorization Basic base64(clientId:clientSecret)(此處需要自行替換)
Content-Type application/x-www-form-urlencoded

請求參數:

參數名稱 參數值
grant_type 固定爲phone
mobile 手機號
captcha 驗證碼

響應內容:

參數名稱 參數含義
access_token 訪問token,在被限制訪問的接口請求中添加Authorization: Bearer access_token
refersh_token 刷新token,用於刷新碼模式獲取新的access_token
userInfo 當前登錄用戶信息
... 其它內容不作詳解,請查看源碼

social模式

任何一個用戶中心端(比如微信、微博、github、gitee)對外提供的對接方式都是授權碼模式、OpenID Connect模式,最終獲取到一段用戶信息(比如用戶名、頭像地址、郵箱),但是其實並沒有辦法拿着這段信息在當前系統中訪問受限資源,以前都是手搓token或者其它手段來得到受限訪問的權限,這種方法不可靠也不安全,而且也不易維護。

jeecg針對以上場景,基於Spring Authorization Server擴展了social模式,用於處理獲取三方用戶信息後,再獲取當前系統的訪問憑證。

social模式實現源碼:package org.jeecg.config.security.social;

提示:文檔中只講解social模式的應用,不講解從三方登錄到應用social模式的全流程,jeecg前後端均已實現,細節請查看源碼。

請求地址:{baseUrl} /oauth2/token

請求方法:POST

請求頭:

請求頭名稱 請求頭值
Authorization Basic base64(clientId:clientSecret)(此處需要自行替換)
Content-Type application/x-www-form-urlencoded

請求參數:

參數名稱 參數值
grant_type 固定爲social
token 可獲取用戶信息的憑證
thirdType 三方來源

響應內容:

參數名稱 參數含義
access_token 訪問token,在被限制訪問的接口請求中添加Authorization: Bearer access_token
refersh_token 刷新token,用於刷新碼模式獲取新的access_token
userInfo 當前登錄用戶信息
... 其它內容不作詳解,請查看源碼

權限校驗

可用於方法或類上,將基於註解的權限code,針對性處理方法或當前類的所有接口進行權限攔截。

基於角色

// shiro用法
@RequiresRoles("admin")
 
// 可替換爲 spring authorization server 用法
@PreAuthorize("jps.requiresRoles('admin')")

基於權限

// shiro用法
@RequiresPermissions("sys:role") 


// 可替換爲 spring authorization server 用法
@PreAuthorize("jps.requiresPermissions('sys:role')")

角色和權限組合使用

- @PreAuthorize("@jps.requiresPermissions('system:quartzJob:add') or @jps.requiresRoles('admin')")

免登錄配置

jeecg:
  shiro:
    excludeUrls: /test/jeecgDemo/demo3,/test/jeecgDemo/redisDemo/**,/jmreport/bigscreen2/**




# 替換爲
security:
  oauth2:
    client:
      ignore-urls:
        - /test/jeecgDemo/demo3
        - /test/jeecgDemo/redisDemo/**
        - /jmreport/bigscreen2/**

升級小技巧

搜索 替換爲
org.apache.shiro.SecurityUtils org.jeecg.config.security.utils.SecureUtil
(LoginUser) SecurityUtils.getSubject().getPrincipal() SecureUtil.currentUser()
org.apache.shiro.authz.annotation.RequiresRoles org.springframework.security.access.prepost.PreAuthorize
org.apache.shiro.authz.annotation.RequiresPermissions org.springframework.security.access.prepost.PreAuthorize
@RequiresPermissions @PreAuthorize("jps.requiresPermissions('xxx')")
@RequiresRoles @PreAuthorize("@jps.requiresRoles('xxx')")

升級SQL

切換springboot3_sas分支的Spring Authorization Server,需要執行升級sql

CREATE TABLE `oauth2_registered_client` (
  `id` varchar(100) NOT NULL,
  `client_id` varchar(100) NOT NULL,
  `client_id_issued_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `client_secret` varchar(200) DEFAULT NULL,
  `client_secret_expires_at` timestamp NULL DEFAULT NULL,
  `client_name` varchar(200) NOT NULL,
  `client_authentication_methods` varchar(1000) NOT NULL,
  `authorization_grant_types` varchar(1000) NOT NULL,
  `redirect_uris` varchar(1000) DEFAULT NULL,
  `post_logout_redirect_uris` varchar(1000) DEFAULT NULL,
  `scopes` varchar(1000) NOT NULL,
  `client_settings` varchar(2000) NOT NULL,
  `token_settings` varchar(2000) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;


INSERT INTO `oauth2_registered_client`
(`id`,
`client_id`,
`client_id_issued_at`,
`client_secret`,
`client_secret_expires_at`,
`client_name`,
`client_authentication_methods`,
`authorization_grant_types`,
`redirect_uris`,
`post_logout_redirect_uris`,
`scopes`,
`client_settings`,
`token_settings`)
VALUES
('3eacac0e-0de9-4727-9a64-6bdd4be2ee1f',
'jeecg-client',
now(),
'secret',
null,
'3eacac0e-0de9-4727-9a64-6bdd4be2ee1f',
'client_secret_basic',
'refresh_token,authorization_code,password,app,phone,social',
'http://127.0.0.1:8080/jeecg-',
'http://127.0.0.1:8080/',
'*',
'{"@class":"java.util.Collections$UnmodifiableMap","settings.client.require-proof-key":false,"settings.client.require-authorization-consent":true}',
'{"@class":"java.util.Collections$UnmodifiableMap","settings.token.reuse-refresh-tokens":true,"settings.token.id-token-signature-algorithm":["org.springframework.security.oauth2.jose.jws.SignatureAlgorithm","RS256"],"settings.token.access-token-time-to-live":["java.time.Duration",300000.000000000],"settings.token.access-token-format":{"@class":"org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat","value":"self-contained"},"settings.token.refresh-token-time-to-live":["java.time.Duration",3600.000000000],"settings.token.authorization-code-time-to-live":["java.time.Duration",300000.000000000],"settings.token.device-code-time-to-live":["java.time.Duration",300000.000000000]}');

常用API

1. 獲取登錄用戶信息

LoginUser sysUser = SecureUtil.currentUser();

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章