mirror of
https://gitee.com/dromara/sa-token.git
synced 2025-12-20 03:49:45 +08:00
完整适配拆分式路由写法
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package com.pj;
|
||||
|
||||
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@@ -12,7 +13,8 @@ public class SaOAuth2ServerApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SaOAuth2ServerApplication.class, args);
|
||||
System.out.println("\nSa-Token-OAuth Server端启动成功");
|
||||
System.out.println("\nSa-Token-OAuth Server端启动成功,配置如下:");
|
||||
System.out.println(SaOAuth2Manager.getConfig());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,7 +22,11 @@ public class SaOAuth2DataLoaderImpl implements SaOAuth2DataLoader {
|
||||
.setClientSecret("aaaa-bbbb-cccc-dddd-eeee") // client 秘钥
|
||||
.addAllowUrls("*") // 所有允许授权的 url
|
||||
.addContractScopes("openid", "userid", "userinfo") // 所有签约的权限
|
||||
.setIsAutoMode(true); // 是否自动判断开放的授权模式
|
||||
.setEnableCode(true) // 是否开启授权码模式
|
||||
.setEnableImplicit(true) // 是否开启隐式模式
|
||||
.setEnablePassword(true) // 是否开启密码模式
|
||||
.setEnableClient(true) // 是否开启客户端模式
|
||||
;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import cn.dev33.satoken.oauth2.template.SaOAuth2Util;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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;
|
||||
@@ -17,20 +16,20 @@ import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Sa-OAuth2 Server端 控制器
|
||||
* Sa-Token-OAuth2 Server端 Controller
|
||||
*
|
||||
* @author click33
|
||||
*
|
||||
*/
|
||||
@RestController
|
||||
public class SaOAuth2ServerController {
|
||||
|
||||
// 处理所有OAuth相关请求
|
||||
// OAuth2-Server 端:处理所有OAuth相关请求
|
||||
@RequestMapping("/oauth2/*")
|
||||
public Object request() {
|
||||
System.out.println("------- 进入请求: " + SaHolder.getRequest().getUrl());
|
||||
return SaOAuth2ServerProcessor.instance.dister();
|
||||
}
|
||||
|
||||
|
||||
// Sa-OAuth2 定制化配置
|
||||
@Autowired
|
||||
public void configOAuth2Server(SaOAuth2Config cfg) {
|
||||
@@ -57,13 +56,6 @@ public class SaOAuth2ServerController {
|
||||
};
|
||||
}
|
||||
|
||||
// 全局异常拦截
|
||||
@ExceptionHandler
|
||||
public SaResult handlerException(Exception e) {
|
||||
e.printStackTrace();
|
||||
return SaResult.error(e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
// ---------- 开放相关资源接口: Client端根据 Access-Token ,置换相关资源 ------------
|
||||
|
||||
|
||||
@@ -3,15 +3,19 @@ server:
|
||||
|
||||
# sa-token配置
|
||||
sa-token:
|
||||
# token名称 (同时也是cookie名称)
|
||||
token-name: satoken-server
|
||||
# token名称 (同时也是 Cookie 名称)
|
||||
token-name: satoken-oauth2-server
|
||||
# OAuth2.0 配置
|
||||
oauth2:
|
||||
is-code: true
|
||||
is-implicit: true
|
||||
is-password: true
|
||||
is-client: true
|
||||
|
||||
oauth2:
|
||||
# 是否全局开启授权码模式
|
||||
enable-code: true
|
||||
# 是否全局开启 Implicit 模式
|
||||
enable-implicit: true
|
||||
# 是否全局开启密码模式
|
||||
enable-password: true
|
||||
# 是否全局开启客户端模式
|
||||
enable-client: true
|
||||
|
||||
spring:
|
||||
# redis配置
|
||||
redis:
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
- [OAuth2-Server端开放 API 接口](/oauth2/oauth2-apidoc)
|
||||
- [配置 client 域名校验 ](/oauth2/oauth2-check-domain)
|
||||
- [定制化登录页面与授权页面](/oauth2/oauth2-custom-login)
|
||||
- [拆分式路由](/oauth2/3)
|
||||
- [自定义 API 路由 ](/oauth2/oauth2-custom-api)
|
||||
- [前后端分离模式整合方案](/oauth2/4)
|
||||
- [平台中心模式开发](/oauth2/5)
|
||||
- [自定义 Scope 权限以处理器](/oauth2/6)
|
||||
|
||||
104
sa-token-doc/oauth2/oauth2-custom-api.md
Normal file
104
sa-token-doc/oauth2/oauth2-custom-api.md
Normal file
@@ -0,0 +1,104 @@
|
||||
# OAuth2-自定义 API 路由
|
||||
|
||||
---
|
||||
|
||||
### 方式一:修改全局变量
|
||||
|
||||
在之前的章节中,我们演示了如何搭建一个 OAuth2 认证中心:
|
||||
``` java
|
||||
/**
|
||||
* Sa-Token-OAuth2 Server端 Controller
|
||||
*/
|
||||
@RestController
|
||||
public class SaOAuth2ServerController {
|
||||
|
||||
// OAuth2-Server 端:处理所有 OAuth 相关请求
|
||||
@RequestMapping("/oauth2/*")
|
||||
public Object request() {
|
||||
return SaOAuth2ServerProcessor.instance.dister();
|
||||
}
|
||||
|
||||
// ... 其它代码
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
这种写法集成简单但却不够灵活。例如获取 code 授权码地址只能是:`http://{host}:{port}/oauth2/authorize`,如果我们想要自定义其API地址,应该怎么做呢?
|
||||
|
||||
打开 OAuth2 模块相关源码,有关 API 的设计都定义在:
|
||||
[SaOAuth2Consts.java](https://gitee.com/dromara/sa-token/blob/master/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/consts/SaOAuth2Consts.java)
|
||||
中,我们可以对其进行二次修改。
|
||||
|
||||
例如,我们可以在 Main 方法启动类或者 OAuth2 配置方法中修改变量值:
|
||||
``` java
|
||||
// 配置 OAuth2 相关参数
|
||||
@Autowired
|
||||
private void configOAuth2Server(SaOAuth2Config cfg) {
|
||||
// 自定义API地址
|
||||
SaOAuth2Consts.Api.authorize = "/oauth2/authorize2";
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
启动项目,统一认证地址就被我们修改成了:`http://{host}:{port}/oauth2/authorize2`
|
||||
|
||||
|
||||
### 方式二:拆分路由入口
|
||||
根据上述路由入口:`@RequestMapping("/oauth2/*")`,我们给它起一个合适的名字 —— 聚合式路由。
|
||||
|
||||
与之对应的,我们可以将其修改为拆分式路由:
|
||||
|
||||
``` java
|
||||
/**
|
||||
* Sa-Token-OAuth2 Server端 Controller
|
||||
*/
|
||||
@RestController
|
||||
public class SaOAuth2ServerController {
|
||||
|
||||
// 模式一:Code授权码 || 模式二:隐藏式
|
||||
@RequestMapping("/oauth2/authorize")
|
||||
public Object authorize() {
|
||||
return SaOAuth2ServerProcessor.instance.authorize();
|
||||
}
|
||||
|
||||
// 用户登录
|
||||
@RequestMapping("/oauth2/doLogin")
|
||||
public Object doLogin() {
|
||||
return SaOAuth2ServerProcessor.instance.doLogin();
|
||||
}
|
||||
|
||||
// 用户确认授权
|
||||
@RequestMapping("/oauth2/doConfirm")
|
||||
public Object doConfirm() {
|
||||
return SaOAuth2ServerProcessor.instance.doConfirm();
|
||||
}
|
||||
|
||||
// Code 换 Access-Token || 模式三:密码式
|
||||
@RequestMapping("/oauth2/token")
|
||||
public Object token() {
|
||||
return SaOAuth2ServerProcessor.instance.tokenOrPassword();
|
||||
}
|
||||
|
||||
// Refresh-Token 刷新 Access-Token
|
||||
@RequestMapping("/oauth2/refresh")
|
||||
public Object refresh() {
|
||||
return SaOAuth2ServerProcessor.instance.refresh();
|
||||
}
|
||||
|
||||
// 回收 Access-Token
|
||||
@RequestMapping("/oauth2/revoke")
|
||||
public Object revoke() {
|
||||
return SaOAuth2ServerProcessor.instance.revoke();
|
||||
}
|
||||
|
||||
// 模式四:凭证式
|
||||
@RequestMapping("/oauth2/client_token")
|
||||
public Object clientToken() {
|
||||
return SaOAuth2ServerProcessor.instance.clientToken();
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
拆分式路由 与 聚合式路由 在功能上完全等价,且提供了更为细致的路由管控。
|
||||
|
||||
@@ -34,16 +34,16 @@ public class SaOAuth2Config implements Serializable {
|
||||
private static final long serialVersionUID = -6541180061782004705L;
|
||||
|
||||
/** 是否打开模式:授权码(Authorization Code) */
|
||||
public Boolean isCode = true;
|
||||
public Boolean enableCode = true;
|
||||
|
||||
/** 是否打开模式:隐藏式(Implicit) */
|
||||
public Boolean isImplicit = true;
|
||||
public Boolean enableImplicit = true;
|
||||
|
||||
/** 是否打开模式:密码式(Password) */
|
||||
public Boolean isPassword = true;
|
||||
public Boolean enablePassword = true;
|
||||
|
||||
/** 是否打开模式:凭证式(Client Credentials) */
|
||||
public Boolean isClient = true;
|
||||
public Boolean enableClient = true;
|
||||
|
||||
/** 是否在每次 Refresh-Token 刷新 Access-Token 时,产生一个新的 Refresh-Token */
|
||||
public Boolean isNewRefresh = false;
|
||||
@@ -69,59 +69,59 @@ public class SaOAuth2Config implements Serializable {
|
||||
|
||||
|
||||
/**
|
||||
* @return isCode
|
||||
* @return enableCode
|
||||
*/
|
||||
public Boolean getIsCode() {
|
||||
return isCode;
|
||||
public Boolean getEnableCode() {
|
||||
return enableCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isCode 要设置的 isCode
|
||||
* @param enableCode 要设置的 enableCode
|
||||
*/
|
||||
public void setIsCode(Boolean isCode) {
|
||||
this.isCode = isCode;
|
||||
public void setEnableCode(Boolean enableCode) {
|
||||
this.enableCode = enableCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return isImplicit
|
||||
* @return enableImplicit
|
||||
*/
|
||||
public Boolean getIsImplicit() {
|
||||
return isImplicit;
|
||||
public Boolean getEnableImplicit() {
|
||||
return enableImplicit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isImplicit 要设置的 isImplicit
|
||||
* @param enableImplicit 要设置的 enableImplicit
|
||||
*/
|
||||
public void setIsImplicit(Boolean isImplicit) {
|
||||
this.isImplicit = isImplicit;
|
||||
public void setEnableImplicit(Boolean enableImplicit) {
|
||||
this.enableImplicit = enableImplicit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return isPassword
|
||||
* @return enablePassword
|
||||
*/
|
||||
public Boolean getIsPassword() {
|
||||
return isPassword;
|
||||
public Boolean getEnablePassword() {
|
||||
return enablePassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isPassword 要设置的 isPassword
|
||||
* @param enablePassword 要设置的 enablePassword
|
||||
*/
|
||||
public void setIsPassword(Boolean isPassword) {
|
||||
this.isPassword = isPassword;
|
||||
public void setEnablePassword(Boolean enablePassword) {
|
||||
this.enablePassword = enablePassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return isClient
|
||||
* @return enableClient
|
||||
*/
|
||||
public Boolean getIsClient() {
|
||||
return isClient;
|
||||
public Boolean getEnableClient() {
|
||||
return enableClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isClient 要设置的 isClient
|
||||
* @param enableClient 要设置的 enableClient
|
||||
*/
|
||||
public void setIsClient(Boolean isClient) {
|
||||
this.isClient = isClient;
|
||||
public void setEnableClient(Boolean enableClient) {
|
||||
this.enableClient = enableClient;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -254,8 +254,11 @@ public class SaOAuth2Config implements Serializable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SaOAuth2Config [isCode=" + isCode + ", isImplicit=" + isImplicit + ", isPassword=" + isPassword
|
||||
+ ", isClient=" + isClient
|
||||
return "SaOAuth2Config [" +
|
||||
"enableCode=" + enableCode
|
||||
+ ", enableImplicit=" + enableImplicit
|
||||
+ ", enablePassword=" + enablePassword
|
||||
+ ", enableClient=" + enableClient
|
||||
+ ", isNewRefresh=" + isNewRefresh
|
||||
+ ", codeTimeout=" + codeTimeout
|
||||
+ ", accessTokenTimeout=" + accessTokenTimeout
|
||||
|
||||
@@ -100,8 +100,8 @@ public class SaOAuth2DataConverterDefaultImpl implements SaOAuth2DataConverter {
|
||||
rt.expiresTime = System.currentTimeMillis() + (clientModel.getRefreshTokenTimeout() * 1000);
|
||||
rt.extraData = new LinkedHashMap<>(at.extraData);
|
||||
// 改变 at 属性
|
||||
at.refreshToken = rt.refreshToken;
|
||||
at.refreshExpiresTime = rt.expiresTime;
|
||||
// at.refreshToken = rt.refreshToken;
|
||||
// at.refreshExpiresTime = rt.expiresTime;
|
||||
return rt;
|
||||
}
|
||||
|
||||
|
||||
@@ -87,10 +87,10 @@ public class SaOAuth2DataGenerateDefaultImpl implements SaOAuth2DataGenerate {
|
||||
|
||||
// 3、生成token
|
||||
AccessTokenModel at = dataConverter.convertCodeToAccessToken(cm);
|
||||
SaOAuth2Strategy.instance.workAccessTokenByScope.accept(at);
|
||||
RefreshTokenModel rt = dataConverter.convertAccessTokenToRefreshToken(at);
|
||||
at.refreshToken = rt.refreshToken;
|
||||
at.refreshExpiresTime = rt.expiresTime;
|
||||
SaOAuth2Strategy.instance.workAccessTokenByScope.accept(at);
|
||||
|
||||
// 4、保存token
|
||||
dao.saveAccessToken(at);
|
||||
@@ -166,14 +166,20 @@ public class SaOAuth2DataGenerateDefaultImpl implements SaOAuth2DataGenerate {
|
||||
// 2、生成 新Access-Token
|
||||
String newAtValue = SaOAuth2Strategy.instance.createAccessToken.execute(ra.clientId, ra.loginId, ra.scopes);
|
||||
AccessTokenModel at = new AccessTokenModel(newAtValue, ra.clientId, ra.loginId, ra.scopes);
|
||||
// TODO 此处的 openid 应该怎么加载?
|
||||
// at.openid = SaOAuth2Manager.getDataLoader().getOpenid(ra.clientId, ra.loginId);
|
||||
|
||||
// 3、根据权限构建额外参数
|
||||
at.extraData = new LinkedHashMap<>();
|
||||
SaOAuth2Strategy.instance.workAccessTokenByScope.accept(at);
|
||||
|
||||
SaClientModel clientModel = SaOAuth2Manager.getDataLoader().getClientModelNotNull(ra.clientId);
|
||||
at.expiresTime = System.currentTimeMillis() + (clientModel.getAccessTokenTimeout() * 1000);
|
||||
|
||||
// 3、生成&保存 Refresh-Token
|
||||
if(isCreateRt) {
|
||||
RefreshTokenModel rt = SaOAuth2Manager.getDataConverter().convertAccessTokenToRefreshToken(at);
|
||||
at.refreshToken = rt.refreshToken;
|
||||
at.refreshExpiresTime = rt.expiresTime;
|
||||
|
||||
dao.saveRefreshToken(rt);
|
||||
dao.saveRefreshTokenIndex(rt);
|
||||
}
|
||||
|
||||
@@ -54,23 +54,23 @@ public class SaClientModel implements Serializable {
|
||||
public List<String> allowUrls;
|
||||
|
||||
/** 此 Client 是否打开模式:授权码(Authorization Code) */
|
||||
public Boolean isCode = false;
|
||||
public Boolean enableCode = false;
|
||||
|
||||
/** 此 Client 是否打开模式:隐藏式(Implicit) */
|
||||
public Boolean isImplicit = false;
|
||||
public Boolean enableImplicit = false;
|
||||
|
||||
/** 此 Client 是否打开模式:密码式(Password) */
|
||||
public Boolean isPassword = false;
|
||||
public Boolean enablePassword = false;
|
||||
|
||||
/** 此 Client 是否打开模式:凭证式(Client Credentials) */
|
||||
public Boolean isClient = false;
|
||||
public Boolean enableClient = false;
|
||||
|
||||
/**
|
||||
* 是否自动判断此 Client 开放的授权模式
|
||||
* <br> 此值为true时:四种模式(isCode、isImplicit、isPassword、isClient)是否生效,依靠全局设置
|
||||
* <br> 此值为false时:四种模式(isCode、isImplicit、isPassword、isClient)是否生效,依靠局部配置+全局配置
|
||||
*/
|
||||
public Boolean isAutoMode = true;
|
||||
// /**
|
||||
// * 是否自动判断此 Client 开放的授权模式
|
||||
// * <br> 此值为true时:四种模式(isCode、isImplicit、isPassword、isClient)是否生效,依靠全局设置
|
||||
// * <br> 此值为false时:四种模式(isCode、isImplicit、isPassword、isClient)是否生效,依靠局部配置+全局配置
|
||||
// */
|
||||
// public Boolean isAutoMode = true;
|
||||
|
||||
/** 单独配置此Client:是否在每次 Refresh-Token 刷新 Access-Token 时,产生一个新的 Refresh-Token [默认取全局配置] */
|
||||
public Boolean isNewRefresh;
|
||||
@@ -171,83 +171,83 @@ public class SaClientModel implements Serializable {
|
||||
/**
|
||||
* @return 此 Client 是否打开模式:授权码(Authorization Code)
|
||||
*/
|
||||
public Boolean getIsCode() {
|
||||
return isCode;
|
||||
public Boolean getEnableCode() {
|
||||
return enableCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isCode 此 Client 是否打开模式:授权码(Authorization Code)
|
||||
* @param enableCode 此 Client 是否打开模式:授权码(Authorization Code)
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaClientModel setIsCode(Boolean isCode) {
|
||||
this.isCode = isCode;
|
||||
public SaClientModel setEnableCode(Boolean enableCode) {
|
||||
this.enableCode = enableCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 此 Client 是否打开模式:隐藏式(Implicit)
|
||||
*/
|
||||
public Boolean getIsImplicit() {
|
||||
return isImplicit;
|
||||
public Boolean getEnableImplicit() {
|
||||
return enableImplicit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isImplicit 此 Client 是否打开模式:隐藏式(Implicit)
|
||||
* @param enableImplicit 此 Client 是否打开模式:隐藏式(Implicit)
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaClientModel setIsImplicit(Boolean isImplicit) {
|
||||
this.isImplicit = isImplicit;
|
||||
public SaClientModel setEnableImplicit(Boolean enableImplicit) {
|
||||
this.enableImplicit = enableImplicit;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 此 Client 是否打开模式:密码式(Password)
|
||||
*/
|
||||
public Boolean getIsPassword() {
|
||||
return isPassword;
|
||||
public Boolean getEnablePassword() {
|
||||
return enablePassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isPassword 此 Client 是否打开模式:密码式(Password)
|
||||
* @param enablePassword 此 Client 是否打开模式:密码式(Password)
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaClientModel setIsPassword(Boolean isPassword) {
|
||||
this.isPassword = isPassword;
|
||||
public SaClientModel setEnablePassword(Boolean enablePassword) {
|
||||
this.enablePassword = enablePassword;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 此 Client 是否打开模式:凭证式(Client Credentials)
|
||||
*/
|
||||
public Boolean getIsClient() {
|
||||
return isClient;
|
||||
public Boolean getEnableClient() {
|
||||
return enableClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isClient 此 Client 是否打开模式:凭证式(Client Credentials)
|
||||
* @param enableClient 此 Client 是否打开模式:凭证式(Client Credentials)
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaClientModel setIsClient(Boolean isClient) {
|
||||
this.isClient = isClient;
|
||||
public SaClientModel setEnableClient(Boolean enableClient) {
|
||||
this.enableClient = enableClient;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 是否自动判断此 Client 开放的授权模式
|
||||
*/
|
||||
public Boolean getIsAutoMode() {
|
||||
return isAutoMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isAutoMode 是否自动判断此 Client 开放的授权模式
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaClientModel setIsAutoMode(Boolean isAutoMode) {
|
||||
this.isAutoMode = isAutoMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
//
|
||||
// /**
|
||||
// * @return 是否自动判断此 Client 开放的授权模式
|
||||
// */
|
||||
// public Boolean getIsAutoMode() {
|
||||
// return isAutoMode;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * @param isAutoMode 是否自动判断此 Client 开放的授权模式
|
||||
// * @return 对象自身
|
||||
// */
|
||||
// public SaClientModel setIsAutoMode(Boolean isAutoMode) {
|
||||
// this.isAutoMode = isAutoMode;
|
||||
// return this;
|
||||
// }
|
||||
//
|
||||
|
||||
/**
|
||||
* @return 此Client:是否在每次 Refresh-Token 刷新 Access-Token 时,产生一个新的 Refresh-Token [默认取全局配置]
|
||||
@@ -338,11 +338,11 @@ public class SaClientModel implements Serializable {
|
||||
", clientSecret='" + clientSecret + '\'' +
|
||||
", contractScopes=" + contractScopes +
|
||||
", allowUrls=" + allowUrls +
|
||||
", isCode=" + isCode +
|
||||
", isImplicit=" + isImplicit +
|
||||
", isPassword=" + isPassword +
|
||||
", isClient=" + isClient +
|
||||
", isAutoMode=" + isAutoMode +
|
||||
", isCode=" + enableCode +
|
||||
", isImplicit=" + enableImplicit +
|
||||
", isPassword=" + enablePassword +
|
||||
", isClient=" + enableClient +
|
||||
// ", isAutoMode=" + isAutoMode +
|
||||
", isNewRefresh=" + isNewRefresh +
|
||||
", accessTokenTimeout=" + accessTokenTimeout +
|
||||
", refreshTokenTimeout=" + refreshTokenTimeout +
|
||||
|
||||
@@ -113,7 +113,7 @@ public class SaOAuth2DataResolverDefaultImpl implements SaOAuth2DataResolver {
|
||||
public Map<String, Object> buildClientTokenReturnValue(ClientTokenModel ct) {
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
map.put("client_token", ct.clientToken);
|
||||
map.put("access_token", ct.clientToken); // 兼容 OAuth2 协议
|
||||
// map.put("access_token", ct.clientToken); // 兼容 OAuth2 协议
|
||||
map.put("expires_in", ct.getExpiresIn());
|
||||
map.put("client_id", ct.clientId);
|
||||
map.put("scope", SaOAuth2Manager.getDataConverter().convertScopeListToString(ct.scopes));
|
||||
|
||||
@@ -98,6 +98,9 @@ public interface SaOAuth2ErrorCode {
|
||||
/** 无效response_type */
|
||||
int CODE_30125 = 30125;
|
||||
|
||||
/** 无效grant_type */
|
||||
int CODE_30126 = 30126;
|
||||
|
||||
/** 暂未开放授权码模式 */
|
||||
int CODE_30131 = 30131;
|
||||
|
||||
|
||||
@@ -71,28 +71,24 @@ public class SaOAuth2ServerProcessor {
|
||||
|
||||
// ------------------ 路由分发 ------------------
|
||||
|
||||
// 模式一:Code授权码
|
||||
if(req.isPath(Api.authorize) && req.isParam(Param.response_type, ResponseType.code)) {
|
||||
SaClientModel cm = currClientModel();
|
||||
if(cfg.getIsCode() && (cm.isCode || cm.isAutoMode)) {
|
||||
return authorize();
|
||||
}
|
||||
throw new SaOAuth2Exception("暂未开放的授权模式").setCode(SaOAuth2ErrorCode.CODE_30131);
|
||||
// 模式一:Code授权码 || 模式二:隐藏式
|
||||
if(req.isPath(Api.authorize)) {
|
||||
return authorize();
|
||||
}
|
||||
|
||||
// Code授权码 获取 Access-Token
|
||||
if(req.isPath(Api.token) && req.isParam(Param.grant_type, GrantType.authorization_code)) {
|
||||
return token();
|
||||
|
||||
// Code 换 Access-Token || 模式三:密码式
|
||||
if(req.isPath(Api.token)) {
|
||||
return tokenOrPassword();
|
||||
}
|
||||
|
||||
// Refresh-Token 刷新 Access-Token
|
||||
if(req.isPath(Api.refresh) && req.isParam(Param.grant_type, GrantType.refresh_token)) {
|
||||
return refreshToken();
|
||||
if(req.isPath(Api.refresh)) {
|
||||
return refresh();
|
||||
}
|
||||
|
||||
// 回收 Access-Token
|
||||
if(req.isPath(Api.revoke)) {
|
||||
return revokeToken();
|
||||
return revoke();
|
||||
}
|
||||
|
||||
// doLogin 登录接口
|
||||
@@ -105,31 +101,9 @@ public class SaOAuth2ServerProcessor {
|
||||
return doConfirm();
|
||||
}
|
||||
|
||||
// 模式二:隐藏式
|
||||
if(req.isPath(Api.authorize) && req.isParam(Param.response_type, ResponseType.token)) {
|
||||
SaClientModel cm = currClientModel();
|
||||
if(cfg.getIsImplicit() && (cm.isImplicit || cm.isAutoMode)) {
|
||||
return authorize();
|
||||
}
|
||||
throw new SaOAuth2Exception("暂未开放的授权模式").setCode(SaOAuth2ErrorCode.CODE_30132);
|
||||
}
|
||||
|
||||
// 模式三:密码式
|
||||
if(req.isPath(Api.token) && req.isParam(Param.grant_type, GrantType.password)) {
|
||||
SaClientModel cm = currClientModel();
|
||||
if(cfg.getIsPassword() && (cm.isPassword || cm.isAutoMode)) {
|
||||
return password();
|
||||
}
|
||||
throw new SaOAuth2Exception("暂未开放的授权模式").setCode(SaOAuth2ErrorCode.CODE_30133);
|
||||
}
|
||||
|
||||
// 模式四:凭证式
|
||||
if(req.isPath(Api.client_token) && req.isParam(Param.grant_type, GrantType.client_credentials)) {
|
||||
SaClientModel cm = currClientModel();
|
||||
if(cfg.getIsClient() && (cm.isClient || cm.isAutoMode)) {
|
||||
return clientToken();
|
||||
}
|
||||
throw new SaOAuth2Exception("暂未开放的授权模式").setCode(SaOAuth2ErrorCode.CODE_30134);
|
||||
if(req.isPath(Api.client_token)) {
|
||||
return clientToken();
|
||||
}
|
||||
|
||||
// 默认返回
|
||||
@@ -141,42 +115,67 @@ public class SaOAuth2ServerProcessor {
|
||||
* @return 处理结果
|
||||
*/
|
||||
public Object authorize() {
|
||||
|
||||
// 获取变量
|
||||
SaRequest req = SaHolder.getRequest();
|
||||
SaResponse res = SaHolder.getResponse();
|
||||
SaOAuth2Config cfg = SaOAuth2Manager.getConfig();
|
||||
SaOAuth2DataGenerate dataGenerate = SaOAuth2Manager.getDataGenerate();
|
||||
String responseType = req.getParamNotNull(Param.response_type);
|
||||
|
||||
// 1、如果尚未登录, 则先去登录
|
||||
// 1、先判断是否开启了指定的授权模式
|
||||
// 模式一:Code授权码
|
||||
if(responseType.equals(ResponseType.code)) {
|
||||
if(!cfg.enableCode) {
|
||||
throwErrorSystemNotEnableModel();
|
||||
}
|
||||
if(!currClientModel().enableCode) {
|
||||
throwErrorClientNotEnableModel();
|
||||
}
|
||||
}
|
||||
// 模式二:隐藏式
|
||||
else if(responseType.equals(ResponseType.token)) {
|
||||
if(!cfg.enableImplicit) {
|
||||
throwErrorSystemNotEnableModel();
|
||||
}
|
||||
if(!currClientModel().enableImplicit) {
|
||||
throwErrorClientNotEnableModel();
|
||||
}
|
||||
}
|
||||
// 其它
|
||||
else {
|
||||
throw new SaOAuth2Exception("无效 response_type: " + req.getParam(Param.response_type)).setCode(SaOAuth2ErrorCode.CODE_30125);
|
||||
}
|
||||
|
||||
// 2、如果尚未登录, 则先去登录
|
||||
if( ! getStpLogic().isLogin()) {
|
||||
return cfg.notLoginView.get();
|
||||
}
|
||||
|
||||
// 2、构建请求 Model
|
||||
// 3、构建请求 Model
|
||||
RequestAuthModel ra = SaOAuth2Manager.getDataResolver().readRequestAuthModel(req, getStpLogic().getLoginId());
|
||||
|
||||
// 3、校验:重定向域名是否合法
|
||||
// 4、校验:重定向域名是否合法
|
||||
oauth2Template.checkRightUrl(ra.clientId, ra.redirectUri);
|
||||
|
||||
// 4、校验:此次申请的Scope,该Client是否已经签约
|
||||
// 5、校验:此次申请的Scope,该Client是否已经签约
|
||||
oauth2Template.checkContract(ra.clientId, ra.scopes);
|
||||
|
||||
// 5、判断:如果此次申请的Scope,该用户尚未授权,则转到授权页面
|
||||
// 6、判断:如果此次申请的Scope,该用户尚未授权,则转到授权页面
|
||||
boolean isGrant = oauth2Template.isGrant(ra.loginId, ra.clientId, ra.scopes);
|
||||
if( ! isGrant) {
|
||||
return cfg.confirmView.apply(ra.clientId, ra.scopes);
|
||||
}
|
||||
|
||||
|
||||
// 6、判断授权类型
|
||||
// 如果是 授权码式,则:开始重定向授权,下放code
|
||||
// 7、判断授权类型,重定向到不同地址
|
||||
// 如果是 授权码式,则:开始重定向授权,下放code
|
||||
if(ResponseType.code.equals(ra.responseType)) {
|
||||
CodeModel codeModel = dataGenerate.generateCode(ra);
|
||||
String redirectUri = dataGenerate.buildRedirectUri(ra.redirectUri, codeModel.code, ra.state);
|
||||
return res.redirect(redirectUri);
|
||||
}
|
||||
|
||||
// 如果是 隐藏式,则:开始重定向授权,下放 token
|
||||
// 如果是 隐藏式,则:开始重定向授权,下放 token
|
||||
if(ResponseType.token.equals(ra.responseType)) {
|
||||
AccessTokenModel at = dataGenerate.generateAccessToken(ra, false);
|
||||
String redirectUri = dataGenerate.buildImplicitRedirectUri(ra.redirectUri, at.accessToken, ra.state);
|
||||
@@ -187,6 +186,34 @@ public class SaOAuth2ServerProcessor {
|
||||
throw new SaOAuth2Exception("无效response_type: " + ra.responseType).setCode(SaOAuth2ErrorCode.CODE_30125);
|
||||
}
|
||||
|
||||
/**
|
||||
* Code 换 Access-Token || 模式三:密码式
|
||||
* @return 处理结果
|
||||
*/
|
||||
public Object tokenOrPassword() {
|
||||
|
||||
String grantType = SaHolder.getRequest().getParamNotNull(Param.grant_type);
|
||||
|
||||
// Code 换 Access-Token
|
||||
if(grantType.equals(GrantType.authorization_code)) {
|
||||
return token();
|
||||
}
|
||||
|
||||
// 模式三:密码式
|
||||
if(grantType.equals(GrantType.password)) {
|
||||
SaOAuth2Config cfg = SaOAuth2Manager.getConfig();
|
||||
if(!cfg.enablePassword) {
|
||||
throwErrorSystemNotEnableModel();
|
||||
}
|
||||
if(!currClientModel().enablePassword) {
|
||||
throwErrorClientNotEnableModel();
|
||||
}
|
||||
return password();
|
||||
}
|
||||
|
||||
throw new SaOAuth2Exception("无效 grant_type:" + grantType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Code授权码 获取 Access-Token
|
||||
* @return 处理结果
|
||||
@@ -216,9 +243,13 @@ public class SaOAuth2ServerProcessor {
|
||||
* Refresh-Token 刷新 Access-Token
|
||||
* @return 处理结果
|
||||
*/
|
||||
public Object refreshToken() {
|
||||
public Object refresh() {
|
||||
// 获取变量
|
||||
SaRequest req = SaHolder.getRequest();
|
||||
String grantType = req.getParamNotNull(Param.grant_type);
|
||||
if(!grantType.equals(GrantType.refresh_token)) {
|
||||
throw new SaOAuth2Exception("无效 grant_type:" + grantType).setCode(SaOAuth2ErrorCode.CODE_30126);
|
||||
}
|
||||
|
||||
// 获取参数
|
||||
|
||||
@@ -241,7 +272,7 @@ public class SaOAuth2ServerProcessor {
|
||||
* 回收 Access-Token
|
||||
* @return 处理结果
|
||||
*/
|
||||
public Object revokeToken() {
|
||||
public Object revoke() {
|
||||
// 获取变量
|
||||
SaRequest req = SaHolder.getRequest();
|
||||
|
||||
@@ -344,6 +375,18 @@ public class SaOAuth2ServerProcessor {
|
||||
public Object clientToken() {
|
||||
// 获取变量
|
||||
SaRequest req = SaHolder.getRequest();
|
||||
SaOAuth2Config cfg = SaOAuth2Manager.getConfig();
|
||||
|
||||
String grantType = req.getParamNotNull(Param.grant_type);
|
||||
if(!grantType.equals(GrantType.client_credentials)) {
|
||||
throw new SaOAuth2Exception("无效 grant_type:" + grantType).setCode(SaOAuth2ErrorCode.CODE_30126);
|
||||
}
|
||||
if(!cfg.enableClient) {
|
||||
throwErrorSystemNotEnableModel();
|
||||
}
|
||||
if(!currClientModel().enableClient) {
|
||||
throwErrorClientNotEnableModel();
|
||||
}
|
||||
|
||||
// 获取参数
|
||||
ClientIdAndSecretModel clientIdAndSecret = SaOAuth2Manager.getDataResolver().readClientIdAndSecret(req);
|
||||
@@ -383,4 +426,18 @@ public class SaOAuth2ServerProcessor {
|
||||
return StpUtil.stpLogic;
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统未开放此授权模式时抛出异常
|
||||
*/
|
||||
public void throwErrorSystemNotEnableModel() {
|
||||
throw new SaOAuth2Exception("系统暂未开放此授权模式").setCode(SaOAuth2ErrorCode.CODE_30131);
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用未开放此授权模式时抛出异常
|
||||
*/
|
||||
public void throwErrorClientNotEnableModel() {
|
||||
throw new SaOAuth2Exception("应用暂未开放此授权模式").setCode(SaOAuth2ErrorCode.CODE_30131);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user