From de7ccf05aadd962759be9cfe181dd7e59d1e557b Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Mon, 19 Jul 2021 01:12:55 +0800 Subject: [PATCH] =?UTF-8?q?OAuth2.0=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 16 +- .../java/cn/dev33/satoken/stp/StpLogic.java | 11 +- .../com/pj/satoken/jwt/SaTokenJwtUtil.java | 5 +- .../com/pj/SaOAuth2ClientApplication.java | 6 +- .../com/pj/SaOAuth2ServerApplication.java | 2 +- .../pj/oauth2/SaOAuth2ServerController.java | 2 +- .../sa-token-demo-springboot/pom.xml | 10 +- .../main/java/com/pj/test/TestController.java | 2 - .../src/main/resources/application.yml | 2 +- sa-token-doc/doc/README.md | 16 +- sa-token-doc/doc/_sidebar.md | 6 +- sa-token-doc/doc/lib/index.css | 3 + sa-token-doc/doc/oauth2/oauth2-api.md | 233 ++++++++++++++++++ sa-token-doc/doc/oauth2/oauth2-server.md | 178 +++++++++++++ sa-token-doc/doc/oauth2/readme.md | 31 +++ sa-token-doc/doc/senior/sso.md | 4 +- sa-token-doc/doc/sso/sso-type1.md | 4 +- sa-token-doc/doc/sso/sso-type2.md | 5 +- sa-token-doc/doc/start/example.md | 2 +- sa-token-doc/doc/use/config.md | 34 ++- sa-token-doc/doc/use/route-check.md | 5 +- .../oauth2/logic/SaOAuth2Template.java | 2 +- 22 files changed, 535 insertions(+), 44 deletions(-) create mode 100644 sa-token-doc/doc/oauth2/oauth2-api.md create mode 100644 sa-token-doc/doc/oauth2/oauth2-server.md create mode 100644 sa-token-doc/doc/oauth2/readme.md diff --git a/README.md b/README.md index b5784c7f..75eed5f6 100644 --- a/README.md +++ b/README.md @@ -25,13 +25,11 @@ - [开源不易,求鼓励,点个star吧 !](###) -## Sa-Token 是什么? +## Sa-Token 介绍 Sa-Token是一个轻量级Java权限认证框架,主要解决:登录认证、权限认证、Session会话、单点登录、OAuth2.0 等一系列权限相关问题 框架集成简单、开箱即用、API设计清爽,通过Sa-Token,你将以一种极其简单的方式实现系统的权限认证部分 -## Sa-Token 能做什么? - - **登录验证** —— 单端登录、多端登录、同端互斥登录、七天内免登录 - **权限验证** —— 权限认证、角色认证、会话二级认证 - **Session会话** —— 全端共享Session、单端独享Session、自定义Session @@ -61,7 +59,7 @@ Sa-Token是一个轻量级Java权限认证框架,主要解决:登录认证 - **更多功能正在集成中...** —— 如有您有好想法或者建议,欢迎加群交流 ##### Sa-Token 功能结构图 -![sa-token-js](https://color-test.oss-cn-qingdao.aliyuncs.com/sa-token/x/sa-token-js2.png 's-w') +![sa-token-js](https://color-test.oss-cn-qingdao.aliyuncs.com/sa-token/x/sa-token-js3.png 's-w') ##### Sa-Token 认证流程图 ![sa-token-rz](https://color-test.oss-cn-qingdao.aliyuncs.com/sa-token/x/sa-token-rz2.png 's-w') @@ -92,6 +90,16 @@ Sa-Token是一个轻量级Java权限认证框架,主要解决:登录认证 6. 高可定制:Sa-Token-SSO模块对代码架构侵入性极低,结合Sa-Token本身的路由拦截特性,你可以非常轻松的定制化开发 +## Sa-Token-OAuth2.0 授权登录 +Sa-OAuth2 模块基于 [RFC-6749 标准](https://tools.ietf.org/html/rfc6749) 编写,通过Sa-OAuth2你可以非常轻松的实现系统的OAuth2.0授权认证 + +1. 授权码(Authorization Code):OAuth2.0标准授权步骤,Server端向Client端下放Code码,Client端再用Code码换取授权Token +2. 隐藏式(Implicit):无法使用授权码模式时的备用选择,Server端使用URL重定向方式直接将Token下放到Client端页面 +3. 密码式(Password):Client直接拿着用户的账号密码换取授权Token +4. 客户端凭证(Client Credentials):Server端针对Client级别的Token,代表应用自身的资源授权 + +详细参考文档:[http://sa-token.dev33.cn/doc/index.html#/oauth2/readme](http://sa-token.dev33.cn/doc/index.html#/oauth2/readme) + ## 代码示例 diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java index 31bf516a..7b9c89f9 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java @@ -258,13 +258,10 @@ public class StpLogic { tokenValue = createTokenValue(id); } - // ------ 3. 获取[User-Session] (如果还没有创建session, 则新建, 如果已经创建,则续期) - SaSession session = getSessionByLoginId(id, false); - if(session == null) { - session = getSessionByLoginId(id); - } else { - session.updateMinTimeout(loginModel.getTimeout()); - } + // ------ 3. 获取[User-Session], 续期 + SaSession session = getSessionByLoginId(id, true); + session.updateMinTimeout(loginModel.getTimeout()); + // 在session上记录token签名 session.addTokenSign(new TokenSign(tokenValue, loginModel.getDevice())); diff --git a/sa-token-demo/sa-token-demo-jwt/src/main/java/com/pj/satoken/jwt/SaTokenJwtUtil.java b/sa-token-demo/sa-token-demo-jwt/src/main/java/com/pj/satoken/jwt/SaTokenJwtUtil.java index 97fbe14d..3c89c650 100644 --- a/sa-token-demo/sa-token-demo-jwt/src/main/java/com/pj/satoken/jwt/SaTokenJwtUtil.java +++ b/sa-token-demo/sa-token-demo-jwt/src/main/java/com/pj/satoken/jwt/SaTokenJwtUtil.java @@ -110,7 +110,10 @@ public class SaTokenJwtUtil { warn += "-------------------------------------"; System.err.println(warn); } - + + // 提前调用一下方法,促使其属性初始化 + StpUtil.getLoginType(); + // 修改默认实现 StpUtil.stpLogic = new StpLogic("login") { diff --git a/sa-token-demo/sa-token-demo-oauth2-client/src/main/java/com/pj/SaOAuth2ClientApplication.java b/sa-token-demo/sa-token-demo-oauth2-client/src/main/java/com/pj/SaOAuth2ClientApplication.java index 4853ef7b..0bbe6c48 100644 --- a/sa-token-demo/sa-token-demo-oauth2-client/src/main/java/com/pj/SaOAuth2ClientApplication.java +++ b/sa-token-demo/sa-token-demo-oauth2-client/src/main/java/com/pj/SaOAuth2ClientApplication.java @@ -3,9 +3,8 @@ package com.pj; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; - /** - * 启动:OAuth2-Client端 + * 启动:Sa-OAuth2 ClientServer端 * @author kong */ @SpringBootApplication @@ -16,7 +15,8 @@ public class SaOAuth2ClientApplication { System.out.println("\nSa-Token-OAuth Client端启动成功\n\n" + str); } - static String str = "首先在host文件 (C:\\WINDOWS\\system32\\drivers\\etc\\hosts) 添加以下内容: \r\n" + + static String str = "-------------------- Sa-Token-OAuth2 示例 --------------------\n\n" + + "首先在host文件 (C:\\windows\\system32\\drivers\\etc\\hosts) 添加以下内容: \r\n" + " 127.0.0.1 sa-oauth-server.com \r\n" + " 127.0.0.1 sa-oauth-client.com \r\n" + "再从浏览器访问:\r\n" + diff --git a/sa-token-demo/sa-token-demo-oauth2-server/src/main/java/com/pj/SaOAuth2ServerApplication.java b/sa-token-demo/sa-token-demo-oauth2-server/src/main/java/com/pj/SaOAuth2ServerApplication.java index 3c2d1567..a588eee0 100644 --- a/sa-token-demo/sa-token-demo-oauth2-server/src/main/java/com/pj/SaOAuth2ServerApplication.java +++ b/sa-token-demo/sa-token-demo-oauth2-server/src/main/java/com/pj/SaOAuth2ServerApplication.java @@ -4,7 +4,7 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** - * 启动:OAuth2-Server端 + * 启动:Sa-OAuth2 Server端 * @author kong */ @SpringBootApplication diff --git a/sa-token-demo/sa-token-demo-oauth2-server/src/main/java/com/pj/oauth2/SaOAuth2ServerController.java b/sa-token-demo/sa-token-demo-oauth2-server/src/main/java/com/pj/oauth2/SaOAuth2ServerController.java index 683a2df4..e40bc4d0 100644 --- a/sa-token-demo/sa-token-demo-oauth2-server/src/main/java/com/pj/oauth2/SaOAuth2ServerController.java +++ b/sa-token-demo/sa-token-demo-oauth2-server/src/main/java/com/pj/oauth2/SaOAuth2ServerController.java @@ -28,7 +28,7 @@ public class SaOAuth2ServerController { // 处理所有OAuth相关请求 @RequestMapping("/oauth2/*") public Object request() { - System.out.println("--------------进入请求 "); + System.out.println("------- 进入请求: " + SaHolder.getRequest().getUrl()); return SaOAuth2Handle.serverRequest(); } diff --git a/sa-token-demo/sa-token-demo-springboot/pom.xml b/sa-token-demo/sa-token-demo-springboot/pom.xml index 259ffcfa..5d3ab8ca 100644 --- a/sa-token-demo/sa-token-demo-springboot/pom.xml +++ b/sa-token-demo/sa-token-demo-springboot/pom.xml @@ -21,7 +21,7 @@ - + org.springframework.boot spring-boot-starter-web @@ -38,27 +38,27 @@ ${sa-token-version} - + - + - + - + cn.dev33 sa-token-spring-aop diff --git a/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java index aa349254..60e193e4 100644 --- a/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java +++ b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java @@ -9,7 +9,6 @@ import org.springframework.web.bind.annotation.RestController; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import com.pj.satoken.at.StpUserUtil; import com.pj.util.AjaxJson; import com.pj.util.Ttime; @@ -242,7 +241,6 @@ public class TestController { @RequestMapping("test") public AjaxJson test() { System.out.println("进来了"); - StpUserUtil.login(10001); return AjaxJson.getSuccess(); } diff --git a/sa-token-demo/sa-token-demo-springboot/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-springboot/src/main/resources/application.yml index 3d9b33c4..5ac6109e 100644 --- a/sa-token-demo/sa-token-demo-springboot/src/main/resources/application.yml +++ b/sa-token-demo/sa-token-demo-springboot/src/main/resources/application.yml @@ -11,7 +11,7 @@ sa-token: # token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒 activity-timeout: -1 # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) - is-concurrent: false + is-concurrent: true # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) is-share: true # token风格 diff --git a/sa-token-doc/doc/README.md b/sa-token-doc/doc/README.md index b5784c7f..75eed5f6 100644 --- a/sa-token-doc/doc/README.md +++ b/sa-token-doc/doc/README.md @@ -25,13 +25,11 @@ - [开源不易,求鼓励,点个star吧 !](###) -## Sa-Token 是什么? +## Sa-Token 介绍 Sa-Token是一个轻量级Java权限认证框架,主要解决:登录认证、权限认证、Session会话、单点登录、OAuth2.0 等一系列权限相关问题 框架集成简单、开箱即用、API设计清爽,通过Sa-Token,你将以一种极其简单的方式实现系统的权限认证部分 -## Sa-Token 能做什么? - - **登录验证** —— 单端登录、多端登录、同端互斥登录、七天内免登录 - **权限验证** —— 权限认证、角色认证、会话二级认证 - **Session会话** —— 全端共享Session、单端独享Session、自定义Session @@ -61,7 +59,7 @@ Sa-Token是一个轻量级Java权限认证框架,主要解决:登录认证 - **更多功能正在集成中...** —— 如有您有好想法或者建议,欢迎加群交流 ##### Sa-Token 功能结构图 -![sa-token-js](https://color-test.oss-cn-qingdao.aliyuncs.com/sa-token/x/sa-token-js2.png 's-w') +![sa-token-js](https://color-test.oss-cn-qingdao.aliyuncs.com/sa-token/x/sa-token-js3.png 's-w') ##### Sa-Token 认证流程图 ![sa-token-rz](https://color-test.oss-cn-qingdao.aliyuncs.com/sa-token/x/sa-token-rz2.png 's-w') @@ -92,6 +90,16 @@ Sa-Token是一个轻量级Java权限认证框架,主要解决:登录认证 6. 高可定制:Sa-Token-SSO模块对代码架构侵入性极低,结合Sa-Token本身的路由拦截特性,你可以非常轻松的定制化开发 +## Sa-Token-OAuth2.0 授权登录 +Sa-OAuth2 模块基于 [RFC-6749 标准](https://tools.ietf.org/html/rfc6749) 编写,通过Sa-OAuth2你可以非常轻松的实现系统的OAuth2.0授权认证 + +1. 授权码(Authorization Code):OAuth2.0标准授权步骤,Server端向Client端下放Code码,Client端再用Code码换取授权Token +2. 隐藏式(Implicit):无法使用授权码模式时的备用选择,Server端使用URL重定向方式直接将Token下放到Client端页面 +3. 密码式(Password):Client直接拿着用户的账号密码换取授权Token +4. 客户端凭证(Client Credentials):Server端针对Client级别的Token,代表应用自身的资源授权 + +详细参考文档:[http://sa-token.dev33.cn/doc/index.html#/oauth2/readme](http://sa-token.dev33.cn/doc/index.html#/oauth2/readme) + ## 代码示例 diff --git a/sa-token-doc/doc/_sidebar.md b/sa-token-doc/doc/_sidebar.md index 4e9d4643..0634d4e2 100644 --- a/sa-token-doc/doc/_sidebar.md +++ b/sa-token-doc/doc/_sidebar.md @@ -31,7 +31,6 @@ - **进阶** - [全局过滤器](/use/global-filter) - [集群、分布式](/senior/dcs) - - [多账号验证](/use/many-account) - **单点登录** @@ -40,6 +39,11 @@ - [SSO模式二 URL重定向传播会话](/sso/sso-type2) - [SSO模式三 Http请求获取会话](/sso/sso-type3) +- **OAuth2.0** + - [OAuth2.0简述](/oauth2/readme) + - [OAuth2-Server搭建](/oauth2/oauth2-server) + - [OAuth2-API列表](/oauth2/oauth2-api) + - **插件** - [AOP注解鉴权](/plugin/aop-at) - [临时Token验证](/plugin/temp-token) diff --git a/sa-token-doc/doc/lib/index.css b/sa-token-doc/doc/lib/index.css index 31146a78..aed7f1d0 100644 --- a/sa-token-doc/doc/lib/index.css +++ b/sa-token-doc/doc/lib/index.css @@ -70,6 +70,9 @@ body{font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu /* yml语言样式优化 */ .main-box .lang-yml{color: #01A252 !important; opacity: 1;} +/* yml语言样式优化 */ +.main-box .lang-url{color: #E96917 !important; opacity: 1;} + /* js语言样式优化 */ .main-box .lang-js{color: #01a252 !important;} .lang-js .token.comment{color: #CDAB53;} diff --git a/sa-token-doc/doc/oauth2/oauth2-api.md b/sa-token-doc/doc/oauth2/oauth2-api.md new file mode 100644 index 00000000..4f94652e --- /dev/null +++ b/sa-token-doc/doc/oauth2/oauth2-api.md @@ -0,0 +1,233 @@ +# Sa-Token-OAuth2 Server端 API列表 +基于官方仓库的搭建示例,`OAuth2-Server`端会暴露出以下API,`OAuth2-Client`端可据此文档进行对接 + +--- + +## 1、模式一:授权码(Authorization Code) + +### 1.1、获取授权码 + +根据以下格式构建URL,引导用户访问 (复制时请注意删减掉相应空格和换行符) +``` url +http://sa-oauth-server.com:8001/oauth2/authorize + ?response_type=code + &client_id={value} + &redirect_uri={value} + &scope={value} + $state={value} +``` + +参数详解: + +| 参数 | 是否必填 | 说明 | +| :-------- | :-------- | :-------- | +| response_type | 是 | 返回类型,这里请填写:code | +| client_id | 是 | 应用id | +| redirect_uri | 是 | 用户确认授权后,重定向的url地址 | +| scope | 否 | 具体请求的权限,多个用逗号隔开 | +| state | 否 | 随机值,此参数会在重定向时追加到url末尾,不填不追加 | + +注意点: +1. 如果用户在Server端尚未登录:会被转发到登录视图,你可以参照文档或官方示例自定义登录页面 +2. 如果scope参数为空,或者请求的权限用户近期已确认过,则无需用户再次确认,达到静默授权的效果,否则需要用户手动确认,服务器才可以下放code授权码 + +用户确认授权之后,会被重定向至`redirect_uri`,并追加code参数与state参数,形如: +``` url +redirect_uri?code={code}&state={state} +``` + +Code授权码具有以下特点: +1. 每次授权产生的Code码都不一样 +2. Code码用完即废,不能二次使用 +3. 一个Code的有效期默认为五分钟,超时自动作废 +4. 每次授权产生新Code码,会导致旧Code码立即作废,即使旧Code码尚未使用 + + +### 1.2、根据授权码获取Access-Token +获得Code码后,我们可以通过以下接口,获取到用户的`Access-Token`、`Refresh-Token`、`openid`等关键信息 + +``` url +http://sa-oauth-server.com:8001/oauth2/token + ?grant_type=authorization_code + &client_id={value} + &client_secret={value} + &code={value} +``` + +参数详解: + +| 参数 | 是否必填 | 说明 | +| :-------- | :-------- | :-------- | +| grant_type | 是 | 授权类型,这里请填写:authorization_code | +| client_id | 是 | 应用id | +| client_secret | 是 | 应用秘钥 | +| code | 是 | 步骤1.1中获取到的授权码 | + +接口返回示例: + +``` js +{ + "code": 200, // 200表示请求成功,非200标识请求失败, 以下不再赘述 + "msg": "ok", + "data": { + "access_token": "7Ngo1Igg6rieWwAmWMe4cxT7j8o46mjyuabuwLETuAoN6JpPzPO2i3PVpEVJ", // Access-Token值 + "refresh_token": "ZMG7QbuCVtCIn1FAJuDbgEjsoXt5Kqzii9zsPeyahAmoir893ARA4rbmeR66", // Refresh-Token值 + "expires_in": 7199, // Access-Token剩余有效期,单位秒 + "refresh_expires_in": 2591999, // Refresh-Token剩余有效期,单位秒 + "client_id": "1001", // 应用id + "scope": "userinfo", // 此令牌包含的权限 + "openid": "gr_SwoIN0MC1ewxHX_vfCW3BothWDZMMtx__" // openid + } +} +``` + + +### 1.3、根据 Refresh-Token 刷新 Access-Token (如果需要的话) +Access-Token的有效期较短,如果每次过期都需要重新授权的话,会比较影响用户体验,因此我们可以在后台通过`Refresh-Token` 刷新 `Access-Token` + +``` url +http://sa-oauth-server.com:8001/oauth2/refresh + ?grant_type=refresh_token + &client_id={value} + &client_secret={value} + &refresh_token={value} +``` + +参数详解: + +| 参数 | 是否必填 | 说明 | +| :-------- | :-------- | :-------- | +| grant_type | 是 | 授权类型,这里请填写:refresh_token | +| client_id | 是 | 应用id | +| client_secret | 是 | 应用秘钥 | +| refresh_token | 是 | 步骤1.2中获取到的`Refresh-Token`值 | + +接口返回值同章节1.2,此处不再赘述 + + +### 1.4、根据 Access-Token 获取相应用户的账号信息 +注:此接口为官方仓库模拟接口,正式项目中大家可以根据此样例,自定义需要的接口及参数 + +``` url +http://sa-oauth-server.com:8001/oauth2/userinfo?access_token={value} +``` + +返回值样例: +``` js +{ + "code": 200, + "msg": "ok", + "data": { + "nickname": "shengzhang_", // 账号昵称 + "avatar": "http://xxx.com/1.jpg", // 头像地址 + "age": "18", // 年龄 + "sex": "男", // 性别 + "address": "山东省 青岛市 城阳区" // 所在城市 + } +} +``` + + +## 2、模式二:隐藏式(Implicit) + +根据以下格式构建URL,引导用户访问: +``` url +http://sa-oauth-server.com:8001/oauth2/authorize + ?response_type=token + &client_id={value} + &redirect_uri={value} + &scope={value} + $state={value} +``` + +参数详解: + +| 参数 | 是否必填 | 说明 | +| :-------- | :-------- | :-------- | +| response_type | 是 | 返回类型,这里请填写:token | +| client_id | 是 | 应用id | +| redirect_uri | 是 | 用户确认授权后,重定向的url地址 | +| scope | 否 | 具体请求的权限,多个用逗号隔开 | +| state | 否 | 随机值,此参数会在重定向时追加到url末尾,不填不追加 | + +此模式会越过授权码的步骤,直接返回Access-Token到前端页面,形如: +``` url +redirect_uri#token=xxxx-xxxx-xxxx-xxxx +``` + +## 3、模式三:密码式(Password) +首先在Client端构建表单,让用户输入Server端的账号和密码,然后在Client端访问接口 +``` url +http://sa-oauth-server.com:8001/oauth2/token + ?grant_type=password + &client_id={value} + &username={value} + &password={value} +``` + +参数详解: + +| 参数 | 是否必填 | 说明 | +| :-------- | :-------- | :-------- | +| grant_type| 是 | 返回类型,这里请填写:password| +| client_id | 是 | 应用id | +| username | 是 | 用户的Server端账号 | +| password | 否 | 用户的Server端密码 | + +接口返回示例: + +``` js +{ + "code": 200, // 200表示请求成功,非200标识请求失败, 以下不再赘述 + "msg": "ok", + "data": { + "access_token": "7Ngo1Igg6rieWwAmWMe4cxT7j8o46mjyuabuwLETuAoN6JpPzPO2i3PVpEVJ", // Access-Token值 + "refresh_token": "ZMG7QbuCVtCIn1FAJuDbgEjsoXt5Kqzii9zsPeyahAmoir893ARA4rbmeR66", // Refresh-Token值 + "expires_in": 7199, // Access-Token剩余有效期,单位秒 + "refresh_expires_in": 2591999, // Refresh-Token剩余有效期,单位秒 + "client_id": "1001", // 应用id + "scope": "", // 此令牌包含的权限 + "openid": "gr_SwoIN0MC1ewxHX_vfCW3BothWDZMMtx__" // openid + } +} +``` + + +## 4、模式四:凭证式(Client Credentials) +以上三种模式获取的都是用户的 `Access-Token`,代表用户对第三方应用的授权, +在OAuth2.0中还有一种针对 Client级别的授权, 即:`Client-Token`,代表应用自身的资源授权 + +在Client端的后台访问以下接口: + +``` url +http://sa-oauth-server.com:8001/oauth2/client_token + ?grant_type=client_credentials + &client_id={value} + &client_secret={value} +``` + +参数详解: + +| 参数 | 是否必填 | 说明 | +| :-------- | :-------- | :-------- | +| grant_type | 是 | 返回类型,这里请填写:client_credentials| +| client_id | 是 | 应用id | +| client_secret | 是 | 应用秘钥 | + +接口返回值样例: +``` js +{ + "code": 200, + "msg": "ok", + "data": { + "client_token": "HmzPtaNuIqGrOdudWLzKJRSfPadN497qEJtanYwE7ZvHQWDy0jeoZJuDIiqO", // Client-Token 值 + "expires_in": 7199, // Token剩余有效时间,单位秒 + "client_id": "1001", // 应用id + "scope": null // 包含权限 + } +} +``` + +注:`Client-Token`具有延迟作废特性,即:在每次获取最新`Client-Token`的时候,旧`Client-Token`不会立即过期,而是作为`Past-Token`再次储存起来, +资源请求方只要携带其中之一便可通过Token校验,这种特性保证了在大量并发请求时不会出现“新旧Token交替造成的授权失效”, 保证了服务的高可用 + diff --git a/sa-token-doc/doc/oauth2/oauth2-server.md b/sa-token-doc/doc/oauth2/oauth2-server.md new file mode 100644 index 00000000..6941b7d4 --- /dev/null +++ b/sa-token-doc/doc/oauth2/oauth2-server.md @@ -0,0 +1,178 @@ +# 搭建OAuth2-Server + +--- + +### 1、准备工作 +首先修改hosts文件`(C:\windows\system32\drivers\etc\hosts)`,添加以下IP映射,方便我们进行测试: +``` url +127.0.0.1 sa-oauth-server.com +127.0.0.1 sa-oauth-client.com +``` + + +### 2、引入依赖 +创建SpringBoot项目 `sa-token-demo-oauth2-server`(不会的同学自行百度或参考仓库示例),添加pom依赖: + +``` xml + + + cn.dev33 + sa-token-spring-boot-starter + ${sa.top.version} + + + + + cn.dev33 + sa-token-oauth2 + ${sa.top.version} + +``` + +### 3、开放服务 +1、新建 `SaOAuth2TemplateImpl` +``` java +/** + * Sa-Token OAuth2.0 整合实现 + */ +@Component +public class SaOAuth2TemplateImpl extends SaOAuth2Template { + + // 根据 id 获取 Client 信息 + @Override + public SaClientModel getClientModel(String clientId) { + // 此为模拟数据,真实环境需要从数据库查询 + if("1001".equals(clientId)) { + return new SaClientModel() + .setClientId("10001") + .setClientSecret("aaaa-bbbb-cccc-dddd-eeee") + .setAllowUrl("*") + .setContractScope("userinfo"); + } + return null; + } + + // 根据ClientId 和 LoginId 获取openid + @Override + public String getOpenid(String clientId, Object loginId) { + // 此为模拟数据,真实环境需要从数据库查询 + return "gr_SwoIN0MC1ewxHX_vfCW3BothWDZMMtx__"; + } + +} +``` + +2、新建`SaOAuth2ServerController` +``` java +/** + * Sa-OAuth2 Server端 控制器 + */ +@RestController +public class SaOAuth2ServerController { + + // 处理所有OAuth相关请求 + @RequestMapping("/oauth2/*") + public Object request() { + System.out.println("------- 进入请求: " + SaHolder.getRequest().getUrl()); + return SaOAuth2Handle.serverRequest(); + } + + // Sa-OAuth2 定制化配置 + @Autowired + public void setSaOAuth2Config(SaOAuth2Config cfg) { + cfg. + // 配置:未登录时返回的View + setNotLoginView(() -> { + String msg = "当前会话在SSO-Server端尚未登录,请先访问" + + " doLogin登录 " + + "进行登录之后,刷新页面开始授权"; + return msg; + }). + // 配置:登录处理函数 + setDoLoginHandle((name, pwd) -> { + if("sa".equals(name) && "123456".equals(pwd)) { + StpUtil.login(10001); + return SaResult.ok(); + } + return SaResult.error("账号名或密码错误"); + }). + // 配置:确认授权时返回的View + setConfirmView((clientId, scope) -> { + String msg = "

应用 " + clientId + " 请求授权:" + scope + "

" + + "

请确认: 确认授权

" + + "

确认之后刷新页面

"; + return msg; + }) + ; + } + + // 全局异常拦截 + @ExceptionHandler + public SaResult handlerException(Exception e) { + e.printStackTrace(); + return SaResult.error(e.getMessage()); + } + +} +``` +注意:在`setDoLoginHandle`函数里如果要获取name, pwd以外的参数,可通过`SaHolder.getRequest().getParam("xxx")`来获取 + +3、创建启动类: +``` java +/** + * 启动:Sa-OAuth2 Server端 + */ +@SpringBootApplication +public class SaOAuth2ServerApplication { + public static void main(String[] args) { + SpringApplication.run(SaOAuth2ServerApplication.class, args); + System.out.println("\nSa-Token-OAuth Server端启动成功"); + } +} +``` +启动项目 + + +### 4、访问测试 + +1、由于暂未搭建Client端,我们可以使用Sa-Token官网作为重定向URL进行测试: +``` url +http://sa-oauth-server.com:8001/oauth2/authorize?response_type=code&client_id=1001&redirect_uri=http://sa-token.dev33.cn/&scope=userinfo +``` + +2、由于首次访问,我们在OAuth-Server端暂未登录,会被转发到登录视图 + +![sa-oauth2-server-login-view](https://oss.dev33.cn/sa-token/doc/oauth2/sa-oauth2-server-login-view.png 's-w-sh') + +3、点击doLogin进行登录之后刷新页面,会提示我们确认授权 +![sa-oauth2-server-login-view](https://oss.dev33.cn/sa-token/doc/oauth2/sa-oauth2-server-scope.png 's-w-sh') + +4、点击确认授权之后刷新页面,我们会被重定向至 redirect_uri 页面,并携带了code参数 + +![sa-oauth2-server-code](https://oss.dev33.cn/sa-token/doc/oauth2/sa-oauth2-server-code.png 's-w-sh') + +4、我们拿着code参数,访问以下地址: +``` url +http://sa-oauth-server.com:8001/oauth2/token?grant_type=authorization_code&client_id=1001&client_secret=aaaa-bbbb-cccc-dddd-eeee&code={code} +``` + +将得到 `Access-Token`、`Refresh-Token`、`openid`等授权信息 + +![sa-oauth2-server-token](https://oss.dev33.cn/sa-token/doc/oauth2/sa-oauth2-server-token.png 's-w-sh') + +测试完毕 + + +### 5、运行官方示例 +以上代码只是简单模拟了一下OAuth2.0的授权流程,现在,我们运行一下官方示例,里面有制作好的UI界面 + +- OAuth2-Server端: `/sa-token-demo/sa-token-demo-oauth2-server/` [源码链接](https://gitee.com/dromara/sa-token/tree/dev/sa-token-demo/sa-token-demo-oauth2-server)
+- OAuth2-Client端: `/sa-token-demo/sa-token-demo-oauth2-client/` [源码链接](https://gitee.com/dromara/sa-token/tree/dev/sa-token-demo/sa-token-demo-oauth2-client)
+ +依次启动`OAuth2-Server` 与 `OAuth2-Client`,然后从浏览器访问:[http://sa-oauth-client.com:8002](http://sa-oauth-client.com:8002) + +![sa-oauth2-client-index](https://oss.dev33.cn/sa-token/doc/oauth2/sa-oauth2-client-index.png 's-w-sh') + +如图,可以针对OAuth2.0四种模式进行详细测试 + + diff --git a/sa-token-doc/doc/oauth2/readme.md b/sa-token-doc/doc/oauth2/readme.md new file mode 100644 index 00000000..11022c34 --- /dev/null +++ b/sa-token-doc/doc/oauth2/readme.md @@ -0,0 +1,31 @@ +# Sa-Token-OAuth2.0 模块 + +--- + +### 什么是OAuth2.0?解决什么问题? + +简单来讲,OAuth2.0的应用场景可以理解为单点登录的升级版,单点登录解决了多个系统间会话的共享,OAuth2.0在此基础上增加了应用之间的权限控制 +(SO:有些系统采用OAuth2.0模式实现了单点登录,但这总给人一种“杀鸡焉用宰牛刀”的感觉) + +有关OAuth2.0的设计思想网上教程较多,此处不再重复赘述,详细可参考博客: +[OAuth2.0 简单解释](https://www.ruanyifeng.com/blog/2019/04/oauth_design.html) + + +Sa-OAuth2 模块基于 [RFC-6749 标准](https://tools.ietf.org/html/rfc6749) 编写,通过Sa-OAuth2你可以非常轻松的实现系统的OAuth2.0授权认证 + + +### OAuth2.0 四种模式 + +基于不同的使用场景,OAuth2.0设计了四种模式: + +1. 授权码(Authorization Code):OAuth2.0标准授权步骤,Server端向Client端下放Code码,Client端再用Code码换取授权Token +2. 隐藏式(Implicit):无法使用授权码模式时的备用选择,Server端使用URL重定向方式直接将Token下放到Client端页面 +3. 密码式(Password):Client直接拿着用户的账号密码换取授权Token +4. 客户端凭证(Client Credentials):Server端针对Client级别的Token,代表应用自身的资源授权 + +![https://oss.dev33.cn/sa-token/doc/oauth2/sa-oauth2-setup.png](https://oss.dev33.cn/sa-token/doc/oauth2/sa-oauth2-setup.png) + +接下来我们将通过简单示例演示如何在Sa-OAuth2中完成这四种模式的对接: [搭建OAuth2-Server](/oauth2/oauth2-server) + + + diff --git a/sa-token-doc/doc/senior/sso.md b/sa-token-doc/doc/senior/sso.md index 495a8fa6..cad0385b 100644 --- a/sa-token-doc/doc/senior/sso.md +++ b/sa-token-doc/doc/senior/sso.md @@ -40,8 +40,8 @@ OK,所有理论就绪,下面开始实战 Sa-Token整合同域下的单点登录非常简单,相比于正常的登录,你只需要在配置文件中增加配置 `sa-token.cookie-domain=xxx.com` 来指定一下Cookie写入时指定的父级域名即可,详细步骤示例如下: #### 1. 准备工作 -首先修改hosts文件(`C:\WINDOWS\system32\drivers\etc\hosts`),添加以下IP映射,方便我们进行测试: -``` text +首先修改hosts文件(`C:\windows\system32\drivers\etc\hosts`),添加以下IP映射,方便我们进行测试: +``` url 127.0.0.1 s1.stp.com 127.0.0.1 s2.stp.com 127.0.0.1 s3.stp.com diff --git a/sa-token-doc/doc/sso/sso-type1.md b/sa-token-doc/doc/sso/sso-type1.md index 05dff303..dfa8cbbc 100644 --- a/sa-token-doc/doc/sso/sso-type1.md +++ b/sa-token-doc/doc/sso/sso-type1.md @@ -29,8 +29,8 @@ OK,所有理论就绪,下面开始实战 ### 1、准备工作 -首先修改hosts文件`(C:\WINDOWS\system32\drivers\etc\hosts)`,添加以下IP映射,方便我们进行测试: -``` text +首先修改hosts文件`(C:\windows\system32\drivers\etc\hosts)`,添加以下IP映射,方便我们进行测试: +``` url 127.0.0.1 s1.stp.com 127.0.0.1 s2.stp.com 127.0.0.1 s3.stp.com diff --git a/sa-token-doc/doc/sso/sso-type2.md b/sa-token-doc/doc/sso/sso-type2.md index 16f5630b..5b1dd70e 100644 --- a/sa-token-doc/doc/sso/sso-type2.md +++ b/sa-token-doc/doc/sso/sso-type2.md @@ -94,6 +94,7 @@ public class SsoServerController { } ``` +注意:在`setDoLoginHandle`函数里如果要获取name, pwd以外的参数,可通过`SaHolder.getRequest().getParam("xxx")`来获取 ##### 1.4、application.yml配置 ``` yml @@ -243,8 +244,8 @@ public class SaSsoClientApplication { ### 3、测试访问 ##### 3.1 修改host文件 -首先修改hosts文件`(C:\WINDOWS\system32\drivers\etc\hosts)`,添加以下IP映射,方便我们进行测试: -``` +首先修改hosts文件`(C:\windows\system32\drivers\etc\hosts)`,添加以下IP映射,方便我们进行测试: +``` url 127.0.0.1 sa-sso-server.com 127.0.0.1 sa-sso-client1.com 127.0.0.1 sa-sso-client2.com diff --git a/sa-token-doc/doc/start/example.md b/sa-token-doc/doc/start/example.md index e27c1601..1ec2abc9 100644 --- a/sa-token-doc/doc/start/example.md +++ b/sa-token-doc/doc/start/example.md @@ -39,7 +39,7 @@ sa-token: # token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒 activity-timeout: -1 # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) - is-concurrent: false + is-concurrent: true # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) is-share: false # token风格 diff --git a/sa-token-doc/doc/use/config.md b/sa-token-doc/doc/use/config.md index 39c3c3c0..7a91342f 100644 --- a/sa-token-doc/doc/use/config.md +++ b/sa-token-doc/doc/use/config.md @@ -18,9 +18,9 @@ sa-token: # token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒 activity-timeout: -1 # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) - is-concurrent: false + is-concurrent: true # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) - is-share: false + is-share: true # token风格 token-style: uuid # 是否输出操作日志 @@ -116,4 +116,32 @@ sa-token: sso: # SSO-Server端 单点登录地址 auth-url: http://sa-sso-server.com:9000/sso/auth -``` \ No newline at end of file +``` + + + +### OAuth2.0相关配置 +| 参数名称 | 类型 | 默认值 | 说明 | +| :-------- | :-------- | :-------- | :-------- | +| isCode | Boolean | true | 是否打开模式:授权码(Authorization Code) | +| isImplicit | Boolean | false | 是否打开模式:隐藏式(Implicit) | +| isPassword | Boolean | false | 是否打开模式:密码式(Password) | +| isClient | Boolean | false | 是否打开模式:凭证式(Client Credentials) | +| isNewRefresh | Boolean | false | 是否在每次 Refresh-Token 刷新 Access-Token 时,产生一个新的 Refresh-Token | +| codeTimeout | long | 300 | Code授权码 保存的时间(单位秒) 默认五分钟 | +| accessTokenTimeout | long | 7200 | Access-Token 保存的时间(单位秒) 默认两个小时 | +| refreshTokenTimeout | long | 2592000 | Refresh-Token 保存的时间(单位秒) 默认30 天 | +| clientTokenTimeout | long | 7200 | Client-Token 保存的时间(单位秒) 默认两个小时 | + +配置示例: +``` yml +# sa-token配置 +sa-token: + token-name: satoken-server + # OAuth2.0 配置 + oauth2: + is-code: true + is-implicit: true + is-password: true + is-client: true +``` diff --git a/sa-token-doc/doc/use/route-check.md b/sa-token-doc/doc/use/route-check.md index 16a6ff19..1a33970c 100644 --- a/sa-token-doc/doc/use/route-check.md +++ b/sa-token-doc/doc/use/route-check.md @@ -87,9 +87,8 @@ public class SaTokenConfigure implements WebMvcConfigurer { } }); - // 提前退出 - - + // 提前退出 (执行SaRouter.stop()后会直接退出匹配链) + SaRouter.match("/test/back", () -> SaRouter.stop()); // 在多账号模式下,可以使用任意StpUtil进行校验 SaRouter.match("/user/**", () -> StpUserUtil.checkLogin()); diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Template.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Template.java index ed97b8a2..ebd1b884 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Template.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Template.java @@ -69,7 +69,7 @@ public class SaOAuth2Template { */ public AccessTokenModel checkAccessToken(String accessToken) { AccessTokenModel at = getAccessToken(accessToken); - SaOAuth2Exception.throwBy(at == null, "无效:access_token" + accessToken); + SaOAuth2Exception.throwBy(at == null, "无效access_token:" + accessToken); return at; } /**