舊的Spring Security OAuth已停止維護,全面擁抱新解決方案Spring SAS
Spring Authorization Server 替換 Shiro 指引
背景
Spring 團隊正式宣布 Spring Security OAuth 停止維護,該項目將不會(huì )再進(jìn)行任何的迭代 目前 Spring 生態(tài)中的 OAuth2 授權服務(wù)器是 Spring Authorization Server 已經(jīng)可以正式生產(chǎn)使用 作為 SpringBoot 3.0 的最新權限方案,JeecgBoot springboot3_sas分支,已經(jīng)完成了采用Spring Authorization Server 替換 Shiro工作。
JeecgBoot SAS分支
Date: 2024-01-17 技術(shù)棧: SpringBoot3+ Spring Authorization Server+jdk18
源碼下載:
后端:https://github.com/jeecgboot/jeecg-boot/tree/springboot3_sas 前端:https://github.com/jeecgboot/jeecgboot-vue3/tree/springboot3_sas
登錄對接
jeecg 基于Spring Authorization Server擴展了四種登錄實(shí)現,加上默認提供的四種,共計有8種登錄方式,額外還有OpenID Connect模式。本文不講解授權碼模式、客戶(hù)端模式、刷新碼模式、設備碼模式、OpenID Connect模式,只會(huì )講解jeecg實(shí)際應用了的四種擴展模式,其它模式請查閱Spring Authorization Server官方原文。
https://docs.spring.io/spring-authorization-server/reference/overview.html
注意:OpenID Connect應當僅為認證階段使用,不可作為權限校驗階段使用。
密碼模式和APP模式
密碼模式在Oauth2.1協(xié)議中被放棄,Spring Authorization Server并沒(méi)有對該模式提供實(shí)現,該實(shí)現是基于Spring Authorization Server提供的擴展入口實(shí)現的。
密碼模式實(shí)現源碼:package org.jeecg.config.security.password;
APP模式實(shí)現源碼:package org.jeecg.config.security.app;
密碼模式與APP模式實(shí)現完全一致,不過(guò)防止額外需求偏差,所以進(jìn)行了分開(kāi)實(shí)現。
請求地址:{baseUrl} /oauth2/token
請求方法:POST
請求頭:
請求頭名稱(chēng) 請求頭值 Authorization Basic base64(clientId:clientSecret)(此處需要自行替換) Content-Type application/x-www-form-urlencoded
請求參數:
參數名稱(chēng) 參數值 grant_type password/app (password為PC端使用,app為移動(dòng)端使用) username 用戶(hù)名 password 密碼
響應內容:
參數名稱(chēng) 參數含義 access_token 訪(fǎng)問(wèn)token,在被限制訪(fǎng)問(wèn)的接口請求中添加Authorization: Bearer access_token refersh_token 刷新token,用于刷新碼模式獲取新的access_token userInfo 當前登錄用戶(hù)信息 ... 其它內容不作詳解,請查看源碼
phone模式
phone模式用于手機+驗證碼登錄場(chǎng)景。
phone模式實(shí)現源碼:package org.jeecg.config.security.phone;
請求地址:{baseUrl} /oauth2/token
請求方法:POST
請求頭:
請求頭名稱(chēng) 請求頭值 Authorization Basic base64(clientId:clientSecret)(此處需要自行替換) Content-Type application/x-www-form-urlencoded
請求參數:
參數名稱(chēng) 參數值 grant_type 固定為phone mobile 手機號 captcha 驗證碼
響應內容:
參數名稱(chēng) 參數含義 access_token 訪(fǎng)問(wèn)token,在被限制訪(fǎng)問(wèn)的接口請求中添加Authorization: Bearer access_token refersh_token 刷新token,用于刷新碼模式獲取新的access_token userInfo 當前登錄用戶(hù)信息 ... 其它內容不作詳解,請查看源碼
social模式
任何一個(gè)用戶(hù)中心端(比如微信、微博、github、gitee)對外提供的對接方式都是授權碼模式、OpenID Connect模式,最終獲取到一段用戶(hù)信息(比如用戶(hù)名、頭像地址、郵箱),但是其實(shí)并沒(méi)有辦法拿著(zhù)這段信息在當前系統中訪(fǎng)問(wèn)受限資源,以前都是手搓token或者其它手段來(lái)得到受限訪(fǎng)問(wèn)的權限,這種方法不可靠也不安全,而且也不易維護。
jeecg針對以上場(chǎng)景,基于Spring Authorization Server擴展了social模式,用于處理獲取三方用戶(hù)信息后,再獲取當前系統的訪(fǎng)問(wèn)憑證。
social模式實(shí)現源碼:package org.jeecg.config.security.social;
提示:文檔中只講解social模式的應用,不講解從三方登錄到應用social模式的全流程,jeecg前后端均已實(shí)現,細節請查看源碼。
請求地址:{baseUrl} /oauth2/token
請求方法:POST
請求頭:
請求頭名稱(chēng) 請求頭值 Authorization Basic base64(clientId:clientSecret)(此處需要自行替換) Content-Type application/x-www-form-urlencoded
請求參數:
參數名稱(chēng) 參數值 grant_type 固定為social token 可獲取用戶(hù)信息的憑證 thirdType 三方來(lái)源
響應內容:
參數名稱(chēng) 參數含義 access_token 訪(fǎng)問(wèn)token,在被限制訪(fǎng)問(wèn)的接口請求中添加Authorization: Bearer access_token refersh_token 刷新token,用于刷新碼模式獲取新的access_token userInfo 當前登錄用戶(hù)信息 ... 其它內容不作詳解,請查看源碼
權限校驗
可用于方法或類(lèi)上,將基于注解的權限code,針對性處理方法或當前類(lèi)的所有接口進(jìn)行權限攔截。
基于角色
// 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. 獲取登錄用戶(hù)信息
LoginUser sysUser = SecureUtil.currentUser();