From 971c2860f00c0068c04b82c8e8daab7e983182e1 Mon Sep 17 00:00:00 2001
From: click33 <2393584716@qq.com>
Date: Sat, 17 Jul 2021 23:48:12 +0800
Subject: [PATCH] OAuth2.0 beta ..
---
.../cn/dev33/satoken/config/SaSsoConfig.java | 5 +-
.../dev33/satoken/config/SaTokenConfig.java | 6 +-
.../satoken/context/model/SaRequest.java | 8 +
.../cn/dev33/satoken/sso/SaSsoConsts.java | 4 +-
.../java/cn/dev33/satoken/util/SaFoxUtil.java | 39 +
.../java/cn/dev33/satoken/util/SaResult.java | 98 ++-
.../sa-token-demo-oauth2-client/pom.xml | 25 +-
.../com/pj/SaOAuth2ClientApplication.java | 11 +-
.../pj/oauth2/SaOAuthClientController.java | 188 +++++
.../src/main/java/com/pj/utils/SoMap.java | 18 +-
.../src/main/resources/application.yml | 6 -
.../src/main/resources/templates/index.html | 253 ++++++
.../sa-token-demo-oauth2-server/pom.xml | 21 +-
.../com/pj/SaOAuth2ServerApplication.java | 4 +-
.../pj/oauth2/SaOAuth2ServerController.java | 89 ++
.../com/pj/oauth2/SaOAuth2TemplateImpl.java | 68 +-
.../src/main/resources/application.yml | 11 +-
.../src/main/resources/templates/confirm.html | 103 +++
.../src/main/resources/templates/login.html | 54 ++
.../sa-token-demo-springboot/pom.xml | 1 -
.../com/pj/SaTokenWebfluxDemoApplication.java | 11 -
sa-token-doc/doc/more/tj-gzh.md | 33 +-
sa-token-doc/doc/plugin/alone-redis.md | 26 +-
sa-token-doc/doc/use/dao-extend.md | 3 +-
sa-token-doc/doc/use/kick.md | 2 +-
sa-token-doc/doc/use/login-auth.md | 3 -
.../dev33/satoken/oauth2/SaOAuth2Manager.java | 2 +-
.../satoken/oauth2/config/SaOAuth2Config.java | 175 ++--
.../satoken/oauth2/logic/SaOAuth2Consts.java | 72 +-
.../satoken/oauth2/logic/SaOAuth2Handle.java | 295 +++++--
.../oauth2/logic/SaOAuth2Template.java | 772 ++++++++++--------
.../satoken/oauth2/logic/SaOAuth2Util.java | 400 ++++-----
.../oauth2/model/AccessTokenModel.java | 16 +-
.../oauth2/model/ClientTokenModel.java | 11 +-
.../dev33/satoken/oauth2/model/CodeModel.java | 8 +-
.../oauth2/model/RefreshTokenModel.java | 13 +-
.../oauth2/model/RequestAuthModel.java | 6 +-
.../satoken/oauth2/model/SaClientModel.java | 115 +++
.../satoken/reactor/spring/SaBeanInject.java | 4 -
.../main/resources/META-INF/spring.factories | 5 +-
.../sa-token-spring-boot-starter/pom.xml | 7 +
.../cn/dev33/satoken/spring/SaBeanInject.java | 4 -
.../spring/oauth2/SaOAuth2BeanInject.java | 40 +
.../spring/oauth2/SaOAuth2BeanRegister.java | 28 +
.../satoken/spring/oauth2/package-info.java | 4 +
.../main/resources/META-INF/spring.factories | 7 +-
46 files changed, 2160 insertions(+), 914 deletions(-)
create mode 100644 sa-token-demo/sa-token-demo-oauth2-client/src/main/java/com/pj/oauth2/SaOAuthClientController.java
create mode 100644 sa-token-demo/sa-token-demo-oauth2-client/src/main/resources/templates/index.html
create mode 100644 sa-token-demo/sa-token-demo-oauth2-server/src/main/java/com/pj/oauth2/SaOAuth2ServerController.java
create mode 100644 sa-token-demo/sa-token-demo-oauth2-server/src/main/resources/templates/confirm.html
create mode 100644 sa-token-demo/sa-token-demo-oauth2-server/src/main/resources/templates/login.html
create mode 100644 sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/SaClientModel.java
create mode 100644 sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/oauth2/SaOAuth2BeanInject.java
create mode 100644 sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/oauth2/SaOAuth2BeanRegister.java
create mode 100644 sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/oauth2/package-info.java
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/config/SaSsoConfig.java b/sa-token-core/src/main/java/cn/dev33/satoken/config/SaSsoConfig.java
index 93539bff..7562e3ed 100644
--- a/sa-token-core/src/main/java/cn/dev33/satoken/config/SaSsoConfig.java
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/config/SaSsoConfig.java
@@ -1,5 +1,6 @@
package cn.dev33.satoken.config;
+import java.io.Serializable;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
@@ -13,7 +14,9 @@ import cn.dev33.satoken.util.SaResult;
* @author kong
*
*/
-public class SaSsoConfig {
+public class SaSsoConfig implements Serializable {
+
+ private static final long serialVersionUID = -6541180061782004705L;
/**
* Ticket有效期 (单位: 秒)
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/config/SaTokenConfig.java b/sa-token-core/src/main/java/cn/dev33/satoken/config/SaTokenConfig.java
index 2823d9c1..9e1b4d57 100644
--- a/sa-token-core/src/main/java/cn/dev33/satoken/config/SaTokenConfig.java
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/config/SaTokenConfig.java
@@ -1,5 +1,7 @@
package cn.dev33.satoken.config;
+import java.io.Serializable;
+
/**
* Sa-Token 配置类 Model
*
@@ -8,7 +10,9 @@ package cn.dev33.satoken.config;
* @author kong
*
*/
-public class SaTokenConfig {
+public class SaTokenConfig implements Serializable {
+
+ private static final long serialVersionUID = -6541180061782004705L;
/** token名称 (同时也是cookie名称) */
private String tokenName = "satoken";
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/context/model/SaRequest.java b/sa-token-core/src/main/java/cn/dev33/satoken/context/model/SaRequest.java
index 76b7dfa6..67b8fbab 100644
--- a/sa-token-core/src/main/java/cn/dev33/satoken/context/model/SaRequest.java
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/context/model/SaRequest.java
@@ -82,6 +82,14 @@ public interface SaRequest {
*/
public String getRequestPath();
+ /**
+ * 返回当前请求path是否为指定值
+ * @return see note
+ */
+ public default boolean isPath(String path) {
+ return getRequestPath().equals(path);
+ }
+
/**
* 返回当前请求的url,例:http://xxx.com/?id=127
* @return see note
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/sso/SaSsoConsts.java b/sa-token-core/src/main/java/cn/dev33/satoken/sso/SaSsoConsts.java
index 1bc440ed..b79a2489 100644
--- a/sa-token-core/src/main/java/cn/dev33/satoken/sso/SaSsoConsts.java
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/sso/SaSsoConsts.java
@@ -65,7 +65,7 @@ public class SaSsoConsts {
/** 表示OK的返回结果 */
public static final String OK = "ok";
- /** 表示请求没有得到任何有效处理 */
- public static final String NOT_HANDLE = "not handle";
+ /** 表示请求没有得到任何有效处理 {msg: "not handle"} */
+ public static final String NOT_HANDLE = "{\"msg\": \"not handle\"}";
}
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java b/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java
index 6cdf98dc..249404d4 100644
--- a/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java
@@ -356,4 +356,43 @@ public class SaFoxUtil {
}
}
+ /**
+ * 将指定字符串按照逗号分隔符转化为字符串集合
+ * @param str 字符串
+ * @return 分割后的字符串集合
+ */
+ public static List convertStringToList(String str) {
+ List list = new ArrayList();
+ if(isEmpty(str)) {
+ return list;
+ }
+ String[] arr = str.split(",");
+ for (String s : arr) {
+ s = s.trim();
+ if(isEmpty(s) == false) {
+ list.add(s);
+ }
+ }
+ return list;
+ }
+
+ /**
+ * 将指定集合按照逗号连接成一个字符串
+ * @param list 集合
+ * @return 字符串
+ */
+ public static String convertListToString(List> list) {
+ if(list == null || list.size() == 0) {
+ return "";
+ }
+ String str = "";
+ for (int i = 0; i < list.size(); i++) {
+ str += list.get(i);
+ if(i != list.size() - 1) {
+ str += ",";
+ }
+ }
+ return str;
+ }
+
}
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/util/SaResult.java b/sa-token-core/src/main/java/cn/dev33/satoken/util/SaResult.java
index 6bfe2391..51222077 100644
--- a/sa-token-core/src/main/java/cn/dev33/satoken/util/SaResult.java
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/util/SaResult.java
@@ -1,67 +1,107 @@
package cn.dev33.satoken.util;
import java.io.Serializable;
-
+import java.util.LinkedHashMap;
+import java.util.Map;
/**
- * 对Ajax请求返回Json格式数据的简易封装
+ * 对Ajax请求返回Json格式数据的简易封装
+ * 所有预留字段:
+ * code=状态码
+ * msg=描述信息
+ * data=携带对象
* @author kong
*
*/
-public class SaResult implements Serializable{
+public class SaResult extends LinkedHashMap implements Serializable{
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 1L; // 序列化版本号
public static final int CODE_SUCCESS = 200;
public static final int CODE_ERROR = 500;
- /**
- * 状态码
- */
- public int code;
+ public SaResult(int code, String msg, Object data) {
+ this.setCode(code);
+ this.setMsg(msg);
+ this.setData(data);
+ }
/**
- * 描述信息
+ * 获取code
+ * @return code
*/
- public String msg;
-
+ public Integer getCode() {
+ return (Integer)this.get("code");
+ }
/**
- * 携带对象
+ * 获取msg
+ * @return msg
*/
- public Object data;
-
+ public String getMsg() {
+ return (String)this.get("msg");
+ }
+ /**
+ * 获取data
+ * @return data
+ */
+ public Object getData() {
+ return (Object)this.get("data");
+ }
+
/**
* 给code赋值,连缀风格
+ * @param code code
+ * @return 对象自身
*/
public SaResult setCode(int code) {
- this.code = code;
+ this.put("code", code);
return this;
}
-
/**
* 给msg赋值,连缀风格
+ * @param msg msg
+ * @return 对象自身
*/
public SaResult setMsg(String msg) {
- this.msg = msg;
+ this.put("msg", msg);
+ return this;
+ }
+ /**
+ * 给data赋值,连缀风格
+ * @param data data
+ * @return 对象自身
+ */
+ public SaResult setData(Object data) {
+ this.put("data", data);
return this;
}
/**
- * 给data赋值,连缀风格
+ * 写入一个值 自定义key, 连缀风格
+ * @param key key
+ * @param data data
+ * @return 对象自身
*/
- public SaResult setData(Object data) {
- this.data = data;
+ public SaResult set(String key, Object data) {
+ this.put(key, data);
return this;
}
- // ============================ 构建 ==================================
-
- public SaResult(int code, String msg, Object data) {
- this.code = code;
- this.msg = msg;
- this.data = data;
+ /**
+ * 写入一个Map, 连缀风格
+ * @param map map
+ * @return 对象自身
+ */
+ public SaResult setMap(Map map) {
+ for (String key : map.keySet()) {
+ this.put(key, map.get(key));
+ }
+ return this;
}
+
+ // ============================ 构建 ==================================
+
// 构建成功
public static SaResult ok() {
return new SaResult(CODE_SUCCESS, "ok", null);
@@ -93,9 +133,9 @@ public class SaResult implements Serializable{
@Override
public String toString() {
return "{"
- + "\"code\": " + this.code
- + ", \"msg\": \"" + this.msg + "\""
- + ", \"data\": \"" + this.data + "\""
+ + "\"code\": " + this.getCode()
+ + ", \"msg\": \"" + this.getMsg() + "\""
+ + ", \"data\": \"" + this.getData() + "\""
+ "}";
}
diff --git a/sa-token-demo/sa-token-demo-oauth2-client/pom.xml b/sa-token-demo/sa-token-demo-oauth2-client/pom.xml
index e2d6d24d..978d9856 100644
--- a/sa-token-demo/sa-token-demo-oauth2-client/pom.xml
+++ b/sa-token-demo/sa-token-demo-oauth2-client/pom.xml
@@ -22,26 +22,39 @@
-
+
org.springframework.boot
spring-boot-starter-web
-
+
cn.dev33
sa-token-spring-boot-starter
${sa-token-version}
+
+
+
+ org.springframework.boot
+ spring-boot-starter-thymeleaf
+
- com.ejlchina
- okhttps
- 2.4.5
+ com.ejlchina
+ okhttps
+ 3.1.1
-
+
+
+
+ org.springframework.boot
+ spring-boot-devtools
+ true
+
+
org.springframework.boot
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 1a10adcf..4853ef7b 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,8 +3,9 @@ package com.pj;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+
/**
- * 启动
+ * 启动:OAuth2-Client端
* @author kong
*/
@SpringBootApplication
@@ -12,7 +13,13 @@ public class SaOAuth2ClientApplication {
public static void main(String[] args) {
SpringApplication.run(SaOAuth2ClientApplication.class, args);
- System.out.println("\n客户端启动成功,访问: http://localhost:8002/login.html");
+ System.out.println("\nSa-Token-OAuth Client端启动成功\n\n" + str);
}
+
+ static String str = "首先在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" +
+ " http://sa-oauth-client.com:8002";
}
diff --git a/sa-token-demo/sa-token-demo-oauth2-client/src/main/java/com/pj/oauth2/SaOAuthClientController.java b/sa-token-demo/sa-token-demo-oauth2-client/src/main/java/com/pj/oauth2/SaOAuthClientController.java
new file mode 100644
index 00000000..e0cb545e
--- /dev/null
+++ b/sa-token-demo/sa-token-demo-oauth2-client/src/main/java/com/pj/oauth2/SaOAuthClientController.java
@@ -0,0 +1,188 @@
+package com.pj.oauth2;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.servlet.ModelAndView;
+
+import com.ejlchina.okhttps.OkHttps;
+import com.pj.utils.SoMap;
+
+import cn.dev33.satoken.stp.StpUtil;
+import cn.dev33.satoken.util.SaResult;
+
+/**
+ * Sa-OAuth2 Client端 控制器
+ * @author kong
+ */
+@RestController
+public class SaOAuthClientController {
+
+ // 相关参数配置
+ private String clientId = "1001"; // 应用id
+ private String clientSecret = "aaaa-bbbb-cccc-dddd-eeee"; // 应用秘钥
+ private String serverUrl = "http://sa-oauth-server.com:8001"; // 服务端接口
+
+ // 进入首页
+ @RequestMapping("/")
+ public Object index(HttpServletRequest request) {
+ request.setAttribute("uid", StpUtil.getLoginIdDefaultNull());
+ return new ModelAndView("index.html");
+ }
+
+ // 根据Code码进行登录,获取 Access-Token 和 openid
+ @RequestMapping("/codeLogin")
+ public SaResult codeLogin(String code) {
+ // 调用Server端接口,获取 Access-Token 以及其他信息
+ String str = OkHttps.sync(serverUrl + "/oauth2/token")
+ .addBodyPara("grant_type", "authorization_code")
+ .addBodyPara("code", code)
+ .addBodyPara("client_id", clientId)
+ .addBodyPara("client_secret", clientSecret)
+ .post()
+ .getBody()
+ .toString();
+ SoMap so = SoMap.getSoMap().setJsonString(str);
+ System.out.println("返回结果: " + so);
+
+ // code不等于200 代表请求失败
+ if(so.getInt("code") != 200) {
+ return SaResult.error(so.getString("msg"));
+ }
+
+ // 根据openid获取其对应的userId
+ SoMap data = so.getMap("data");
+ long uid = getUserIdByOpenid(data.getString("openid"));
+ data.set("uid", uid);
+
+ // 返回相关参数
+ StpUtil.login(uid);
+ return SaResult.data(data);
+ }
+
+ // 根据 Refresh-Token 去刷新 Access-Token
+ @RequestMapping("/refresh")
+ public SaResult refresh(String refreshToken) {
+ // 调用Server端接口,通过 Refresh-Token 刷新出一个新的 Access-Token
+ String str = OkHttps.sync(serverUrl + "/oauth2/refresh")
+ .addBodyPara("grant_type", "refresh_token")
+ .addBodyPara("client_id", clientId)
+ .addBodyPara("client_secret", clientSecret)
+ .addBodyPara("refresh_token", refreshToken)
+ .post()
+ .getBody()
+ .toString();
+ SoMap so = SoMap.getSoMap().setJsonString(str);
+ System.out.println("返回结果: " + so);
+
+ // code不等于200 代表请求失败
+ if(so.getInt("code") != 200) {
+ return SaResult.error(so.getString("msg"));
+ }
+
+ // 返回相关参数 (data=新的Access-Token )
+ SoMap data = so.getMap("data");
+ return SaResult.data(data);
+ }
+
+ // 模式三:密码式-授权登录
+ @RequestMapping("/passwordLogin")
+ public SaResult passwordLogin(String username, String password) {
+ // 模式三:密码式-授权登录
+ String str = OkHttps.sync(serverUrl + "/oauth2/token")
+ .addBodyPara("grant_type", "password")
+ .addBodyPara("client_id", clientId)
+ .addBodyPara("username", username)
+ .addBodyPara("password", password)
+ .post()
+ .getBody()
+ .toString();
+ SoMap so = SoMap.getSoMap().setJsonString(str);
+ System.out.println("返回结果: " + so);
+
+ // code不等于200 代表请求失败
+ if(so.getInt("code") != 200) {
+ return SaResult.error(so.getString("msg"));
+ }
+
+ // 根据openid获取其对应的userId
+ SoMap data = so.getMap("data");
+ long uid = getUserIdByOpenid(data.getString("openid"));
+ data.set("uid", uid);
+
+ // 返回相关参数
+ StpUtil.login(uid);
+ return SaResult.data(data);
+ }
+
+ // 模式四:获取应用的 Client-Token
+ @RequestMapping("/clientToken")
+ public SaResult clientToken() {
+ // 调用Server端接口
+ String str = OkHttps.sync(serverUrl + "/oauth2/client_token")
+ .addBodyPara("grant_type", "client_credentials")
+ .addBodyPara("client_id", clientId)
+ .addBodyPara("client_secret", clientSecret)
+ .post()
+ .getBody()
+ .toString();
+ SoMap so = SoMap.getSoMap().setJsonString(str);
+ System.out.println("返回结果: " + so);
+
+ // code不等于200 代表请求失败
+ if(so.getInt("code") != 200) {
+ return SaResult.error(so.getString("msg"));
+ }
+
+ // 返回相关参数 (data=新的Client-Token )
+ SoMap data = so.getMap("data");
+ return SaResult.data(data);
+ }
+
+ // 注销登录
+ @RequestMapping("/logout")
+ public SaResult logout() {
+ StpUtil.logout();
+ return SaResult.ok();
+ }
+
+ // 根据 Access-Token 置换相关的资源: 获取账号昵称、头像、性别等信息
+ @RequestMapping("/getUserinfo")
+ public SaResult getUserinfo(String accessToken) {
+ // 调用Server端接口,查询开放的资源
+ String str = OkHttps.sync(serverUrl + "/oauth2/userinfo")
+ .addBodyPara("access_token", accessToken)
+ .post()
+ .getBody()
+ .toString();
+ SoMap so = SoMap.getSoMap().setJsonString(str);
+ System.out.println("返回结果: " + so);
+
+ // code不等于200 代表请求失败
+ if(so.getInt("code") != 200) {
+ return SaResult.error(so.getString("msg"));
+ }
+
+ // 返回相关参数 (data=获取到的资源 )
+ SoMap data = so.getMap("data");
+ return SaResult.data(data);
+ }
+
+ // 全局异常拦截
+ @ExceptionHandler
+ public SaResult handlerException(Exception e) {
+ e.printStackTrace();
+ return SaResult.error(e.getMessage());
+ }
+
+
+ // ------------ 模拟方法 ------------------
+ // 模拟方法:根据openid获取userId
+ private long getUserIdByOpenid(String openid) {
+ // 此方法仅做模拟,实际开发要根据具体业务逻辑来获取userId
+ return 10001;
+ }
+
+}
diff --git a/sa-token-demo/sa-token-demo-oauth2-client/src/main/java/com/pj/utils/SoMap.java b/sa-token-demo/sa-token-demo-oauth2-client/src/main/java/com/pj/utils/SoMap.java
index e4524216..5258a6d3 100644
--- a/sa-token-demo/sa-token-demo-oauth2-client/src/main/java/com/pj/utils/SoMap.java
+++ b/sa-token-demo/sa-token-demo-oauth2-client/src/main/java/com/pj/utils/SoMap.java
@@ -33,12 +33,10 @@ public class SoMap extends LinkedHashMap {
public SoMap() {
}
-
/** 以下元素会在isNull函数中被判定为Null, */
public static final Object[] NULL_ELEMENT_ARRAY = {null, ""};
public static final List
+
+
+
+
+
+
diff --git a/sa-token-demo/sa-token-demo-springboot/pom.xml b/sa-token-demo/sa-token-demo-springboot/pom.xml
index 10585bd6..259ffcfa 100644
--- a/sa-token-demo/sa-token-demo-springboot/pom.xml
+++ b/sa-token-demo/sa-token-demo-springboot/pom.xml
@@ -79,7 +79,6 @@
5.5.4
-->
-
diff --git a/sa-token-demo/sa-token-demo-webflux/src/main/java/com/pj/SaTokenWebfluxDemoApplication.java b/sa-token-demo/sa-token-demo-webflux/src/main/java/com/pj/SaTokenWebfluxDemoApplication.java
index 783c0e8e..330a23ec 100644
--- a/sa-token-demo/sa-token-demo-webflux/src/main/java/com/pj/SaTokenWebfluxDemoApplication.java
+++ b/sa-token-demo/sa-token-demo-webflux/src/main/java/com/pj/SaTokenWebfluxDemoApplication.java
@@ -1,16 +1,5 @@
package com.pj;
-//import org.springframework.boot.SpringApplication;
-//import org.springframework.boot.autoconfigure.SpringBootApplication;
-//import org.springframework.context.annotation.Bean;
-//import org.springframework.http.MediaType;
-//import org.springframework.web.reactive.function.server.RequestPredicates;
-//import org.springframework.web.reactive.function.server.RouterFunction;
-//import org.springframework.web.reactive.function.server.RouterFunctions;
-//import org.springframework.web.reactive.function.server.ServerRequest;
-//import org.springframework.web.reactive.function.server.ServerResponse;
-
-
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
diff --git a/sa-token-doc/doc/more/tj-gzh.md b/sa-token-doc/doc/more/tj-gzh.md
index f5a55801..f2f83656 100644
--- a/sa-token-doc/doc/more/tj-gzh.md
+++ b/sa-token-doc/doc/more/tj-gzh.md
@@ -7,6 +7,36 @@
+
+
+ 终码一生
+ 分享Java开发技术(JVM,多线程,高并发,性能调优)
+ |
+
+
+ CodeSheep
+ 一只爱技术的程序羊,想把分享变成一种习惯!
+ |
+ - |
+ - |
+ - |
+
+
+
+
+ Java开发宝典
+ 分享Java基础、Java框架、数据库、微服务、中间件、分布式、架构等技术干货
+ |
+
+
+ MarkerHub
+ 专注于梳理java知识,解析开源项目。
+ |
+
+
+ 架构师必备
+ 分享干货文章,做一个有逼格的架构师社区!
+ |
Github导航站
@@ -17,9 +47,6 @@
Java爱好者
分享Java开发编程资源和Java技术文章
|
- - |
- - |
- - |
|
diff --git a/sa-token-doc/doc/plugin/alone-redis.md b/sa-token-doc/doc/plugin/alone-redis.md
index d2d88ef5..9dd817c3 100644
--- a/sa-token-doc/doc/plugin/alone-redis.md
+++ b/sa-token-doc/doc/plugin/alone-redis.md
@@ -45,19 +45,23 @@ sa-token:
password:
# 连接超时时间(毫秒)
timeout: 10ms
- lettuce:
- pool:
- # 连接池最大连接数
- max-active: 200
- # 连接池最大阻塞等待时间(使用负值表示没有限制)
- max-wait: -1ms
- # 连接池中的最大空闲连接
- max-idle: 10
- # 连接池中的最小空闲连接
- min-idle: 0
+
+spring:
+ # 配置业务使用的Redis连接
+ redis:
+ # Redis数据库索引(默认为0)
+ database: 0
+ # Redis服务器地址
+ host: 127.0.0.1
+ # Redis服务器连接端口
+ port: 6379
+ # Redis服务器连接密码(默认为空)
+ password:
+ # 连接超时时间(毫秒)
+ timeout: 10ms
```
-具体可参考:[码云:application.yml](https://gitee.com/dromara/sa-token/blob/dev/sa-token-demo/sa-token-demo-alone-redis/src/main/resources/application.yml)
+具体可参考示例:[码云:application.yml](https://gitee.com/dromara/sa-token/blob/dev/sa-token-demo/sa-token-demo-alone-redis/src/main/resources/application.yml)
### 3、测试
diff --git a/sa-token-doc/doc/use/dao-extend.md b/sa-token-doc/doc/use/dao-extend.md
index f66e27a0..18c8097d 100644
--- a/sa-token-doc/doc/use/dao-extend.md
+++ b/sa-token-doc/doc/use/dao-extend.md
@@ -84,5 +84,4 @@ spring:
更多框架的集成方案正在更新中... (欢迎大家提交pr)
-?> SerializationException序列化异常, 如果你在集成redis的时候遇到这个报错不要紧张, 下面说一下可能的原因
-?> 当你第一次使用redis的时候默认是可以的运行的, 但是切换到另一种序列化方式后就报错了, 这是因为默认SaToken会直接读取之前存储的数据, 以jackson方式读取jdk默认序列化的内容或者反过来读取都会导致读取失败. 此时只需要删除与SaToken相关的redis数据就好了
+
diff --git a/sa-token-doc/doc/use/kick.md b/sa-token-doc/doc/use/kick.md
index ac265373..db0b611e 100644
--- a/sa-token-doc/doc/use/kick.md
+++ b/sa-token-doc/doc/use/kick.md
@@ -51,6 +51,6 @@ StpUtil.untieDisable(10001);
// 先踢下线
StpUtil.logoutByLoginId(10001);
// 再封禁账号
-StpUtil.disable(10001, 86400);
+StpUtil.disableLoginId(10001, 86400);
```
diff --git a/sa-token-doc/doc/use/login-auth.md b/sa-token-doc/doc/use/login-auth.md
index e002a165..8e8a9f43 100644
--- a/sa-token-doc/doc/use/login-auth.md
+++ b/sa-token-doc/doc/use/login-auth.md
@@ -67,7 +67,4 @@ StpUtil.getTokenInfo();
?> 有关TokenInfo参数详解,请参考:[参考:TokenInfo参数详解](/fun/token-info)
-?> Stpuitl依赖的是当前的线程上下文,不支持多线程异步调用
-?> 开发者传到其它的异步方法里面,需要先将必要参数取出来,否则这一块的数据会丢失的
-
diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/SaOAuth2Manager.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/SaOAuth2Manager.java
index 8c153d21..2ad2854b 100644
--- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/SaOAuth2Manager.java
+++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/SaOAuth2Manager.java
@@ -3,7 +3,7 @@ package cn.dev33.satoken.oauth2;
import cn.dev33.satoken.oauth2.config.SaOAuth2Config;
/**
- * sa-token oauth2 模块 总控类
+ * Sa-Token-OAuth2 模块 总控类
*
* @author kong
*
diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/config/SaOAuth2Config.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/config/SaOAuth2Config.java
index de245b7c..06ecd72a 100644
--- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/config/SaOAuth2Config.java
+++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/config/SaOAuth2Config.java
@@ -1,40 +1,118 @@
package cn.dev33.satoken.oauth2.config;
+import java.io.Serializable;
import java.util.function.BiFunction;
-import java.util.function.Function;
import java.util.function.Supplier;
-import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.util.SaResult;
/**
- * sa-token oauth2 配置类 Model
+ * Sa-Token-OAuth2 配置类 Model
* @author kong
*
*/
-public class SaOAuth2Config {
+public class SaOAuth2Config implements Serializable {
- /**
- * 授权码默认保存的时间(单位秒) 默认五分钟
- */
- private long codeTimeout = 60 * 5;
+ private static final long serialVersionUID = -6541180061782004705L;
- /**
- * access_token默认保存的时间(单位秒) 默认两个小时
- */
- private long accessTokenTimeout = 60 * 60 * 2;
+ /** 是否打开模式:授权码(Authorization Code) */
+ public Boolean isCode = true;
- /**
- * refresh_token默认保存的时间(单位秒) 默认30 天
- */
- private long refreshTokenTimeout = 60 * 60 * 24 * 30;
+ /** 是否打开模式:隐藏式(Implicit) */
+ public Boolean isImplicit = false;
- /**
- * client_token默认保存的时间(单位秒) 默认两个小时
- */
- private long clientTokenTimeout = 60 * 60 * 2;
+ /** 是否打开模式:密码式(Password) */
+ public Boolean isPassword = false;
+ /** 是否打开模式:凭证式(Client Credentials) */
+ public Boolean isClient = false;
+
+ /** 是否在每次 Refresh-Token 刷新 Access-Token 时,产生一个新的 Refresh-Token */
+ public Boolean isNewRefresh = false;
+ /** Code授权码 保存的时间(单位秒) 默认五分钟 */
+ public long codeTimeout = 60 * 5;
+
+ /** Access-Token 保存的时间(单位秒) 默认两个小时 */
+ public long accessTokenTimeout = 60 * 60 * 2;
+
+ /** Refresh-Token 保存的时间(单位秒) 默认30 天 */
+ public long refreshTokenTimeout = 60 * 60 * 24 * 30;
+
+ /** Client-Token 保存的时间(单位秒) 默认两个小时 */
+ public long clientTokenTimeout = 60 * 60 * 2;
+
+
+ /**
+ * @return isCode
+ */
+ public Boolean getIsCode() {
+ return isCode;
+ }
+
+ /**
+ * @param isCode 要设置的 isCode
+ */
+ public void setIsCode(Boolean isCode) {
+ this.isCode = isCode;
+ }
+
+ /**
+ * @return isImplicit
+ */
+ public Boolean getIsImplicit() {
+ return isImplicit;
+ }
+
+ /**
+ * @param isImplicit 要设置的 isImplicit
+ */
+ public void setIsImplicit(Boolean isImplicit) {
+ this.isImplicit = isImplicit;
+ }
+
+ /**
+ * @return isPassword
+ */
+ public Boolean getIsPassword() {
+ return isPassword;
+ }
+
+ /**
+ * @param isPassword 要设置的 isPassword
+ */
+ public void setIsPassword(Boolean isPassword) {
+ this.isPassword = isPassword;
+ }
+
+ /**
+ * @return isClient
+ */
+ public Boolean getIsClient() {
+ return isClient;
+ }
+
+ /**
+ * @param isClient 要设置的 isClient
+ */
+ public void setIsClient(Boolean isClient) {
+ this.isClient = isClient;
+ }
+
+ /**
+ * @return isNewRefresh
+ */
+ public Boolean getIsNewRefresh() {
+ return isNewRefresh;
+ }
+
+ /**
+ * @param isNewRefresh 要设置的 isNewRefresh
+ */
+ public void setIsNewRefresh(Boolean isNewRefresh) {
+ this.isNewRefresh = isNewRefresh;
+ }
+
/**
* @return codeTimeout
*/
@@ -100,26 +178,13 @@ public class SaOAuth2Config {
}
-
-
// -------------------- SaOAuth2Handle 所有回调函数 --------------------
-
/**
* OAuth-Server端:未登录时返回的View
*/
public Supplier notLoginView = () -> "当前会话在OAuth-Server认证中心尚未登录";
- /**
- * OAuth-Server端:重定向URL无效时返回的View
- */
- public BiFunction invalidUrlView = (clientId, url) -> "无效重定向URL:" + url;
-
- /**
- * OAuth-Server端:Client请求的Scope暂未签约时返回的View
- */
- public BiFunction invalidScopeView = (clientId, scope) -> "请求的Scope暂未签约";
-
/**
* OAuth-Server端:确认授权时返回的View
*/
@@ -130,12 +195,6 @@ public class SaOAuth2Config {
*/
public BiFunction doLoginHandle = (name, pwd) -> SaResult.error();
- /**
- * SSO-Client端:发送Http请求的处理函数
- */
- public Function sendHttp = url -> {throw new SaTokenException("请配置Http处理器");};
-
-
/**
* @param notLoginView OAuth-Server端:未登录时返回的View
* @return 对象自身
@@ -145,24 +204,6 @@ public class SaOAuth2Config {
return this;
}
- /**
- * @param invalidScopeView OAuth-Server端:重定向URL无效时返回的View
- * @return 对象自身
- */
- public SaOAuth2Config setInvalidUrlView(BiFunction invalidUrlView) {
- this.invalidUrlView = invalidUrlView;
- return this;
- }
-
- /**
- * @param invalidScopeView OAuth-Server端:Client请求的Scope暂未签约时返回的View
- * @return 对象自身
- */
- public SaOAuth2Config setInvalidScopeView(BiFunction invalidScopeView) {
- this.invalidScopeView = invalidScopeView;
- return this;
- }
-
/**
* @param confirmView OAuth-Server端:确认授权时返回的View
* @return 对象自身
@@ -181,23 +222,13 @@ public class SaOAuth2Config {
return this;
}
- /**
- * @param sendHttp 发送Http请求的处理函数
- * @return 对象自身
- */
- public SaOAuth2Config setSendHttp(Function sendHttp) {
- this.sendHttp = sendHttp;
- return this;
- }
-
-
-
-
@Override
public String toString() {
- return "SaOAuth2Config [codeTimeout=" + codeTimeout + ", accessTokenTimeout=" + accessTokenTimeout
- + ", refreshTokenTimeout=" + refreshTokenTimeout + "]";
+ return "SaOAuth2Config [isCode=" + isCode + ", isImplicit=" + isImplicit + ", isPassword=" + isPassword
+ + ", isClient=" + isClient + ", isNewRefresh=" + isNewRefresh + ", codeTimeout=" + codeTimeout
+ + ", accessTokenTimeout=" + accessTokenTimeout + ", refreshTokenTimeout=" + refreshTokenTimeout
+ + ", clientTokenTimeout=" + clientTokenTimeout + "]";
}
-
+
}
diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Consts.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Consts.java
index 5848513f..f84082c6 100644
--- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Consts.java
+++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Consts.java
@@ -12,10 +12,12 @@ public class SaOAuth2Consts {
* @author kong
*/
public static final class Api {
-
- /** OAuth-Server端:授权地址 */
public static String authorize = "/oauth2/authorize";
-
+ public static String token = "/oauth2/token";
+ public static String refresh = "/oauth2/refresh";
+ public static String client_token = "/oauth2/client_token";
+ public static String doLogin = "/oauth2/doLogin";
+ public static String doConfirm = "/oauth2/doConfirm";
}
/**
@@ -23,70 +25,44 @@ public class SaOAuth2Consts {
* @author kong
*/
public static final class Param {
-
- /** authorize 的 返回值类型 */
public static String response_type = "response_type";
-
- /** client_id 参数名称 */
public static String client_id = "client_id";
-
- /** client_secret 参数名称 */
public static String client_secret = "client_secret";
-
- /** redirect_uri 参数名称 */
public static String redirect_uri = "redirect_uri";
-
- /** scope 参数名称 */
public static String scope = "scope";
-
- /** state */
public static String state = "state";
-
- /** code 参数名称 */
public static String code = "code";
-
- /** token 参数名称 */
public static String token = "token";
-
- /** grant_type 参数名称 */
+ public static String refresh_token = "refresh_token";
public static String grant_type = "grant_type";
-
+ public static String username = "username";
+ public static String password = "password";
+ public static String name = "name";
+ public static String pwd = "pwd";
+ }
+
+ /**
+ * 所有返回类型
+ */
+ public static final class ResponseType {
+ public static String code = "code";
+ public static String token = "token";
}
/**
* 所有授权类型
*/
- public static final class AuthType {
-
- /** 方式一:授权码 */
- public static String code = "code";
-
- /** 方式二:隐藏式 */
- public static String token = "token";
-
- /** 方式三:密码式 */
- public static String password = "password";
-
- /** 方式四:凭证式 */
- public static String client_credentials = "client_credentials";
-
+ public static final class GrantType {
public static String authorization_code = "authorization_code";
-
+ public static String refresh_token = "refresh_token";
+ public static String password = "password";
+ public static String client_credentials = "client_credentials";
}
-
-
- /**
- * 在保存授权码时用到的key
- */
- public static final String UNLIMITED_DOMAIN = "*";
-
-
/** 表示OK的返回结果 */
public static final String OK = "ok";
- /** 表示请求没有得到任何有效处理 */
- public static final String NOT_HANDLE = "not handle";
-
+ /** 表示请求没有得到任何有效处理 {msg: "not handle"} */
+ public static final String NOT_HANDLE = "{\"msg\": \"not handle\"}";
}
diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Handle.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Handle.java
index 6e915100..b3a15106 100644
--- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Handle.java
+++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Handle.java
@@ -5,12 +5,15 @@ import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
import cn.dev33.satoken.oauth2.config.SaOAuth2Config;
-import cn.dev33.satoken.oauth2.logic.SaOAuth2Consts.AuthType;
+import cn.dev33.satoken.oauth2.exception.SaOAuth2Exception;
+import cn.dev33.satoken.oauth2.logic.SaOAuth2Consts.Api;
+import cn.dev33.satoken.oauth2.logic.SaOAuth2Consts.GrantType;
import cn.dev33.satoken.oauth2.logic.SaOAuth2Consts.Param;
+import cn.dev33.satoken.oauth2.logic.SaOAuth2Consts.ResponseType;
import cn.dev33.satoken.oauth2.model.AccessTokenModel;
+import cn.dev33.satoken.oauth2.model.ClientTokenModel;
import cn.dev33.satoken.oauth2.model.CodeModel;
import cn.dev33.satoken.oauth2.model.RequestAuthModel;
-import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
@@ -20,106 +23,236 @@ import cn.dev33.satoken.util.SaResult;
*
*/
public class SaOAuth2Handle {
-
+
/**
- * 处理Server端请求
+ * 处理Server端请求, 路由分发
* @return 处理结果
*/
- public static Object authorize() {
+ public static Object serverRequest() {
// 获取变量
SaRequest req = SaHolder.getRequest();
SaResponse res = SaHolder.getResponse();
SaOAuth2Config cfg = SaOAuth2Manager.getConfig();
- // StpLogic stpLogic = SaSsoUtil.saSsoTemplate.stpLogic;
- // match(Api.authorize) &&
- // 授权
- if(req.isParam(Param.response_type, AuthType.code)) {
- // 1、构建请求Model TODO: 貌似这个RequestAuthModel对象也可以省略掉
- RequestAuthModel ra = SaOAuth2Util.generateRequestAuth(req, StpUtil.getLoginId());
-
- // 2、如果尚未登录, 则先去登录
- if(StpUtil.isLogin() == false) {
- return cfg.notLoginView.get();
- }
-
- // 3、判断:重定向域名的格式是否合法
- boolean isRigh = SaOAuth2Util.isRightUrl(ra.clientId, ra.redirectUri);
- if(isRigh == false) {
- return cfg.invalidUrlView.apply(ra.clientId, ra.redirectUri);
- }
-
- // 4、判断:此次申请的Scope,该Client是否已经签约
- boolean isContract = SaOAuth2Util.isContract(ra.clientId, ra.scope);
- if(isContract == false) {
- return cfg.invalidScopeView.apply(ra.clientId, ra.scope);
- }
-
- // 5、判断:此次申请的Scope,该用户是否已经授权过了
- boolean isGrant = SaOAuth2Util.isGrant(StpUtil.getLoginId(), ra.clientId, ra.scope);
- if(isGrant == false) {
- // 如果尚未授权,则转到授权页面,开始授权操作
- return cfg.confirmView.apply(ra.clientId, ra.scope);
- }
+ // ------------------ 路由分发 ------------------
+
+ // 模式一:Code授权码
+ if(req.isPath(Api.authorize) && req.isParam(Param.response_type, ResponseType.code) && cfg.isCode) {
+ return authorize(req, res, cfg);
+ }
- // 6、开始重定向授权,下放code
+ // Code授权码 获取 Access-Token
+ if(req.isPath(Api.token) && req.isParam(Param.grant_type, GrantType.authorization_code)) {
+ return token(req, res, cfg);
+ }
+
+ // Refresh-Token 刷新 Access-Token
+ if(req.isPath(Api.refresh) && req.isParam(Param.grant_type, GrantType.refresh_token)) {
+ return refreshToken(req);
+ }
+
+ // doLogin 登录接口
+ if(req.isPath(Api.doLogin)) {
+ return doLogin(req, res, cfg);
+ }
+
+ // doConfirm 确认授权接口
+ if(req.isPath(Api.doConfirm)) {
+ return doConfirm(req);
+ }
+
+ // 模式二:隐藏式
+ if(req.isPath(Api.authorize) && req.isParam(Param.response_type, ResponseType.token) && cfg.isImplicit) {
+ return authorize(req, res, cfg);
+ }
+
+ // 模式三:密码式
+ if(req.isPath(Api.token) && req.isParam(Param.grant_type, GrantType.password) && cfg.isPassword) {
+ return password(req, res, cfg);
+ }
+
+ // 模式四:凭证式
+ if(req.isPath(Api.client_token) && req.isParam(Param.grant_type, GrantType.client_credentials) && cfg.isClient) {
+ return clientToken(req, res, cfg);
+ }
+
+ // 默认返回
+ return SaOAuth2Consts.NOT_HANDLE;
+ }
+
+ /**
+ * 模式一:Code授权码 / 模式二:隐藏式
+ * @param req 请求对象
+ * @param res 响应对象
+ * @param cfg 配置对象
+ * @return 处理结果
+ */
+ public static Object authorize(SaRequest req, SaResponse res, SaOAuth2Config cfg) {
+
+ // 1、如果尚未登录, 则先去登录
+ if(StpUtil.isLogin() == false) {
+ return cfg.notLoginView.get();
+ }
+
+ // 2、构建请求Model
+ RequestAuthModel ra = SaOAuth2Util.generateRequestAuth(req, StpUtil.getLoginId());
+
+ // 3、校验:重定向域名是否合法
+ SaOAuth2Util.checkRightUrl(ra.clientId, ra.redirectUri);
+
+ // 4、校验:此次申请的Scope,该Client是否已经签约
+ SaOAuth2Util.checkContract(ra.clientId, ra.scope);
+
+ // 5、判断:如果此次申请的Scope,该用户尚未授权,则转到授权页面
+ boolean isGrant = SaOAuth2Util.isGrant(ra.loginId, ra.clientId, ra.scope);
+ if(isGrant == false) {
+ return cfg.confirmView.apply(ra.clientId, ra.scope);
+ }
+
+ // 6、判断授权类型
+ // 如果是 授权码式,则:开始重定向授权,下放code
+ if(ResponseType.code.equals(ra.responseType)) {
CodeModel codeModel = SaOAuth2Util.generateCode(ra);
String redirectUri = SaOAuth2Util.buildRedirectUri(ra.redirectUri, codeModel.code, ra.state);
return res.redirect(redirectUri);
}
-
-
-
-
- // 默认返回
- return SaOAuth2Consts.NOT_HANDLE;
- }
-
- /**
- * 获取Token
- * @return
- */
- public static Object token() {
-
- // 获取变量
- SaRequest req = SaHolder.getRequest();
- // SaResponse res = SaHolder.getResponse();
- // SaOAuth2Config cfg = SaOAuth2Manager.getConfig();
-
- // 根据code换token
- if(req.isParam(Param.grant_type, AuthType.authorization_code)) {
- System.out.println("------------获取token,,,");
-
- // 获取参数
- String code = req.getParamNotNull(Param.code); // code码
- String clientId = req.getParamNotNull(Param.client_id); // 应用id
- String clientSecret = req.getParamNotNull(Param.client_secret); // 应用秘钥
- String redirectUri = req.getParam(Param.redirect_uri); // 应用秘钥
-
- // 校验参数
- SaOAuth2Util.checkCodeIdSecret(code, clientId, clientSecret, redirectUri);
-
- // 构建 access_token
- AccessTokenModel token = SaOAuth2Util.generateAccessToken(code);
-
- // 返回
- return SaResult.data(token.toLineMap());
+ // 如果是 隐藏式,则:开始重定向授权,下放 token
+ if(ResponseType.token.equals(ra.responseType)) {
+ AccessTokenModel at = SaOAuth2Util.generateAccessToken(ra, false);
+ String redirectUri = SaOAuth2Util.buildImplicitRedirectUri(ra.redirectUri, at.accessToken, ra.state);
+ return res.redirect(redirectUri);
}
// 默认返回
- return SaOAuth2Consts.NOT_HANDLE;
+ throw new SaOAuth2Exception("无效response_type: " + ra.responseType);
}
-
-
+ /**
+ * Code授权码 获取 Access-Token
+ * @param req 请求对象
+ * @param res 响应对象
+ * @param cfg 配置对象
+ * @return 处理结果
+ */
+ public static Object token(SaRequest req, SaResponse res, SaOAuth2Config cfg) {
+ // 获取参数
+ String code = req.getParamNotNull(Param.code);
+ String clientId = req.getParamNotNull(Param.client_id);
+ String clientSecret = req.getParamNotNull(Param.client_secret);
+ String redirectUri = req.getParam(Param.redirect_uri);
+
+ // 校验参数
+ SaOAuth2Util.checkGainTokenParam(code, clientId, clientSecret, redirectUri);
+
+ // 构建 Access-Token
+ AccessTokenModel token = SaOAuth2Util.generateAccessToken(code);
+
+ // 返回
+ return SaResult.data(token.toLineMap());
+ }
/**
- * 路由匹配算法
- * @param pattern 路由表达式
- * @return 是否可以匹配
+ * Refresh-Token 刷新 Access-Token
+ * @param req 请求对象
+ * @return 处理结果
*/
- static boolean match(String pattern) {
- return SaRouter.isMatch(pattern, SaHolder.getRequest().getRequestPath());
+ public static Object refreshToken(SaRequest req) {
+ // 获取参数
+ String clientId = req.getParamNotNull(Param.client_id);
+ String clientSecret = req.getParamNotNull(Param.client_secret);
+ String refreshToken = req.getParamNotNull(Param.refresh_token);
+
+ // 校验参数
+ SaOAuth2Util.checkRefreshTokenParam(clientId, clientSecret, refreshToken);
+
+ // 获取新Token返回
+ Object data = SaOAuth2Util.saOAuth2Template.refreshAccessToken(refreshToken).toLineMap();
+ return SaResult.data(data);
}
+
+ /**
+ * doLogin 登录接口
+ * @param req 请求对象
+ * @param res 响应对象
+ * @param cfg 配置对象
+ * @return 处理结果
+ */
+ public static Object doLogin(SaRequest req, SaResponse res, SaOAuth2Config cfg) {
+ return cfg.doLoginHandle.apply(req.getParamNotNull(Param.name), req.getParamNotNull("pwd"));
+ }
+
+ /**
+ * doConfirm 确认授权接口
+ * @param req 请求对象
+ * @return 处理结果
+ */
+ public static Object doConfirm(SaRequest req) {
+ String clientId = req.getParamNotNull(Param.client_id);
+ String scope = req.getParamNotNull(Param.scope);
+ Object loginId = StpUtil.getLoginId();
+ SaOAuth2Util.saveGrantScope(clientId, loginId, scope);
+ return SaResult.ok();
+ }
+
+ /**
+ * 模式三:密码式
+ * @param req 请求对象
+ * @param res 响应对象
+ * @param cfg 配置对象
+ * @return 处理结果
+ */
+ public static Object password(SaRequest req, SaResponse res, SaOAuth2Config cfg) {
+
+ // 1、获取请求参数
+ String username = req.getParamNotNull(Param.username);
+ String password = req.getParamNotNull(Param.password);
+ String clientId = req.getParamNotNull(Param.client_id);
+
+ // 2、校验client_id
+ SaOAuth2Util.checkClientModel(clientId);
+
+ // 3、防止因前端误传token造成逻辑干扰
+ SaHolder.getStorage().set(StpUtil.stpLogic.splicingKeyJustCreatedSave(), "no-token");
+
+ // 4、调用API 开始登录,如果没能成功登录,则直接退出
+ Object retObj = cfg.doLoginHandle.apply(username, password);
+ if(StpUtil.isLogin() == false) {
+ return retObj;
+ }
+
+ // 5、构建 ra对象
+ RequestAuthModel ra = new RequestAuthModel();
+ ra.clientId = clientId;
+ ra.loginId = StpUtil.getLoginId();
+ ra.scope = req.getParam(Param.scope, "");
+
+ // 6、生成 Access-Token
+ AccessTokenModel at = SaOAuth2Util.generateAccessToken(ra, true);
+
+ // 7、返回 Access-Token
+ return SaResult.data(at.toLineMap());
+ }
+
+ /**
+ * 模式四:凭证式
+ * @return 处理结果
+ */
+ public static Object clientToken(SaRequest req, SaResponse res, SaOAuth2Config cfg) {
+
+ // 获取参数
+ String clientId = req.getParamNotNull(Param.client_id);
+ String clientSecret = req.getParamNotNull(Param.client_secret);
+ String scope = req.getParam(Param.scope);
+
+ // 校验 ClientSecret
+ SaOAuth2Util.checkClientSecret(clientId, clientSecret);
+
+ // 返回 Client-Token
+ ClientTokenModel ct = SaOAuth2Util.generateClientToken(clientId, scope);
+
+ // 返回 Client-Token
+ return SaResult.data(ct.toLineMap());
+ }
+
}
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 e01251da..ed97b8a2 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
@@ -1,12 +1,9 @@
package cn.dev33.satoken.oauth2.logic;
-import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.context.model.SaRequest;
-import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
import cn.dev33.satoken.oauth2.exception.SaOAuth2Exception;
import cn.dev33.satoken.oauth2.logic.SaOAuth2Consts.Param;
@@ -15,65 +12,27 @@ import cn.dev33.satoken.oauth2.model.ClientTokenModel;
import cn.dev33.satoken.oauth2.model.CodeModel;
import cn.dev33.satoken.oauth2.model.RefreshTokenModel;
import cn.dev33.satoken.oauth2.model.RequestAuthModel;
+import cn.dev33.satoken.oauth2.model.SaClientModel;
import cn.dev33.satoken.util.SaFoxUtil;
/**
- * sa-token-oauth2 模块 逻辑接口
+ * Sa-Token-OAuth2 模块 代码实现
* @author kong
*
*/
public class SaOAuth2Template {
- // ------------------- 获取数据
+ // ------------------- 获取数据 (开发者必须重写的函数)
/**
- * 返回此平台所有权限集合
- * @return 此平台所有权限名称集合
+ * 根据id获取Client信息
+ * @param clientId 应用id
+ * @return ClientModel
*/
- public List getAppScopeList() {
- return Arrays.asList("userinfo");
- }
-
- /**
- * 返回指定Client签约的所有Scope名称集合
- * @param clientId 应用id
- * @return Scope集合
- */
- public List getClientScopeList(String clientId) {
- // 默认返回此APP的所有权限
- return getAppScopeList();
- }
-
- /**
- * [转Redis]获取指定 LoginId 对指定 Client 已经授权过的所有 Scope
- * @param clientId 应用id
- * @param loginId 账号id
- * @return Scope集合
- */
- public List getGrantScopeList(Object loginId, String clientId) {
- // 默认返回空集合
- return Arrays.asList();
- }
-
- /**
- * 返回指定Client允许的回调域名, 多个用逗号隔开, *代表不限制
- * @param clientId 应用id
- * @return domain集合
- */
- public String getClientDomain(String clientId) {
- return "*";
- }
-
- /**
- * 返回指定ClientId的ClientSecret
- * @param clientId 应用id
- * @return 此应用的秘钥
- */
- public String getClientSecret(String clientId) {
+ public SaClientModel getClientModel(String clientId) {
return null;
}
-
/**
- * 根据ClientId和LoginId返回openid
+ * 根据ClientId 和 LoginId 获取openid
* @param clientId 应用id
* @param loginId 账号id
* @return 此账号在此Client下的openid
@@ -81,86 +40,52 @@ public class SaOAuth2Template {
public String getOpenid(String clientId, Object loginId) {
return null;
}
-
+
+ // ------------------- 资源获取
/**
- * [可取消]根据ClientId和openid返回LoginId
- * @param clientId 应用id
- * @param openid openid
+ * 根据id获取Client信息, 如果Client为空,则抛出异常
+ * @param clientId 应用id
+ * @return ClientModel
+ */
+ public SaClientModel checkClientModel(String clientId) {
+ SaClientModel clientModel = getClientModel(clientId);
+ if(clientModel == null) {
+ throw new SaOAuth2Exception("无效client_id: " + clientId);
+ }
+ return clientModel;
+ }
+ /**
+ * 获取 access_token 所代表的LoginId
+ * @param accessToken access_token
* @return LoginId
*/
- public Object getLoginId(String clientId, String openid) {
- return null;
+ public Object getLoginIdByAccessToken(String accessToken) {
+ return checkAccessToken(accessToken).loginId;
}
-
- // ------------------- conver 数据转换
/**
- * [OK] 将 CodeModel 转换为 AccessTokenModel
- * @param cm CodeModel对象
- * @return AccessToken对象
+ * 获取 Access-Token,如果AccessToken为空则抛出异常
+ * @param accessToken .
+ * @return .
*/
- public AccessTokenModel converCodeToAccessToken(CodeModel cm) {
- AccessTokenModel at = new AccessTokenModel();
- at.accessToken = randomAccessToken(cm.clientId, cm.loginId, cm.scope);
- at.refreshToken = randomRefreshToken(cm.clientId, cm.loginId, cm.scope);
- at.clientId = cm.clientId;
- at.loginId = cm.loginId;
- at.scope = cm.scope;
- at.openid = getOpenid(cm.clientId, cm.loginId);
- at.expiresTime = System.currentTimeMillis() + (SaOAuth2Manager.getConfig().getAccessTokenTimeout() * 1000);
- // at.refreshExpiresTime = System.currentTimeMillis() + (SaOAuth2Manager.getConfig().getRefreshTokenTimeout() * 1000);
+ public AccessTokenModel checkAccessToken(String accessToken) {
+ AccessTokenModel at = getAccessToken(accessToken);
+ SaOAuth2Exception.throwBy(at == null, "无效:access_token" + accessToken);
return at;
}
/**
- * [OK] 将 AccessToken 转换为 RefreshTokenModel
- * @param at AccessToken对象
- * @return RefreshToken对象
+ * 获取 Client-Token,如果ClientToken为空则抛出异常
+ * @param clientToken .
+ * @return .
*/
- public RefreshTokenModel converAccessTokenToRefreshToken(AccessTokenModel at) {
- RefreshTokenModel rt = new RefreshTokenModel();
- rt.refreshToken = at.refreshToken;
- rt.clientId = at.clientId;
- rt.loginId = at.loginId;
- rt.scope = at.scope;
- rt.openid = at.openid;
- rt.expiresTime = System.currentTimeMillis() + (SaOAuth2Manager.getConfig().getRefreshTokenTimeout() * 1000);
- return rt;
- }
- /**
- * [OK] 将 RefreshTokenModel 转换为 AccessTokenModel
- * @param codeModel CodeModel对象
- * @return RefreshToken对象
- */
- public AccessTokenModel converRefreshTokenToAccessToken(RefreshTokenModel rt) {
- AccessTokenModel at = new AccessTokenModel();
- at.accessToken = randomAccessToken(rt.clientId, rt.loginId, rt.scope);
- at.refreshToken = rt.refreshToken;
- at.clientId = rt.clientId;
- at.loginId = rt.loginId;
- at.scope = rt.scope;
- at.openid = rt.openid;
- at.expiresTime = System.currentTimeMillis() + (SaOAuth2Manager.getConfig().getAccessTokenTimeout() * 1000);
- at.refreshExpiresTime = rt.expiresTime;
- return at;
- }
- /**
- * 将指定字符串按照逗号分隔符转化为字符串集合
- * @param str 字符串
- * @return 分割后的字符串集合
- */
- public List convertStringToList(String str) {
- String[] arr = str.split(",");
- List list = new ArrayList();
- for (String s : arr) {
- if(SaFoxUtil.isEmpty(s) == false) {
- list.add(s);
- }
- }
- return list;
+ public ClientTokenModel checkClientToken(String clientToken) {
+ ClientTokenModel ct = getClientToken(clientToken);
+ SaOAuth2Exception.throwBy(ct == null, "无效:client_token" + ct);
+ return ct;
}
// ------------------- generate 构建数据
/**
- * 构建:请求Model
+ * 构建Model:请求Model
* @param req SaRequest对象
* @param loginId 账号id
* @return RequestAuthModel对象
@@ -176,134 +101,142 @@ public class SaOAuth2Template {
return ra;
}
/**
- * 构建:授权码Model
- * @param ra 请求授权参数Model
+ * 构建Model:Code授权码
+ * @param ra 请求参数Model
* @return 授权码Model
*/
public CodeModel generateCode(RequestAuthModel ra) {
// 删除旧Code
- String oldCode = getCodeValue(ra.clientId, ra.loginId);
- if(oldCode != null) {
- deleteCode(oldCode);
- // deleteCodeIndex(ra.clientId, ra.loginId); // 此处无需删除,因为下边的set会直接覆盖掉
- }
+ deleteCode(getCodeValue(ra.clientId, ra.loginId));
// 生成新Code
String code = randomCode(ra.clientId, ra.loginId, ra.scope);
- CodeModel codeModel = new CodeModel(code, ra.clientId, ra.scope, ra.loginId, ra.redirectUri);
+ CodeModel cm = new CodeModel(code, ra.clientId, ra.scope, ra.loginId, ra.redirectUri);
// 保存新Code
- saveCode(codeModel);
- saveCodeIndex(codeModel);
+ saveCode(cm);
+ saveCodeIndex(cm);
// 返回
- return codeModel;
+ return cm;
}
/**
- * 构建:AccessToken Model
- * @param codeModel 授权码Model
- * @return AccessTokenModel
+ * 构建Model:Access-Token
+ * @param code 授权码Model
+ * @return AccessToken Model
*/
public AccessTokenModel generateAccessToken(String code) {
- // 先校验
+ // 1、先校验
CodeModel cm = getCode(code);
SaOAuth2Exception.throwBy(cm == null, "无效code");
- // 生成token
+ // 2、删除旧Token
+ deleteAccessToken(getAccessTokenValue(cm.clientId, cm.loginId));
+ deleteRefreshToken(getRefreshTokenValue(cm.clientId, cm.loginId));
+
+ // 3、生成token
AccessTokenModel at = converCodeToAccessToken(cm);
RefreshTokenModel rt = converAccessTokenToRefreshToken(at);
+ at.refreshToken = rt.refreshToken;
at.refreshExpiresTime = rt.expiresTime;
- // 保存Token
+ // 4、保存token
saveAccessToken(at);
saveAccessTokenIndex(at);
saveRefreshToken(rt);
saveRefreshTokenIndex(rt);
- // 删除此Code
+ // 5、删除此Code
deleteCode(code);
deleteCodeIndex(cm.clientId, cm.loginId);
- // 返回
+ // 6、返回 Access-Token
return at;
}
/**
- * 刷新:根据 RefreshToken 生成一个 AccessToken
- * @param refreshToken refresh_token
- * @return 新的 access_token
+ * 刷新Model:根据 Refresh-Token 生成一个新的 Access-Token
+ * @param refreshToken Refresh-Token值
+ * @return 新的 Access-Token
*/
public AccessTokenModel refreshAccessToken(String refreshToken) {
- // 获取RefreshToken信息
+ // 获取 Refresh-Token 信息
RefreshTokenModel rt = getRefreshToken(refreshToken);
SaOAuth2Exception.throwBy(rt == null, "无效refresh_token: " + refreshToken);
- // 删除旧AccessToken
- String atValue = getAccessTokenValue(rt.clientId, rt.loginId);
- if(atValue != null) {
- deleteAccessToken(atValue);
- deleteAccessTokenIndex(rt.clientId, rt.loginId);
+ // 如果配置了[每次刷新产生新的Refresh-Token]
+ if(SaOAuth2Manager.getConfig().getIsNewRefresh()) {
+ // 删除旧 Refresh-Token
+ deleteRefreshToken(rt.refreshToken);
+
+ // 创建并保持新的 Refresh-Token
+ rt = converRefreshTokenToRefreshToken(rt);
+ saveRefreshToken(rt);
+ saveRefreshTokenIndex(rt);
}
- // 生成新AccessToken
+ // 删除旧 Access-Token
+ deleteAccessToken(getAccessTokenValue(rt.clientId, rt.loginId));
+
+ // 生成新 Access-Token
AccessTokenModel at = converRefreshTokenToAccessToken(rt);
- // 保存新AccessToken
+ // 保存新 Access-Token
saveAccessToken(at);
saveAccessTokenIndex(at);
- // 返回新AccessToken
+ // 返回新 Access-Token
return at;
}
/**
- * 构建:AccessToken Model (根据RequestAuthModel) 用于隐藏式
- * @param ra 请求授权参数Model
- * @return 授权码Model
+ * 构建Model:Access-Token (根据RequestAuthModel构建,用于隐藏式 and 密码式)
+ * @param ra 请求参数Model
+ * @param isCreateRt 是否生成对应的Refresh-Token
+ * @return Access-Token Model
*/
- public AccessTokenModel generateAccessToken(RequestAuthModel ra) {
+ public AccessTokenModel generateAccessToken(RequestAuthModel ra, boolean isCreateRt) {
- // 删除旧AccessToken
- String oldAccessToken = getAccessTokenValue(ra.clientId, ra.loginId);
- if(oldAccessToken != null) {
- deleteAccessToken(oldAccessToken);
+ // 1、删除 旧Token
+ deleteAccessToken(getAccessTokenValue(ra.clientId, ra.loginId));
+ if(isCreateRt) {
+ deleteRefreshToken(getRefreshTokenValue(ra.clientId, ra.loginId));
}
- // 生成新AccessToken
- String atValue = randomAccessToken(ra.clientId, ra.loginId, ra.scope);
- AccessTokenModel at = new AccessTokenModel(atValue, ra.clientId, ra.loginId, ra.scope);
+ // 2、生成 新Access-Token
+ String newAtValue = randomAccessToken(ra.clientId, ra.loginId, ra.scope);
+ AccessTokenModel at = new AccessTokenModel(newAtValue, ra.clientId, ra.loginId, ra.scope);
at.openid = getOpenid(ra.clientId, ra.loginId);
at.expiresTime = System.currentTimeMillis() + (SaOAuth2Manager.getConfig().getAccessTokenTimeout() * 1000);
- // 保存新Token
+ // 3、生成&保存 Refresh-Token
+ if(isCreateRt) {
+ RefreshTokenModel rt = converAccessTokenToRefreshToken(at);
+ saveRefreshToken(rt);
+ saveRefreshTokenIndex(rt);
+ }
+
+ // 5、保存 新Access-Token
saveAccessToken(at);
saveAccessTokenIndex(at);
- // 返回新Token
+ // 6、返回 新Access-Token
return at;
}
-
/**
- * 构建:ClientToken Model
- * @param ra 请求授权参数Model
- * @return ClientToken-Model
+ * 构建Model:Client-Token
+ * @param clientId 应用id
+ * @param scope 授权范围
+ * @return Client-Token Model
*/
public ClientTokenModel generateClientToken(String clientId, String scope) {
// 1、删掉 Past-Token
- String ptValue = getPastTokenValue(clientId);
- if(ptValue != null) {
- deleteClientToken(ptValue);
- }
+ deleteClientToken(getPastTokenValue(clientId));
- // 2、将Client-Token 标记 Past-Token
+ // 2、将Client-Token 标记 Past-Token
String ctValue = getClientTokenValue(clientId);
- if(ctValue != null) {
- ClientTokenModel ct = getClientToken(ctValue);
- if(ct != null) {
- savePastClientTokenIndex(ct);
- }
- }
+ savePastTokenIndex(getClientToken(ctValue));
// 3、生成新Token
ClientTokenModel ct = new ClientTokenModel(randomClientToken(clientId, scope), clientId, scope);
@@ -316,22 +249,8 @@ public class SaOAuth2Template {
// 4、返回
return ct;
}
-
- // ------------------- 其它方法
/**
- * 获取 access_token 所代表的LoginId
- * @param accessToken access_token
- * @return LoginId
- */
- public Object getLoginIdByAccessToken(String accessToken) {
- AccessTokenModel tokenModel = SaOAuth2Util.getAccessToken(accessToken);
- if(tokenModel == null) {
- throw new SaTokenException("无效access_token");
- }
- return getLoginId(tokenModel.clientId, tokenModel.openid);
- }
- /**
- * [OK] 构建URL:下放授权码URL
+ * 构建URL:下放Code URL (Authorization Code 授权码)
* @param redirectUri 下放地址
* @param code code参数
* @param state state参数
@@ -345,57 +264,54 @@ public class SaOAuth2Template {
return url;
}
/**
- * [OK] 构建URL:下放Token URL
+ * 构建URL:下放Access-Token URL (implicit 隐藏式)
* @param redirectUri 下放地址
* @param token token
* @param state state参数
* @return 构建完毕的URL
*/
- public String buildRedirectUri2(String redirectUri, String token, String state) {
+ public String buildImplicitRedirectUri(String redirectUri, String token, String state) {
String url = SaFoxUtil.joinSharpParam(redirectUri, Param.token, token);
if(SaFoxUtil.isEmpty(state) == false) {
- url = SaFoxUtil.joinParam(url, Param.state, state);
+ url = SaFoxUtil.joinSharpParam(url, Param.state, state);
}
return url;
}
- // ------------------- 数据校验
+ // ------------------- check 数据校验
/**
- * [OK] 判断:该Client是否签约了指定的Scope
- * @param clientId 应用id
- * @param scope 权限
- */
- public boolean isContract(String clientId, String scope) {
- if(SaFoxUtil.isEmpty(scope)) {
- return true;
- }
- List clientScopeList = getClientScopeList(clientId);
- List scopelist = Arrays.asList(scope.split(","));
- return clientScopeList.containsAll(scopelist);
- }
- /**
- * [OK] 指定 loginId 是否对一个 Client 授权给了指定 Scope
+ * 判断:指定 loginId 是否对一个 Client 授权给了指定 Scope
* @param loginId 账号id
* @param clientId 应用id
* @param scope 权限
* @return 是否已经授权
*/
public boolean isGrant(Object loginId, String clientId, String scope) {
- List grantScopeList = getGrantScopeList(loginId, clientId);
- List scopeList = convertStringToList(scope);
+ List grantScopeList = SaFoxUtil.convertStringToList(getGrantScope(clientId, loginId));
+ List scopeList = SaFoxUtil.convertStringToList(scope);
return scopeList.size() == 0 || grantScopeList.containsAll(scopeList);
}
/**
- * [OK] 指定Client使用指定url作为回调地址,是否合法
+ * 校验:该Client是否签约了指定的Scope
+ * @param clientId 应用id
+ * @param scope 权限(多个用逗号隔开)
+ */
+ public void checkContract(String clientId, String scope) {
+ List clientScopeList = SaFoxUtil.convertStringToList(checkClientModel(clientId).contractScope);
+ List scopelist = SaFoxUtil.convertStringToList(scope);
+ if(clientScopeList.containsAll(scopelist) == false) {
+ throw new SaOAuth2Exception("请求的Scope暂未签约");
+ }
+ }
+ /**
+ * 校验:该Client使用指定url作为回调地址,是否合法
* @param clientId 应用id
* @param url 指定url
- * @return 是否合法
*/
- public boolean isRightUrl(String clientId, String url) {
-
- // 1、是否是一个有效的url
+ public void checkRightUrl(String clientId, String url) {
+ // 1、是否是一个有效的url
if(SaFoxUtil.isUrl(url) == false) {
- return false;
+ throw new SaOAuth2Exception("无效redirect_url:" + url);
}
// 2、截取掉?后面的部分
@@ -405,81 +321,142 @@ public class SaOAuth2Template {
}
// 3、是否在[允许地址列表]之中
- String domain = getClientDomain(clientId);
- if(SaFoxUtil.isEmpty(domain)) {
- return false;
+ List allowList = SaFoxUtil.convertStringToList(checkClientModel(clientId).allowUrl);
+ if(SaManager.getSaTokenAction().hasElement(allowList, url) == false) {
+ throw new SaOAuth2Exception("非法redirect_url:" + url);
}
- List authUrlList = Arrays.asList(domain.replaceAll(" ", "").split(","));
- if(SaManager.getSaTokenAction().hasElement(authUrlList, url) == false) {
- return false;
- }
-
- // 验证通过
- return true;
}
/**
- * [OK 方法名改一下]校验code、clientId、clientSecret 三者是否正确
+ * 校验:clientId 与 clientSecret 是否正确
+ * @param clientId 应用id
+ * @param clientSecret 秘钥
+ * @return SaClientModel对象
+ */
+ public SaClientModel checkClientSecret(String clientId, String clientSecret) {
+ SaClientModel cm = checkClientModel(clientId);
+ SaOAuth2Exception.throwBy(cm.clientSecret == null || cm.clientSecret.equals(clientSecret) == false, "无效client_secret: " + clientSecret);
+ return cm;
+ }
+ /**
+ * 校验:使用 code 获取 token 时提供的参数校验
* @param code 授权码
* @param clientId 应用id
* @param clientSecret 秘钥
- * @param redirectUri 秘钥
+ * @param redirectUri 重定向地址
* @return CodeModel对象
*/
- public CodeModel checkCodeIdSecret(String code, String clientId, String clientSecret, String redirectUri) {
+ public CodeModel checkGainTokenParam(String code, String clientId, String clientSecret, String redirectUri) {
// 校验:Code是否存在
- CodeModel codeModel = getCode(code);
- if(codeModel == null) {
- throw new SaOAuth2Exception("无效code");
- }
+ CodeModel cm = getCode(code);
+ SaOAuth2Exception.throwBy(cm == null, "无效code: " + code);
// 校验:ClientId是否一致
- if(codeModel.getClientId().equals(clientId) == false){
- throw new SaOAuth2Exception("无效client_id");
- }
+ SaOAuth2Exception.throwBy(cm.clientId.equals(clientId) == false, "无效client_id: " + clientId);
// 校验:Secret是否正确
- String dbClientSecret = getClientSecret(clientId);
- if(dbClientSecret == null || dbClientSecret.equals(clientSecret) == false){
- throw new SaOAuth2Exception("无效client_secret");
- }
+ String dbSecret = checkClientModel(clientId).clientSecret;
+ SaOAuth2Exception.throwBy(dbSecret == null || dbSecret.equals(clientSecret) == false, "无效client_secret: " + clientSecret);
// 如果提供了redirectUri,则校验其是否与请求Code时提供的一致
if(SaFoxUtil.isEmpty(redirectUri) == false) {
- if(redirectUri.equals(codeModel.redirectUri) == false) {
- throw new SaOAuth2Exception("无效redirect_uri");
- }
+ SaOAuth2Exception.throwBy(redirectUri.equals(cm.redirectUri) == false, "无效redirect_uri: " + redirectUri);
}
- // 返回CodeMdoel
- return codeModel;
+ // 返回CodeMdoel
+ return cm;
}
/**
- * 校验access_token、clientId、clientSecret 三者是否正确
- * @param accessToken access_token
+ * 校验:使用 Refresh-Token 刷新 Access-Token 时提供的参数校验
* @param clientId 应用id
* @param clientSecret 秘钥
- * @return AccessTokenModel对象
+ * @param refreshToken Refresh-Token
+ * @return CodeModel对象
*/
- public AccessTokenModel checkTokenIdSecret(String accessToken, String clientId, String clientSecret) {
+ public RefreshTokenModel checkRefreshTokenParam(String clientId, String clientSecret, String refreshToken) {
- // 获取授权码信息
- AccessTokenModel tokenModel = getAccessToken(accessToken);
+ // 校验:Refresh-Token是否存在
+ RefreshTokenModel rt = getRefreshToken(refreshToken);
+ SaOAuth2Exception.throwBy(rt == null, "无效refresh_token: " + refreshToken);
+
+ // 校验:ClientId是否一致
+ SaOAuth2Exception.throwBy(rt.clientId.equals(clientId) == false, "无效client_id: " + clientId);
- // 验证code、client_id、client_secret
- if(tokenModel == null) {
- throw new SaTokenException("无效access_token");
- }
- if(tokenModel.clientId.equals(clientId) == false){
- throw new SaTokenException("无效client_id");
- }
- String dbClientSecret = getClientSecret(clientId);
- if(dbClientSecret == null || dbClientSecret.equals(clientSecret)){
- throw new SaTokenException("无效client_secret");
- }
+ // 校验:Secret是否正确
+ String dbSecret = checkClientModel(clientId).clientSecret;
+ SaOAuth2Exception.throwBy(dbSecret == null || dbSecret.equals(clientSecret) == false, "无效client_secret: " + clientSecret);
- // 返回AccessTokenModel
- return tokenModel;
+ // 返回Refresh-Token
+ return rt;
+ }
+
+ // ------------------- conver 数据转换
+ /**
+ * 将 Code 转换为 Access-Token
+ * @param cm CodeModel对象
+ * @return AccessToken对象
+ */
+ public AccessTokenModel converCodeToAccessToken(CodeModel cm) {
+ AccessTokenModel at = new AccessTokenModel();
+ at.accessToken = randomAccessToken(cm.clientId, cm.loginId, cm.scope);
+ // at.refreshToken = randomRefreshToken(cm.clientId, cm.loginId, cm.scope);
+ at.clientId = cm.clientId;
+ at.loginId = cm.loginId;
+ at.scope = cm.scope;
+ at.openid = getOpenid(cm.clientId, cm.loginId);
+ at.expiresTime = System.currentTimeMillis() + (SaOAuth2Manager.getConfig().getAccessTokenTimeout() * 1000);
+ // at.refreshExpiresTime = System.currentTimeMillis() + (SaOAuth2Manager.getConfig().getRefreshTokenTimeout() * 1000);
+ return at;
+ }
+ /**
+ * 将 Access-Token 转换为 Refresh-Token
+ * @param at .
+ * @return .
+ */
+ public RefreshTokenModel converAccessTokenToRefreshToken(AccessTokenModel at) {
+ RefreshTokenModel rt = new RefreshTokenModel();
+ rt.refreshToken = randomRefreshToken(at.clientId, at.loginId, at.scope);
+ rt.clientId = at.clientId;
+ rt.loginId = at.loginId;
+ rt.scope = at.scope;
+ rt.openid = at.openid;
+ rt.expiresTime = System.currentTimeMillis() + (SaOAuth2Manager.getConfig().getRefreshTokenTimeout() * 1000);
+ // 改变at属性
+ at.refreshToken = rt.refreshToken;
+ at.refreshExpiresTime = rt.expiresTime;
+ return rt;
+ }
+ /**
+ * 将 Refresh-Token 转换为 Access-Token
+ * @param rt .
+ * @return .
+ */
+ public AccessTokenModel converRefreshTokenToAccessToken(RefreshTokenModel rt) {
+ AccessTokenModel at = new AccessTokenModel();
+ at.accessToken = randomAccessToken(rt.clientId, rt.loginId, rt.scope);
+ at.refreshToken = rt.refreshToken;
+ at.clientId = rt.clientId;
+ at.loginId = rt.loginId;
+ at.scope = rt.scope;
+ at.openid = rt.openid;
+ at.expiresTime = System.currentTimeMillis() + (SaOAuth2Manager.getConfig().getAccessTokenTimeout() * 1000);
+ at.refreshExpiresTime = rt.expiresTime;
+ return at;
+ }
+ /**
+ * 根据 Refresh-Token 创建一个新的 Refresh-Token
+ * @param rt .
+ * @return .
+ */
+ public RefreshTokenModel converRefreshTokenToRefreshToken(RefreshTokenModel rt) {
+ RefreshTokenModel newRt = new RefreshTokenModel();
+ newRt.refreshToken = randomRefreshToken(rt.clientId, rt.loginId, rt.scope);
+ newRt.expiresTime = System.currentTimeMillis() + (SaOAuth2Manager.getConfig().getRefreshTokenTimeout() * 1000);
+ newRt.clientId = rt.clientId;
+ newRt.scope = rt.scope;
+ newRt.loginId = rt.loginId;
+ newRt.openid = rt.openid;
+ return newRt;
}
// ------------------- save 数据
@@ -488,266 +465,344 @@ public class SaOAuth2Template {
* @param c .
*/
public void saveCode(CodeModel c) {
- SaManager.getSaTokenDao().setObject(splicingKeySaveCode(c.code), c, SaOAuth2Manager.getConfig().getCodeTimeout());
+ if(c == null) {
+ return;
+ }
+ SaManager.getSaTokenDao().setObject(splicingCodeSaveKey(c.code), c, SaOAuth2Manager.getConfig().getCodeTimeout());
}
/**
* 持久化:Code-索引
* @param c .
*/
public void saveCodeIndex(CodeModel c) {
- SaManager.getSaTokenDao().set(splicingKeyCodeIndex(c.clientId, c.loginId), c.code, SaOAuth2Manager.getConfig().getCodeTimeout());
+ if(c == null) {
+ return;
+ }
+ SaManager.getSaTokenDao().set(splicingCodeIndexKey(c.clientId, c.loginId), c.code, SaOAuth2Manager.getConfig().getCodeTimeout());
}
/**
* 持久化:AccessToken-Model
* @param at .
*/
public void saveAccessToken(AccessTokenModel at) {
- SaManager.getSaTokenDao().setObject(splicingKeySaveAccessToken(at.accessToken), at, at.getExpiresIn());
+ if(at == null) {
+ return;
+ }
+ SaManager.getSaTokenDao().setObject(splicingAccessTokenSaveKey(at.accessToken), at, at.getExpiresIn());
}
/**
* 持久化:AccessToken-索引
* @param at .
*/
public void saveAccessTokenIndex(AccessTokenModel at) {
- SaManager.getSaTokenDao().set(splicingKeyAccessTokenIndex(at.clientId, at.loginId), at.accessToken, at.getExpiresIn());
+ if(at == null) {
+ return;
+ }
+ SaManager.getSaTokenDao().set(splicingAccessTokenIndexKey(at.clientId, at.loginId), at.accessToken, at.getExpiresIn());
}
/**
* 持久化:RefreshToken-Model
* @param rt .
*/
public void saveRefreshToken(RefreshTokenModel rt) {
- SaManager.getSaTokenDao().setObject(splicingKeySaveRefreshToken(rt.refreshToken), rt, rt.getExpiresIn());
+ if(rt == null) {
+ return;
+ }
+ SaManager.getSaTokenDao().setObject(splicingRefreshTokenSaveKey(rt.refreshToken), rt, rt.getExpiresIn());
}
/**
* 持久化:RefreshToken-索引
* @param rt .
*/
public void saveRefreshTokenIndex(RefreshTokenModel rt) {
- SaManager.getSaTokenDao().set(splicingKeyRefreshTokenIndex(rt.clientId, rt.loginId), rt.refreshToken, rt.getExpiresIn());
+ if(rt == null) {
+ return;
+ }
+ SaManager.getSaTokenDao().set(splicingRefreshTokenIndexKey(rt.clientId, rt.loginId), rt.refreshToken, rt.getExpiresIn());
}
/**
* 持久化:ClientToken-Model
- * @param at .
+ * @param ct .
*/
public void saveClientToken(ClientTokenModel ct) {
- SaManager.getSaTokenDao().setObject(splicingKeySaveClientToken(ct.clientToken), ct, ct.getExpiresIn());
+ if(ct == null) {
+ return;
+ }
+ SaManager.getSaTokenDao().setObject(splicingClientTokenSaveKey(ct.clientToken), ct, ct.getExpiresIn());
}
/**
* 持久化:ClientToken-索引
- * @param at .
+ * @param ct .
*/
public void saveClientTokenIndex(ClientTokenModel ct) {
- SaManager.getSaTokenDao().set(splicingKeyClientTokenIndex(ct.clientId), ct.clientToken, ct.getExpiresIn());
+ if(ct == null) {
+ return;
+ }
+ SaManager.getSaTokenDao().set(splicingClientTokenIndexKey(ct.clientId), ct.clientToken, ct.getExpiresIn());
}
/**
- * 持久化:Past-ClientToken-索引
- * @param at .
+ * 持久化:Past-Token-索引
+ * @param ct .
*/
- public void savePastClientTokenIndex(ClientTokenModel ct) {
- SaManager.getSaTokenDao().set(splicingKeyPastTokenIndex(ct.clientId), ct.clientToken, ct.getExpiresIn());
+ public void savePastTokenIndex(ClientTokenModel ct) {
+ if(ct == null) {
+ return;
+ }
+ SaManager.getSaTokenDao().set(splicingPastTokenIndexKey(ct.clientId), ct.clientToken, ct.getExpiresIn());
+ }
+ /**
+ * 持久化:用户授权记录
+ * @param clientId 应用id
+ * @param loginId 账号id
+ * @param scope 权限列表(多个逗号隔开)
+ */
+ public void saveGrantScope(String clientId, Object loginId, String scope) {
+ if(SaFoxUtil.isEmpty(scope) == false) {
+ long ttl = SaOAuth2Manager.getConfig().getAccessTokenTimeout();
+ SaManager.getSaTokenDao().set(splicingGrantScopeKey(clientId, loginId), scope, ttl);
+ }
}
- // ------------------- get 数据 [OK]
+ // ------------------- get 数据
/**
- * 获取:授权码
+ * 获取:Code Model
* @param code .
* @return .
*/
public CodeModel getCode(String code) {
- return (CodeModel)SaManager.getSaTokenDao().getObject(splicingKeySaveCode(code));
+ if(code == null) {
+ return null;
+ }
+ return (CodeModel)SaManager.getSaTokenDao().getObject(splicingCodeSaveKey(code));
}
/**
- * 获取:授权码-Value
+ * 获取:Code Value
* @param clientId 应用id
* @param loginId 账号id
* @return .
*/
public String getCodeValue(String clientId, Object loginId) {
- return SaManager.getSaTokenDao().get(splicingKeyCodeIndex(clientId, loginId));
+ return SaManager.getSaTokenDao().get(splicingCodeIndexKey(clientId, loginId));
}
/**
- * 获取:AccessToken
+ * 获取:Access-Token Model
* @param accessToken .
* @return .
*/
public AccessTokenModel getAccessToken(String accessToken) {
- return (AccessTokenModel)SaManager.getSaTokenDao().getObject(splicingKeySaveAccessToken(accessToken));
+ if(accessToken == null) {
+ return null;
+ }
+ return (AccessTokenModel)SaManager.getSaTokenDao().getObject(splicingAccessTokenSaveKey(accessToken));
}
/**
- * 获取:AccessToken-Value
+ * 获取:Access-Token Value
* @param clientId 应用id
* @param loginId 账号id
* @return .
*/
public String getAccessTokenValue(String clientId, Object loginId) {
- return SaManager.getSaTokenDao().get(splicingKeyAccessTokenIndex(clientId, loginId));
+ return SaManager.getSaTokenDao().get(splicingAccessTokenIndexKey(clientId, loginId));
}
/**
- * 获取:RefreshToken
+ * 获取:Refresh-Token Model
* @param refreshToken .
* @return .
*/
public RefreshTokenModel getRefreshToken(String refreshToken) {
- return (RefreshTokenModel)SaManager.getSaTokenDao().getObject(splicingKeySaveRefreshToken(refreshToken));
+ if(refreshToken == null) {
+ return null;
+ }
+ return (RefreshTokenModel)SaManager.getSaTokenDao().getObject(splicingRefreshTokenSaveKey(refreshToken));
}
/**
- * 获取:RefreshToken-Value
+ * 获取:Refresh-Token Value
* @param clientId 应用id
* @param loginId 账号id
* @return .
*/
public String getRefreshTokenValue(String clientId, Object loginId) {
- return SaManager.getSaTokenDao().get(splicingKeyRefreshTokenIndex(clientId, loginId));
+ return SaManager.getSaTokenDao().get(splicingRefreshTokenIndexKey(clientId, loginId));
}
-
/**
- * 获取:ClientTokenModel
+ * 获取:Client-Token Model
* @param clientToken .
* @return .
*/
public ClientTokenModel getClientToken(String clientToken) {
- return (ClientTokenModel)SaManager.getSaTokenDao().getObject(splicingKeySaveClientToken(clientToken));
+ if(clientToken == null) {
+ return null;
+ }
+ return (ClientTokenModel)SaManager.getSaTokenDao().getObject(splicingClientTokenSaveKey(clientToken));
}
/**
- * 获取:ClientTokenModel-Value
+ * 获取:Client-Token Value
* @param clientId 应用id
- * @param loginId 账号id
* @return .
*/
public String getClientTokenValue(String clientId) {
- return SaManager.getSaTokenDao().get(splicingKeyClientTokenIndex(clientId));
+ return SaManager.getSaTokenDao().get(splicingClientTokenIndexKey(clientId));
}
/**
- * 获取:ClientTokenModel-Value
+ * 获取:Past-Token Value
* @param clientId 应用id
- * @param loginId 账号id
* @return .
*/
public String getPastTokenValue(String clientId) {
- return SaManager.getSaTokenDao().get(splicingKeyPastTokenIndex(clientId));
+ return SaManager.getSaTokenDao().get(splicingPastTokenIndexKey(clientId));
+ }
+ /**
+ * 获取:用户授权记录
+ * @param clientId 应用id
+ * @param loginId 账号id
+ * @return 权限
+ */
+ public String getGrantScope(String clientId, Object loginId) {
+ return SaManager.getSaTokenDao().get(splicingGrantScopeKey(clientId, loginId));
}
-
- // ------------------- delete 数据 [OK]
+ // ------------------- delete数据
/**
- * 删除:授权码
- * @param code 授权码
+ * 删除:Code
+ * @param code 值
*/
public void deleteCode(String code) {
- SaManager.getSaTokenDao().deleteObject(splicingKeySaveCode(code));
+ if(code != null) {
+ SaManager.getSaTokenDao().deleteObject(splicingCodeSaveKey(code));
+ }
}
/**
- * 删除:授权码索引
+ * 删除:Code索引
* @param clientId 应用id
* @param loginId 账号id
*/
public void deleteCodeIndex(String clientId, Object loginId) {
- SaManager.getSaTokenDao().delete(splicingKeyCodeIndex(clientId, loginId));
+ SaManager.getSaTokenDao().delete(splicingCodeIndexKey(clientId, loginId));
}
/**
- * 删除:AccessToken
- * @param accessToken .
+ * 删除:Access-Token
+ * @param accessToken 值
*/
public void deleteAccessToken(String accessToken) {
- SaManager.getSaTokenDao().deleteObject(splicingKeySaveAccessToken(accessToken));
+ if(accessToken != null) {
+ SaManager.getSaTokenDao().deleteObject(splicingAccessTokenSaveKey(accessToken));
+ }
}
/**
- * 删除:AccessToken索引
+ * 删除:Access-Token索引
* @param clientId 应用id
* @param loginId 账号id
*/
public void deleteAccessTokenIndex(String clientId, Object loginId) {
- SaManager.getSaTokenDao().delete(splicingKeyAccessTokenIndex(clientId, loginId));
+ SaManager.getSaTokenDao().delete(splicingAccessTokenIndexKey(clientId, loginId));
}
/**
- * 删除:RefreshAccess
- * @param refreshAccess .
+ * 删除:Refresh-Token
+ * @param refreshToken 值
*/
- public void deleteRefreshAccess(String refreshAccess) {
- SaManager.getSaTokenDao().deleteObject(splicingKeySaveRefreshToken(refreshAccess));
+ public void deleteRefreshToken(String refreshToken) {
+ if(refreshToken != null) {
+ SaManager.getSaTokenDao().deleteObject(splicingRefreshTokenSaveKey(refreshToken));
+ }
}
/**
- * 删除:RefreshAccess索引
+ * 删除:Refresh-Token索引
* @param clientId 应用id
* @param loginId 账号id
*/
- public void deleteRefreshAccessIndex(String clientId, Object loginId) {
- SaManager.getSaTokenDao().delete(splicingKeyRefreshTokenIndex(clientId, loginId));
+ public void deleteRefreshTokenIndex(String clientId, Object loginId) {
+ SaManager.getSaTokenDao().delete(splicingRefreshTokenIndexKey(clientId, loginId));
}
/**
- * 删除:ClientToken
- * @param clientToken .
+ * 删除:Client-Token
+ * @param clientToken 值
*/
public void deleteClientToken(String clientToken) {
- SaManager.getSaTokenDao().deleteObject(splicingKeySaveClientToken(clientToken));
+ if(clientToken != null) {
+ SaManager.getSaTokenDao().deleteObject(splicingClientTokenSaveKey(clientToken));
+ }
}
/**
- * 删除:ClientToken索引
+ * 删除:Client-Token索引
* @param clientId 应用id
*/
public void deleteClientTokenIndex(String clientId) {
- SaManager.getSaTokenDao().delete(splicingKeyClientTokenIndex(clientId));
+ SaManager.getSaTokenDao().delete(splicingClientTokenIndexKey(clientId));
}
/**
* 删除:Past-Token索引
* @param clientId 应用id
*/
public void deletePastTokenIndex(String clientId) {
- SaManager.getSaTokenDao().delete(splicingKeyPastTokenIndex(clientId));
+ SaManager.getSaTokenDao().delete(splicingPastTokenIndexKey(clientId));
+ }
+ /**
+ * 删除:用户授权记录
+ * @param clientId 应用id
+ * @param loginId 账号id
+ */
+ public void deleteGrantScope(String clientId, Object loginId) {
+ SaManager.getSaTokenDao().delete(splicingGrantScopeKey(clientId, loginId));
}
-
- // ------------------- Random数据 [OK]
+ // ------------------- Random数据
/**
- * 生成授权码
+ * 随机一个 Code
* @param clientId 应用id
* @param loginId 账号id
* @param scope 权限
- * @return 授权码
+ * @return Code
*/
public String randomCode(String clientId, Object loginId, String scope) {
return SaFoxUtil.getRandomString(60);
}
/**
- * 生成AccessToken
- * @param codeModel CodeModel对象
- * @return AccessToken
+ * 随机一个 Access-Token
+ * @param clientId 应用id
+ * @param loginId 账号id
+ * @param scope 权限
+ * @return Access-Token
*/
public String randomAccessToken(String clientId, Object loginId, String scope) {
return SaFoxUtil.getRandomString(60);
}
/**
- * 生成RefreshToken
- * @param codeModel CodeModel对象
- * @return RefreshToken
+ * 随机一个 Refresh-Token
+ * @param clientId 应用id
+ * @param loginId 账号id
+ * @param scope 权限
+ * @return Refresh-Token
*/
public String randomRefreshToken(String clientId, Object loginId, String scope) {
return SaFoxUtil.getRandomString(60);
}
/**
- * 生成ClientToken
- * @return RefreshToken
+ * 随机一个 Client-Token
+ * @param clientId 应用id
+ * @param loginId 账号id
+ * @param scope 权限
+ * @return Client-Token
*/
public String randomClientToken(String clientId, Object loginId) {
return SaFoxUtil.getRandomString(60);
}
- // ------------------- 拼接key [OK]
+ // ------------------- 拼接key
/**
- * 拼接key:授权码持久化
+ * 拼接key:Code持久化
* @param code 授权码
* @return key
*/
- public String splicingKeySaveCode(String code) {
+ public String splicingCodeSaveKey(String code) {
return SaManager.getConfig().getTokenName() + ":oauth2:code:" + code;
}
/**
- * 拼接key:授权码索引
+ * 拼接key:Code索引
* @param clientId 应用id
* @param loginId 账号id
* @return key
*/
- public String splicingKeyCodeIndex(String clientId, Object loginId) {
+ public String splicingCodeIndexKey(String clientId, Object loginId) {
return SaManager.getConfig().getTokenName() + ":oauth2:code-index:" + clientId + ":" + loginId;
}
/**
@@ -755,7 +810,7 @@ public class SaOAuth2Template {
* @param accessToken accessToken
* @return key
*/
- public String splicingKeySaveAccessToken(String accessToken) {
+ public String splicingAccessTokenSaveKey(String accessToken) {
return SaManager.getConfig().getTokenName() + ":oauth2:access-token:" + accessToken;
}
/**
@@ -764,49 +819,58 @@ public class SaOAuth2Template {
* @param loginId 账号id
* @return key
*/
- public String splicingKeyAccessTokenIndex(String clientId, Object loginId) {
+ public String splicingAccessTokenIndexKey(String clientId, Object loginId) {
return SaManager.getConfig().getTokenName() + ":oauth2:access-token-index:" + clientId + ":" + loginId;
}
/**
- * 拼接key:RefreshToken持久化
+ * 拼接key:Refresh-Token持久化
* @param refreshToken refreshToken
* @return key
*/
- public String splicingKeySaveRefreshToken(String refreshToken) {
+ public String splicingRefreshTokenSaveKey(String refreshToken) {
return SaManager.getConfig().getTokenName() + ":oauth2:refresh-token:" + refreshToken;
}
/**
- * 拼接key:RefreshToken索引
+ * 拼接key:Refresh-Token索引
* @param clientId 应用id
* @param loginId 账号id
* @return key
*/
- public String splicingKeyRefreshTokenIndex(String clientId, Object loginId) {
+ public String splicingRefreshTokenIndexKey(String clientId, Object loginId) {
return SaManager.getConfig().getTokenName() + ":oauth2:refresh-token-index:" + clientId + ":" + loginId;
}
/**
* 拼接key:Client-Token持久化
- * @param clientToken accessToken
+ * @param clientToken clientToken
* @return key
*/
- public String splicingKeySaveClientToken(String clientToken) {
+ public String splicingClientTokenSaveKey(String clientToken) {
return SaManager.getConfig().getTokenName() + ":oauth2:client-token:" + clientToken;
}
/**
- * 拼接key:ClientToken 索引
- * @param clientToken accessToken
+ * 拼接key:Past-Token 索引
+ * @param clientId clientId
* @return key
*/
- public String splicingKeyClientTokenIndex(String clientId) {
+ public String splicingClientTokenIndexKey(String clientId) {
return SaManager.getConfig().getTokenName() + ":oauth2:client-token-indedx:" + clientId;
}
/**
- * 拼接key:Past-ClientToken 索引
+ * 拼接key:Past-Token 索引
* @param clientId clientId
* @return key
*/
- public String splicingKeyPastTokenIndex(String clientId) {
+ public String splicingPastTokenIndexKey(String clientId) {
return SaManager.getConfig().getTokenName() + ":oauth2:past-token-indedx:" + clientId;
}
+ /**
+ * 拼接key:用户授权记录
+ * @param clientId 应用id
+ * @param loginId 账号id
+ * @return key
+ */
+ public String splicingGrantScopeKey(String clientId, Object loginId) {
+ return SaManager.getConfig().getTokenName() + ":oauth2:grant-scope:" + clientId + ":" + loginId;
+ }
}
diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Util.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Util.java
index d604e4d2..472b055c 100644
--- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Util.java
+++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Util.java
@@ -1,199 +1,39 @@
package cn.dev33.satoken.oauth2.logic;
-import java.util.List;
-
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.oauth2.model.AccessTokenModel;
import cn.dev33.satoken.oauth2.model.ClientTokenModel;
import cn.dev33.satoken.oauth2.model.CodeModel;
import cn.dev33.satoken.oauth2.model.RefreshTokenModel;
import cn.dev33.satoken.oauth2.model.RequestAuthModel;
+import cn.dev33.satoken.oauth2.model.SaClientModel;
/**
- * sa-token-oauth2 模块 静态类接口转发, 方便调用
+ * Sa-Token-OAuth2 模块 工具类
* @author kong
- *
+ *
*/
public class SaOAuth2Util {
+ /**
+ * 模板代码对象
+ */
public static SaOAuth2Template saOAuth2Template = new SaOAuth2Template();
- /**
- * 根据 SaRequest 对象创建 RequestAuthModel
- * @param req SaRequest对象
- * @param loginId 账号id
- * @return RequestAuthModel对象
- */
- public static RequestAuthModel generateRequestAuth(SaRequest req, Object loginId) {
- return saOAuth2Template.generateRequestAuth(req, loginId);
- }
-
-
-
-
-
-
-
-
-
- // ---------------------------------------------- 分界线 -----------------------------------------------------
-
-
- // ------------------- 获取数据
+ // ------------------- 资源获取
/**
- * 返回此平台所有权限集合
- * @return 此平台所有权限名称集合
- */
- public static List getAppScopeList() {
- return saOAuth2Template.getAppScopeList();
- }
-
- /**
- * 返回指定Client签约的所有Scope名称集合
- * @param clientId 应用id
- * @return Scope集合
- */
- public static List getClientScopeList(String clientId) {
- return saOAuth2Template.getClientScopeList(clientId);
- }
-
- /**
- * 获取指定 LoginId 对指定 Client 已经授权过的所有 Scope
- * @param clientId 应用id
- * @param loginId 账号id
- * @return Scope集合
- */
- public static List getGrantScopeList(Object loginId, String clientId) {
- return saOAuth2Template.getGrantScopeList(loginId, clientId);
- }
-
-
- // ------------------- 数据校验
-
- /**
- * [OK] 判断:该Client是否签约了指定的Scope
+ * 根据id获取Client信息, 如果Client为空,则抛出异常
* @param clientId 应用id
- * @param scope 权限
+ * @return ClientModel
*/
- public static boolean isContract(String clientId, String scope) {
- return saOAuth2Template.isContract(clientId, scope);
+ public static SaClientModel checkClientModel(String clientId) {
+ return saOAuth2Template.checkClientModel(clientId);
}
/**
- * 指定 loginId 是否对一个 Client 授权给了指定 Scope
- * @param clientId 应用id
- * @param scope 权限
- * @param loginId 账号id
- * @return 是否已经授权
- */
- public static boolean isGrant(Object loginId, String clientId, String scope) {
- return saOAuth2Template.isGrant(loginId, clientId, scope);
- }
-
- /**
- * [OK] 指定Client使用指定url作为回调地址,是否合法
- * @param clientId 应用id
- * @param url 指定url
- * @return 是否合法
- */
- public static boolean isRightUrl(String clientId, String url) {
- return saOAuth2Template.isRightUrl(clientId, url);
- }
-
- /**
- * [OK 方法名改一下]校验code、clientId、clientSecret 三者是否正确
- * @param code 授权码
- * @param clientId 应用id
- * @param clientSecret 秘钥
- * @param redirectUri 秘钥
- * @return CodeModel对象
- */
- public static CodeModel checkCodeIdSecret(String code, String clientId, String clientSecret, String redirectUri) {
- return saOAuth2Template.checkCodeIdSecret(code, clientId, clientSecret, redirectUri);
- }
-
- /**
- * [default] 校验access_token、clientId、clientSecret 三者是否正确
- * @param accessToken access_token
- * @param clientId 应用id
- * @param clientSecret 秘钥
- * @return AccessTokenModel对象
- */
- public static AccessTokenModel checkTokenIdSecret(String accessToken, String clientId, String clientSecret) {
- return saOAuth2Template.checkTokenIdSecret(accessToken, clientId, clientSecret);
- }
-
-
-
- // ------------------- 逻辑相关
-
- /**
- * [OK] 根据参数生成一个授权码并返回
- * @param authModel 请求授权参数Model
- * @return 授权码Model
- */
- public static CodeModel generateCode(RequestAuthModel authModel) {
- return saOAuth2Template.generateCode(authModel);
- }
-
-
- /**
- * 根据授权码获得授权码Model
- * @param code 授权码
- * @return 授权码Model
- */
- public static CodeModel getCode(String code) {
- return saOAuth2Template.getCode(code);
- }
-
- /**
- * [default] 删除一个授权码
- * @param code 授权码
- */
- public static void deleteCode(String code) {
- saOAuth2Template.deleteCode(code);
- }
-
- /**
- * 根据授权码Model生成一个access_token
- * @param codeModel 授权码Model
- * @return AccessTokenModel
- */
- public static AccessTokenModel generateAccessToken(String code) {
- return saOAuth2Template.generateAccessToken(code);
- }
-
- /**
- * [default] 根据 access_token 获得其Model详细信息
- * @param accessToken access_token
- * @return AccessTokenModel (授权码Model)
- */
- public static AccessTokenModel getAccessToken(String accessToken) {
- return saOAuth2Template.getAccessToken(accessToken);
- }
-
- /**
- * 根据 refresh_token 生成一个新的 access_token
- * @param refreshToken refresh_token
- * @return 新的 access_token
- */
- public static AccessTokenModel refreshAccessToken(String refreshToken) {
- return saOAuth2Template.refreshAccessToken(refreshToken);
- }
-
- /**
- * [default] 根据 refresh_token 获得其Model详细信息
- * @param refreshToken refresh_token
- * @return RefreshToken
- */
- public static RefreshTokenModel getRefreshToken(String refreshToken) {
- return saOAuth2Template.getRefreshToken(refreshToken);
- }
-
- /**
- * [default] 获取 access_token 所代表的LoginId
+ * 获取 access_token 所代表的LoginId
* @param accessToken access_token
* @return LoginId
*/
@@ -202,27 +42,85 @@ public class SaOAuth2Util {
}
/**
- * 构建:AccessToken Model (根据RequestAuthModel) 用于隐藏式
- * @param ra 请求授权参数Model
- * @return 授权码Model
+ * 获取 Access-Token,如果AccessToken为空则抛出异常
+ * @param accessToken .
+ * @return .
*/
- public static AccessTokenModel generateAccessToken(RequestAuthModel ra) {
- return saOAuth2Template.generateAccessToken(ra);
+ public static AccessTokenModel checkAccessToken(String accessToken) {
+ return saOAuth2Template.checkAccessToken(accessToken);
+ }
+
+ /**
+ * 获取 Client-Token,如果ClientToken为空则抛出异常
+ * @param clientToken .
+ * @return .
+ */
+ public static ClientTokenModel checkClientToken(String clientToken) {
+ return saOAuth2Template.checkClientToken(clientToken);
+ }
+
+
+ // ------------------- generate 构建数据
+
+ /**
+ * 构建Model:请求Model
+ * @param req SaRequest对象
+ * @param loginId 账号id
+ * @return RequestAuthModel对象
+ */
+ public static RequestAuthModel generateRequestAuth(SaRequest req, Object loginId) {
+ return saOAuth2Template.generateRequestAuth(req, loginId);
+ }
+
+ /**
+ * 构建Model:Code授权码
+ * @param ra 请求参数Model
+ * @return 授权码Model
+ */
+ public static CodeModel generateCode(RequestAuthModel ra) {
+ return saOAuth2Template.generateCode(ra);
+ }
+
+ /**
+ * 构建Model:Access-Token
+ * @param code 授权码Model
+ * @return AccessToken Model
+ */
+ public static AccessTokenModel generateAccessToken(String code) {
+ return saOAuth2Template.generateAccessToken(code);
}
/**
- * 构建:ClientToken Model
- * @param ra 请求授权参数Model
- * @return ClientToken-Model
+ * 刷新Model:根据 Refresh-Token 生成一个新的 Access-Token
+ * @param refreshToken Refresh-Token值
+ * @return 新的 Access-Token
+ */
+ public static AccessTokenModel refreshAccessToken(String refreshToken) {
+ return saOAuth2Template.refreshAccessToken(refreshToken);
+ }
+
+ /**
+ * 构建Model:Access-Token (根据RequestAuthModel构建,用于隐藏式 and 密码式)
+ * @param ra 请求参数Model
+ * @param isCreateRt 是否生成对应的Refresh-Token
+ * @return Access-Token Model
+ */
+ public static AccessTokenModel generateAccessToken(RequestAuthModel ra, boolean isCreateRt) {
+ return saOAuth2Template.generateAccessToken(ra, isCreateRt);
+ }
+
+ /**
+ * 构建Model:Client-Token
+ * @param clientId 应用id
+ * @param scope 授权范围
+ * @return Client-Token Model
*/
public static ClientTokenModel generateClientToken(String clientId, String scope) {
return saOAuth2Template.generateClientToken(clientId, scope);
}
-
- // ------------------- 自定义策略相关
-
+
/**
- * [OK] 构建URL:下放授权码URL
+ * 构建URL:下放Code URL (Authorization Code 授权码)
* @param redirectUri 下放地址
* @param code code参数
* @param state state参数
@@ -231,16 +129,144 @@ public class SaOAuth2Util {
public static String buildRedirectUri(String redirectUri, String code, String state) {
return saOAuth2Template.buildRedirectUri(redirectUri, code, state);
}
+
/**
- * [OK] 构建URL:下放Token URL
+ * 构建URL:下放Access-Token URL (implicit 隐藏式)
* @param redirectUri 下放地址
* @param token token
* @param state state参数
* @return 构建完毕的URL
*/
- public static String buildRedirectUri2(String redirectUri, String token, String state) {
- return saOAuth2Template.buildRedirectUri2(redirectUri, token, state);
+ public static String buildImplicitRedirectUri(String redirectUri, String token, String state) {
+ return saOAuth2Template.buildImplicitRedirectUri(redirectUri, token, state);
}
+ // ------------------- 数据校验
+
+ /**
+ * 判断:指定 loginId 是否对一个 Client 授权给了指定 Scope
+ * @param loginId 账号id
+ * @param clientId 应用id
+ * @param scope 权限
+ * @return 是否已经授权
+ */
+ public static boolean isGrant(Object loginId, String clientId, String scope) {
+ return saOAuth2Template.isGrant(loginId, clientId, scope);
+ }
+
+ /**
+ * 校验:该Client是否签约了指定的Scope
+ * @param clientId 应用id
+ * @param scope 权限(多个用逗号隔开)
+ */
+ public static void checkContract(String clientId, String scope) {
+ saOAuth2Template.checkContract(clientId, scope);
+ }
+
+ /**
+ * 校验:该Client使用指定url作为回调地址,是否合法
+ * @param clientId 应用id
+ * @param url 指定url
+ */
+ public static void checkRightUrl(String clientId, String url) {
+ saOAuth2Template.checkRightUrl(clientId, url);
+ }
+ /**
+ * 校验:clientId 与 clientSecret 是否正确
+ * @param clientId 应用id
+ * @param clientSecret 秘钥
+ * @return SaClientModel对象
+ */
+ public static SaClientModel checkClientSecret(String clientId, String clientSecret) {
+ return saOAuth2Template.checkClientSecret(clientId, clientSecret);
+ }
+
+ /**
+ * 校验:使用 code 获取 token 时提供的参数校验
+ * @param code 授权码
+ * @param clientId 应用id
+ * @param clientSecret 秘钥
+ * @param redirectUri 重定向地址
+ * @return CodeModel对象
+ */
+ public static CodeModel checkGainTokenParam(String code, String clientId, String clientSecret, String redirectUri) {
+ return saOAuth2Template.checkGainTokenParam(code, clientId, clientSecret, redirectUri);
+ }
+
+ /**
+ * 校验:使用 Refresh-Token 刷新 Access-Token 时提供的参数校验
+ * @param clientId 应用id
+ * @param clientSecret 秘钥
+ * @param refreshToken Refresh-Token
+ * @return CodeModel对象
+ */
+ public static RefreshTokenModel checkRefreshTokenParam(String clientId, String clientSecret, String refreshToken) {
+ return saOAuth2Template.checkRefreshTokenParam(clientId, clientSecret, refreshToken);
+ }
+
+
+ // ------------------- save 数据
+
+ /**
+ * 持久化:用户授权记录
+ * @param clientId 应用id
+ * @param loginId 账号id
+ * @param scope 权限列表(多个逗号隔开)
+ */
+ public static void saveGrantScope(String clientId, Object loginId, String scope) {
+ saOAuth2Template.saveGrantScope(clientId, loginId, scope);
+ }
+
+
+ // ------------------- get 数据
+
+ /**
+ * 获取:Code Model
+ * @param code .
+ * @return .
+ */
+ public static CodeModel getCode(String code) {
+ return saOAuth2Template.getCode(code);
+ }
+
+ /**
+ * 获取:Access-Token Model
+ * @param accessToken .
+ * @return .
+ */
+ public static AccessTokenModel getAccessToken(String accessToken) {
+ return saOAuth2Template.getAccessToken(accessToken);
+ }
+
+ /**
+ * 获取:Refresh-Token Model
+ * @param refreshToken .
+ * @return .
+ */
+ public static RefreshTokenModel getRefreshToken(String refreshToken) {
+ return saOAuth2Template.getRefreshToken(refreshToken);
+ }
+
+ /**
+ * 获取:Client-Token Model
+ * @param clientToken .
+ * @return .
+ */
+ public static ClientTokenModel getClientToken(String clientToken) {
+ return saOAuth2Template.getClientToken(clientToken);
+ }
+
+ /**
+ * 获取:用户授权记录
+ * @param clientId 应用id
+ * @param loginId 账号id
+ * @return 权限
+ */
+ public static String getGrantScope(String clientId, Object loginId) {
+ return saOAuth2Template.getGrantScope(clientId, loginId);
+ }
+
+
+
}
diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/AccessTokenModel.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/AccessTokenModel.java
index 211dc0d1..eba671e8 100644
--- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/AccessTokenModel.java
+++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/AccessTokenModel.java
@@ -1,32 +1,35 @@
package cn.dev33.satoken.oauth2.model;
+import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.Map;
/**
- * Model: access_token
+ * Model: Access-Token
* @author kong
*
*/
-public class AccessTokenModel {
+public class AccessTokenModel implements Serializable {
+
+ private static final long serialVersionUID = -6541180061782004705L;
/**
- * access_token 值
+ * Access-Token 值
*/
public String accessToken;
/**
- * refresh_token 值
+ * Refresh-Token 值
*/
public String refreshToken;
/**
- * access_token 到期时间
+ * Access-Token 到期时间
*/
public long expiresTime;
/**
- * refresh_token 到期时间
+ * Refresh-Token 到期时间
*/
public long refreshExpiresTime;
@@ -92,7 +95,6 @@ public class AccessTokenModel {
return s < 1 ? -2 : s;
}
-
/**
* 将所有属性转换为下划线形式的Map
* @return
diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/ClientTokenModel.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/ClientTokenModel.java
index 5ac2ea49..52c67deb 100644
--- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/ClientTokenModel.java
+++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/ClientTokenModel.java
@@ -1,22 +1,25 @@
package cn.dev33.satoken.oauth2.model;
+import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.Map;
/**
- * Model: client_token
+ * Model: Client-Token
* @author kong
*
*/
-public class ClientTokenModel {
+public class ClientTokenModel implements Serializable {
+
+ private static final long serialVersionUID = -6541180061782004705L;
/**
- * client_token 值
+ * Client-Token 值
*/
public String clientToken;
/**
- * client_token 到期时间
+ * Client-Token 到期时间
*/
public long expiresTime;
diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/CodeModel.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/CodeModel.java
index 998da143..a3d86382 100644
--- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/CodeModel.java
+++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/CodeModel.java
@@ -1,11 +1,15 @@
package cn.dev33.satoken.oauth2.model;
+import java.io.Serializable;
+
/**
- * Model: [授权码 - 数据 对应关系]
+ * Model: 授权码
* @author kong
*
*/
-public class CodeModel {
+public class CodeModel implements Serializable {
+
+ private static final long serialVersionUID = -6541180061782004705L;
/**
* 授权码
diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/RefreshTokenModel.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/RefreshTokenModel.java
index 2b945a3c..4414d56d 100644
--- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/RefreshTokenModel.java
+++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/RefreshTokenModel.java
@@ -1,18 +1,23 @@
package cn.dev33.satoken.oauth2.model;
+
+import java.io.Serializable;
+
/**
- * Model: refresh_token
+ * Model: Refresh-Token
* @author kong
*
*/
-public class RefreshTokenModel {
+public class RefreshTokenModel implements Serializable {
+
+ private static final long serialVersionUID = -6541180061782004705L;
/**
- * refresh_token 值
+ * Refresh-Token 值
*/
public String refreshToken;
/**
- * refresh_token到期时间
+ * Refresh-Token 到期时间
*/
public long expiresTime;
diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/RequestAuthModel.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/RequestAuthModel.java
index 61c1ce9d..7dcb3775 100644
--- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/RequestAuthModel.java
+++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/RequestAuthModel.java
@@ -1,5 +1,7 @@
package cn.dev33.satoken.oauth2.model;
+import java.io.Serializable;
+
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.util.SaFoxUtil;
@@ -8,7 +10,9 @@ import cn.dev33.satoken.util.SaFoxUtil;
* @author kong
*
*/
-public class RequestAuthModel {
+public class RequestAuthModel implements Serializable {
+
+ private static final long serialVersionUID = -6541180061782004705L;
/**
* 应用id
diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/SaClientModel.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/SaClientModel.java
new file mode 100644
index 00000000..952f696c
--- /dev/null
+++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/SaClientModel.java
@@ -0,0 +1,115 @@
+package cn.dev33.satoken.oauth2.model;
+
+import java.io.Serializable;
+
+/**
+ * Client应用信息 Model
+ * @author kong
+ *
+ */
+public class SaClientModel implements Serializable {
+
+ private static final long serialVersionUID = -6541180061782004705L;
+
+ /**
+ * 应用id
+ */
+ public String clientId;
+
+ /**
+ * 应用秘钥
+ */
+ public String clientSecret;
+
+ /**
+ * 应用签约的所有权限, 多个用逗号隔开
+ */
+ public String contractScope;
+
+ /**
+ * 应用允许授权的所有URL, 多个用逗号隔开
+ */
+ public String allowUrl;
+
+ public SaClientModel() {
+
+ }
+ public SaClientModel(String clientId, String clientSecret, String contractScope, String allowUrl) {
+ super();
+ this.clientId = clientId;
+ this.clientSecret = clientSecret;
+ this.contractScope = contractScope;
+ this.allowUrl = allowUrl;
+ }
+
+ /**
+ * @return 应用id
+ */
+ public String getClientId() {
+ return clientId;
+ }
+
+ /**
+ * @param clientId 应用id
+ * @return 对象自身
+ */
+ public SaClientModel setClientId(String clientId) {
+ this.clientId = clientId;
+ return this;
+ }
+
+ /**
+ * @return 应用秘钥
+ */
+ public String getClientSecret() {
+ return clientSecret;
+ }
+
+ /**
+ * @param clientSecret 应用秘钥
+ * @return 对象自身
+ */
+ public SaClientModel setClientSecret(String clientSecret) {
+ this.clientSecret = clientSecret;
+ return this;
+ }
+
+ /**
+ * @return 应用签约的所有权限, 多个用逗号隔开
+ */
+ public String getContractScope() {
+ return contractScope;
+ }
+
+ /**
+ * @param contractScope 应用签约的所有权限, 多个用逗号隔开
+ * @return 对象自身
+ */
+ public SaClientModel setContractScope(String contractScope) {
+ this.contractScope = contractScope;
+ return this;
+ }
+
+ /**
+ * @return 应用允许授权的所有URL, 多个用逗号隔开
+ */
+ public String getAllowUrl() {
+ return allowUrl;
+ }
+
+ /**
+ * @param allowUrl 应用允许授权的所有URL, 多个用逗号隔开
+ * @return 对象自身
+ */
+ public SaClientModel setAllowUrl(String allowUrl) {
+ this.allowUrl = allowUrl;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return "SaClientModel [clientId=" + clientId + ", clientSecret=" + clientSecret + ", contractScope="
+ + contractScope + ", allowUrl=" + allowUrl + "]";
+ }
+
+}
diff --git a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaBeanInject.java b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaBeanInject.java
index d456bf5c..c33f0e07 100644
--- a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaBeanInject.java
+++ b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaBeanInject.java
@@ -2,8 +2,6 @@ package cn.dev33.satoken.reactor.spring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.context.annotation.Import;
-import org.springframework.stereotype.Component;
import org.springframework.util.PathMatcher;
import cn.dev33.satoken.SaManager;
@@ -21,8 +19,6 @@ import cn.dev33.satoken.temp.SaTempInterface;
* @author kong
*
*/
-@Component
-@Import({SaHistoryVersionInject.class, SaBeanRegister.class})
public class SaBeanInject {
/**
diff --git a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/resources/META-INF/spring.factories b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/resources/META-INF/spring.factories
index 399afb5a..cecda683 100644
--- a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/resources/META-INF/spring.factories
+++ b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/resources/META-INF/spring.factories
@@ -1 +1,4 @@
-org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.dev33.satoken.reactor.spring.SaBeanInject
\ No newline at end of file
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+cn.dev33.satoken.reactor.spring.SaBeanRegister,\
+cn.dev33.satoken.reactor.spring.SaBeanInject,\
+cn.dev33.satoken.reactor.spring.SaHistoryVersionInject
\ No newline at end of file
diff --git a/sa-token-starter/sa-token-spring-boot-starter/pom.xml b/sa-token-starter/sa-token-spring-boot-starter/pom.xml
index ba0ffd58..582e408a 100644
--- a/sa-token-starter/sa-token-spring-boot-starter/pom.xml
+++ b/sa-token-starter/sa-token-spring-boot-starter/pom.xml
@@ -26,6 +26,13 @@
spring-boot-starter-web
2.0.0.RELEASE
+
+
+ cn.dev33
+ sa-token-oauth2
+ ${sa-token-version}
+ true
+
org.springframework.boot
diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaBeanInject.java b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaBeanInject.java
index a59b01de..887b47ef 100644
--- a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaBeanInject.java
+++ b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaBeanInject.java
@@ -2,8 +2,6 @@ package cn.dev33.satoken.spring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.context.annotation.Import;
-import org.springframework.stereotype.Component;
import org.springframework.util.PathMatcher;
import cn.dev33.satoken.SaManager;
@@ -21,8 +19,6 @@ import cn.dev33.satoken.temp.SaTempInterface;
* @author kong
*
*/
-@Component
-@Import({SaBeanRegister.class, SaHistoryVersionInject.class})
public class SaBeanInject {
/**
diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/oauth2/SaOAuth2BeanInject.java b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/oauth2/SaOAuth2BeanInject.java
new file mode 100644
index 00000000..fd0380e8
--- /dev/null
+++ b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/oauth2/SaOAuth2BeanInject.java
@@ -0,0 +1,40 @@
+package cn.dev33.satoken.spring.oauth2;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+
+import cn.dev33.satoken.oauth2.SaOAuth2Manager;
+import cn.dev33.satoken.oauth2.config.SaOAuth2Config;
+import cn.dev33.satoken.oauth2.logic.SaOAuth2Template;
+import cn.dev33.satoken.oauth2.logic.SaOAuth2Util;
+
+/**
+ * 注入 Sa-Token-OAuth2 所需要的Bean
+ *
+ * @author kong
+ *
+ */
+@ConditionalOnClass(SaOAuth2Manager.class)
+public class SaOAuth2BeanInject {
+
+ /**
+ * 注入OAuth2配置Bean
+ *
+ * @param saOAuth2Config 配置对象
+ */
+ @Autowired(required = false)
+ public void setSaOAuth2Config(SaOAuth2Config saOAuth2Config) {
+ SaOAuth2Manager.setConfig(saOAuth2Config);
+ }
+
+ /**
+ * 注入代码模板Bean
+ *
+ * @param saOAuth2Template 代码模板Bean
+ */
+ @Autowired(required = false)
+ public void setSaOAuth2Interface(SaOAuth2Template saOAuth2Template) {
+ SaOAuth2Util.saOAuth2Template = saOAuth2Template;
+ }
+
+}
diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/oauth2/SaOAuth2BeanRegister.java b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/oauth2/SaOAuth2BeanRegister.java
new file mode 100644
index 00000000..0122d0a2
--- /dev/null
+++ b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/oauth2/SaOAuth2BeanRegister.java
@@ -0,0 +1,28 @@
+package cn.dev33.satoken.spring.oauth2;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+
+import cn.dev33.satoken.oauth2.SaOAuth2Manager;
+import cn.dev33.satoken.oauth2.config.SaOAuth2Config;
+
+/**
+ * 注册 Sa-Token-OAuth2 所需要的Bean
+ * @author kong
+ *
+ */
+@ConditionalOnClass(SaOAuth2Manager.class)
+public class SaOAuth2BeanRegister {
+
+ /**
+ * 获取OAuth2配置Bean
+ * @return 配置对象
+ */
+ @Bean
+ @ConfigurationProperties(prefix = "sa-token.oauth2")
+ public SaOAuth2Config getSaOAuth2Config() {
+ return new SaOAuth2Config();
+ }
+
+}
diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/oauth2/package-info.java b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/oauth2/package-info.java
new file mode 100644
index 00000000..793d87db
--- /dev/null
+++ b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/oauth2/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Sa-Token-OAuth2 模块自动化配置(只有引入了Sa-Token-OAuth2模块后,此包下的代码才会开始工作)
+ */
+package cn.dev33.satoken.spring.oauth2;
\ No newline at end of file
diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/main/resources/META-INF/spring.factories b/sa-token-starter/sa-token-spring-boot-starter/src/main/resources/META-INF/spring.factories
index bc9a42c0..2e7e333a 100644
--- a/sa-token-starter/sa-token-spring-boot-starter/src/main/resources/META-INF/spring.factories
+++ b/sa-token-starter/sa-token-spring-boot-starter/src/main/resources/META-INF/spring.factories
@@ -1 +1,6 @@
-org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.dev33.satoken.spring.SaBeanInject
\ No newline at end of file
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+cn.dev33.satoken.spring.SaBeanRegister,\
+cn.dev33.satoken.spring.SaBeanInject,\
+cn.dev33.satoken.spring.SaHistoryVersionInject,\
+cn.dev33.satoken.spring.oauth2.SaOAuth2BeanRegister,\
+cn.dev33.satoken.spring.oauth2.SaOAuth2BeanInject
\ No newline at end of file
|