细节优化、文档优化

This commit is contained in:
click33
2024-08-23 16:18:24 +08:00
parent 3345e3aaf9
commit 419ca3797c
30 changed files with 226 additions and 199 deletions

View File

@@ -58,7 +58,7 @@
- [配置 client 域名校验 ](/oauth2/oauth2-check-domain)
- [定制化登录页面与授权页面](/oauth2/oauth2-custom-login)
- [自定义 API 路由 ](/oauth2/oauth2-custom-api)
- [自定义 Scope 权限以处理器](/oauth2/oauth2-custom-scope-handler)
- [自定义 Scope 权限以处理器](/oauth2/oauth2-custom-scope)
- [为 Scope 划分等级](/oauth2/oauth2-scope-level)
- [自定义 grant_type](/oauth2/oauth2-custom-grant_type)
- [OAuth2-与登录会话实现数据互通](/oauth2/oauth2-interworking)

View File

@@ -14,7 +14,7 @@ public class SaOAuth2DataLoaderImpl implements SaOAuth2DataLoader {
if("1001".equals(clientId)) {
return new SaClientModel()
// ...
.addAllowUrls("*") // 所有允许授权的 url
.addAllowRedirectUris("*") // 所有允许授权的 url
// ...
}
return null;
@@ -23,7 +23,7 @@ public class SaOAuth2DataLoaderImpl implements SaOAuth2DataLoader {
}
```
配置项 `AllowUrls` 意为配置此 `Client` 端所有允许的授权地址,不在此配置项中的 URL 将无法下发 `code` 授权码。
配置项 `AllowRedirectUris` 意为配置此 `Client` 端所有允许的授权地址,不在此配置项中的 URL 将无法下发 `code` 授权码。
为了方便测试,上述代码将其配置为`*`,但是,<font color="#FF0000" >在生产环境中,此配置项绝对不能配置为 * </font>,否则会有被 `code` 劫持的风险。
@@ -40,7 +40,7 @@ public class SaOAuth2DataLoaderImpl implements SaOAuth2DataLoader {
### 2、防范方法
造成此漏洞的直接原因就是我们对此 client 配置了过于宽泛的 `AllowUrls` 允许授权地址,防范的方法也很简单,就是缩小 `AllowUrls` 授权范围。
造成此漏洞的直接原因就是我们对此 client 配置了过于宽泛的 `AllowRedirectUris` 允许授权地址,防范的方法也很简单,就是缩小 `AllowRedirectUris` 授权范围。
我们将其配置为一个具体的URL
@@ -53,7 +53,7 @@ public class SaOAuth2DataLoaderImpl implements SaOAuth2DataLoader {
if("1001".equals(clientId)) {
return new SaClientModel()
// ...
.addAllowUrls("http://sa-oauth-client.com:8002/") // 所有允许授权的 url
.addAllowRedirectUris("http://sa-oauth-client.com:8002/") // 所有允许授权的 url
// ...
}
return null;
@@ -66,7 +66,7 @@ public class SaOAuth2DataLoaderImpl implements SaOAuth2DataLoader {
![oauth2-feifa-rf](https://oss.dev33.cn/sa-token/doc/oauth2-new/oauth2-feifa-rf.png 's-w-sh')
域名没有通过校验,拒绝授权!
URL 没有通过校验,拒绝授权!
### 3、配置安全性参考表
@@ -81,10 +81,18 @@ public class SaOAuth2DataLoaderImpl implements SaOAuth2DataLoader {
### 4、其它规则
1、AllowUrls 配置的地址不允许出现 `@` 字符。
- 反例:`http://user@sa-token.cc`
- 反例:`http://sa-oauth-client.com@sa-token.cc`
*详见源码:[SaOAuth2Template.java](https://gitee.com/dromara/sa-token/blob/master/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/template/SaOAuth2Template.java)
`checkRightUrl` 方法。*
2、AllowUrls 配置的地址 `*` 通配符只允许出现在字符串末尾,不允许出现在字符串中间位置。
- 反例:`http*://sa-oauth-client.com/`
- 反例:`http://*.sa-oauth-client.com/`
*详见源码: [SaOAuth2Template.java](https://gitee.com/dromara/sa-token/blob/master/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/template/SaOAuth2Template.java)
`checkAllowUrlListStaticMethod` 方法。*

View File

@@ -12,7 +12,7 @@
@RestController
public class SaOAuth2ServerController {
// OAuth2-Server 端:处理所有 OAuth 相关请求
// OAuth2-Server 端:处理所有 OAuth2 相关请求
@RequestMapping("/oauth2/*")
public Object request() {
return SaOAuth2ServerProcessor.instance.dister();
@@ -33,7 +33,7 @@ public class SaOAuth2ServerController {
``` java
// 配置 OAuth2 相关参数
@Autowired
private void configOAuth2Server(SaOAuth2Config cfg) {
private void configOAuth2Server(SaOAuth2ServerConfig oauth2Server) {
// 自定义API地址
SaOAuth2Consts.Api.authorize = "/oauth2/authorize2";
// ...
@@ -76,7 +76,7 @@ public class SaOAuth2ServerController {
// Code 换 Access-Token || 模式三:密码式
@RequestMapping("/oauth2/token")
public Object token() {
return SaOAuth2ServerProcessor.instance.tokenOrPassword();
return SaOAuth2ServerProcessor.instance.token();
}
// Refresh-Token 刷新 Access-Token

View File

@@ -58,8 +58,9 @@ public class PhoneCodeGrantTypeHandler implements SaOAuth2GrantTypeHandlerInterf
}
@Override
public AccessTokenModel getAccessTokenModel(SaRequest req, String clientId, List<String> scopes) {
public AccessTokenModel getAccessToken(SaRequest req, String clientId, List<String> scopes) {
// 获取前端提交的参数
String phone = req.getParamNotNull("phone");
String code = req.getParamNotNull("code");
String realCode = SaManager.getSaTokenDao().get("phone_code:" + phone);
@@ -102,7 +103,7 @@ public class SaOAuth2DataLoaderImpl implements SaOAuth2DataLoader {
return new SaClientModel()
.setClientId("1001")
.setClientSecret("aaaa-bbbb-cccc-dddd-eeee")
.addAllowUrls("*")
.addAllowRedirectUris("*") // 所有允许授权的 url
.addContractScopes("openid", "userid", "userinfo")
.addAllowGrantTypes(
GrantType.authorization_code,

View File

@@ -10,9 +10,9 @@
``` java
@Autowired
public void configOAuth2Server(SaOAuth2Config cfg) {
public void configOAuth2Server(SaOAuth2ServerConfig oauth2Server) {
// 配置未登录时返回的View
cfg.notLoginView = ()->{
oauth2Server.notLoginView = ()->{
return new ModelAndView("xxx.html");
};
}
@@ -64,9 +64,9 @@ public SaResult ss(String name, String pwd) {
``` java
@Autowired
public void configOAuth2Server(SaOAuth2Config cfg) {
public void configOAuth2Server(SaOAuth2ServerConfig oauth2Server) {
// 配置:授权确认视图
cfg.confirmView = (clientId, scopes)->{
oauth2Server.confirmView = (clientId, scopes)->{
Map<String, Object> map = new HashMap<>();
map.put("clientId", clientId);
map.put("scope", scopes);

View File

@@ -1,4 +1,4 @@
# Sa-Token-OAuth2 与登录会话实现数据互通
# OAuth2 与登录会话实现数据互通
---
@@ -16,29 +16,35 @@
### OAuth2-Server 端数据互通
很简单,你只需要在 `SaOAuth2TemplateImpl` 实现类中继续重写 Access-Token 的生成策略:
很简单,你只需要在 `configOAuth2Server`重写 Access-Token 的生成策略:
``` java
@Component
public class SaOAuth2TemplateImpl extends SaOAuth2Template {
// Sa-Token OAuth2 定制化配置
@Autowired
public void configOAuth2Server(SaOAuth2ServerConfig oauth2Server) {
// 其它配置 ...
// ... 其它代码
// 重写 AccessToken 创建策略,返回会话令牌
SaOAuth2Strategy.instance.createAccessToken = (clientId, loginId, scopes) -> {
System.out.println("----返回会话令牌");
return StpUtil.createLoginSession(loginId);
};
// 重写 Access-Token 生成策略复用登录会话的Token
@Override
public String randomAccessToken(String clientId, Object loginId, String scope) {
String tokenValue = StpUtil.createLoginSession(loginId);
return tokenValue;
}
}
```
重启项目,然后在 OAuth2 模块授权登录,现在生成的 `access_token` ,可以用来访问 `satoken` 的会话接口了。
> [!WARNING| label:注意点]
> 数据互通,让前端与后端的交互更加方便,一个 token 即可访问所有接口但也一定程度上失去了OAuth2的 “不同 Client 不同权限” 的设计意义,
> 同时也默认每个 Client 都拥有了账号的会话权限access_token 与 satoken 为同一个)。
>
> 应该根据自己的架构合理分析是否应该整合数据互通。
### OAuth2-Client 数据互通
除了Server端Client端也可以打通 `access_token` 与 `satoken` 会话。做法是在 Client 端拿到 `access_token` 后进行登录时,使用 SaLoginModel 预定登录生成的 Token 值
除了Server端Client端也可以打通 `access_token` 与 `satoken` 会话。做法是在 Client 端拿到 `access_token` 后进行登录时,使用 `SaLoginModel` 预定登录生成的 Token 值
``` java
// 1. 获取到access_token
@@ -51,13 +57,6 @@ StpUtil.login(uid, SaLoginConfig.setToken(access_token));
```
> [!WARNING| label:注意点]
> 数据互通,让前端与后端的交互更加方便,一个 token 即可访问所有接口但也一定程度上失去了OAuth2的 “不同 Client 不同权限” 的设计意义,
> 同时也默认每个 Client 都拥有了账号的会话权限access_token 与 satoken 为同一个)。
>
> 应该根据自己的架构合理分析是否应该整合数据互通。

View File

@@ -23,23 +23,39 @@
<version>${sa.top.version}</version>
</dependency>
<!-- Sa-Token-OAuth2.0 模块 -->
<!-- Sa-Token OAuth2.0 模块 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-oauth2</artifactId>
<version>${sa.top.version}</version>
</dependency>
<!-- Sa-Token 整合 Redis (可选) -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redis-jackson</artifactId>
<version>${sa-token.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
```
<!-------- tab:Gradle 方式 -------->
``` gradle
// Sa-Token 权限认证在线文档https://sa-token.cc
implementation 'cn.dev33:sa-token-spring-boot-starter:${sa.top.version}'
// Sa-Token-OAuth2.0 模块
// Sa-Token OAuth2.0 模块
implementation 'cn.dev33:sa-token-oauth2:${sa.top.version}'
// Sa-Token 整合 Redis (可选)
implementation 'cn.dev33:sa-token-redis-jackson:${sa.top.version}'
implementation 'org.apache.commons:commons-pool2'
```
<!---------------------------- tabs:end ---------------------------->
Redis 相关依赖是非必须的,如果集成了 redis可以让你更细致的观察到 sa-token-oauth2 的底层数据格式。
### 3、开放服务
@@ -60,9 +76,16 @@ public class SaOAuth2DataLoaderImpl implements SaOAuth2DataLoader {
return new SaClientModel()
.setClientId("1001") // client id
.setClientSecret("aaaa-bbbb-cccc-dddd-eeee") // client 秘钥
.addAllowUrls("*") // 所有允许授权的 url
.addAllowRedirectUris("*") // 所有允许授权的 url
.addContractScopes("openid", "userid", "userinfo") // 所有签约的权限
.setIsAutoMode(true); // 是否自动判断开放的授权模式
.addAllowGrantTypes( // 所有允许的授权模式
GrantType.authorization_code, // 授权码式
GrantType.implicit, // 隐式式
GrantType.refresh_token, // 刷新令牌
GrantType.password, // 密码式
GrantType.client_credentials // 客户端模式
)
;
}
return null;
}
@@ -83,24 +106,24 @@ public class SaOAuth2DataLoaderImpl implements SaOAuth2DataLoader {
2、新建`SaOAuth2ServerController`
``` java
/**
* Sa-OAuth2 Server端 控制器
* Sa-Token OAuth2 Server端 控制器
*/
@RestController
public class SaOAuth2ServerController {
// 处理所有OAuth相关请求
// OAuth2-Server 端:处理所有 OAuth2 相关请求
@RequestMapping("/oauth2/*")
public Object request() {
System.out.println("------- 进入请求: " + SaHolder.getRequest().getUrl());
return SaOAuth2Handle.serverRequest();
return SaOAuth2ServerProcessor.instance.dister();
}
// Sa-OAuth2 定制化配置
// Sa-Token OAuth2 定制化配置
@Autowired
public void setSaOAuth2Config(SaOAuth2Config cfg) {
public void setSaOAuth2Config(SaOAuth2Config oauth2Server) {
// 配置未登录时返回的View
cfg.notLoginView = () -> {
oauth2Server.notLoginView = () -> {
String msg = "当前会话在OAuth-Server端尚未登录请先访问"
+ "<a href='/oauth2/doLogin?name=sa&pwd=123456' target='_blank'> doLogin登录 </a>"
+ "进行登录之后,刷新页面开始授权";
@@ -108,7 +131,7 @@ public class SaOAuth2ServerController {
};
// 配置:登录处理函数
cfg.doLoginHandle = (name, pwd) -> {
oauth2Server.doLoginHandle = (name, pwd) -> {
if("sa".equals(name) && "123456".equals(pwd)) {
StpUtil.login(10001);
return SaResult.ok();
@@ -117,7 +140,7 @@ public class SaOAuth2ServerController {
};
// 配置:确认授权时返回的 view
cfg.confirmView = (clientId, scopes) -> {
oauth2Server.confirmView = (clientId, scopes) -> {
String scopeStr = SaFoxUtil.convertListToString(scopes);
String yesCode =
"fetch('/oauth2/doConfirm?client_id=" + clientId + "&scope=" + scopeStr + "', {method: 'POST'})" +
@@ -132,16 +155,9 @@ public class SaOAuth2ServerController {
};
}
// 全局异常拦截
@ExceptionHandler
public SaResult handlerException(Exception e) {
e.printStackTrace();
return SaResult.error(e.getMessage());
}
}
```
注意:在`setDoLoginHandle`函数里如果要获取name, pwd以外的参数可通过`SaHolder.getRequest().getParam("xxx")`来获取
注意:在 `doLoginHandle` 函数里如果要获取 name, pwd 以外的参数,可通过 `SaHolder.getRequest().getParam("xxx")` 来获取
3、全局异常处理
``` java
@@ -164,7 +180,8 @@ public class GlobalExceptionHandler {
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-OAuth2 Server 端启动成功");
System.out.println(SaOAuth2Manager.getConfig());
}
}
```
@@ -173,7 +190,7 @@ public class SaOAuth2ServerApplication {
### 4、访问测试
1、由于暂未搭建Client端我们可以使用Sa-Token官网作为重定向URL进行测试
1、由于暂未搭建Client端我们可以使用 Sa-Token 官网作为重定向URL进行测试
``` url
http://sa-oauth-server.com:8000/oauth2/authorize?response_type=code&client_id=1001&redirect_uri=https://sa-token.cc&scope=openid
```
@@ -185,7 +202,7 @@ http://sa-oauth-server.com:8000/oauth2/authorize?response_type=code&client_id=10
3、点击doLogin进行登录之后刷新页面会提示我们确认授权
![sa-oauth2-server-scope](https://oss.dev33.cn/sa-token/doc/oauth2-new/sa-oauth2-server-scope.png 's-w-sh')
4、点击确认授权之后刷新页面,我们会被重定向至 redirect_uri 页面并携带了code参数
4、点击同意授权之后,我们会被重定向至 redirect_uri 页面并携带了code参数
![sa-oauth2-server-code](https://oss.dev33.cn/sa-token/doc/oauth2-new/sa-oauth2-server-code.png 's-w-sh')
@@ -194,7 +211,7 @@ http://sa-oauth-server.com:8000/oauth2/authorize?response_type=code&client_id=10
http://sa-oauth-server.com:8000/oauth2/token?grant_type=authorization_code&client_id=1001&client_secret=aaaa-bbbb-cccc-dddd-eeee&code={code}
```
将得到 `Access-Token`、`Refresh-Token`、`openid`等授权信息
将得到 `Access-Token`、`Refresh-Token`、`openid`等授权信息
``` js
{

View File

@@ -73,7 +73,7 @@ implementation 'cn.dev33:sa-token-redis-jackson:${sa.top.version}'
```
<!-------- tab:Gradle 方式 -------->
``` gradle
// Sa-Token 整合 Redis (使用 jackson 序列化方式)
// 提供Redis连接池
implementation 'org.apache.commons:commons-pool2'
```
<!---------------------------- tabs:end ------------------------------>

View File

@@ -294,18 +294,21 @@ sa-token.sso-client.is-slo=true
### 4、OAuth2.0相关配置
| 参数名称 | 类型 | 默认值 | 说明 |
| :-------- | :-------- | :-------- | :-------- |
| isCode | Boolean | true | 是否打开模式:授权码(`Authorization Code` |
| isImplicit | Boolean | true | 是否打开模式:隐藏式(`Implicit` |
| isPassword | Boolean | true | 是否打开模式:密码式(`Password` |
| isClient | Boolean | true | 是否打开模式:凭证式(`Client Credentials` |
| isNewRefresh | Boolean | false | 是否在每次 `Refresh-Token` 刷新 `Access-Token` 时,产生一个新的 Refresh-Token |
| codeTimeout | long | 300 | Code授权码 保存的时间(单位:秒) 默认五分钟 |
| accessTokenTimeout | long | 7200 | `Access-Token` 保存的时间(单位:秒)默认两个小时 |
| refreshTokenTimeout | long | 2592000 | `Refresh-Token` 保存的时间(单位:秒) 默认30 天 |
| clientTokenTimeout | long | 7200 | `Client-Token` 保存的时间(单位:秒) 默认两个小时 |
| pastClientTokenTimeout | long | 7200 | `Past-Client-Token` 保存的时间(单位:秒) ,默认为-1代表延续 `Client-Token` 的有效时间 |
| 参数名称 | 类型 | 默认值 | 说明 |
| :-------- | :-------- | :-------- | :-------- |
| enableAuthorizationCode | Boolean | true | 是否打开模式:授权码(`Authorization Code` |
| enableImplicit | Boolean | true | 是否打开模式:隐藏式(`Implicit` |
| enablePassword | Boolean | true | 是否打开模式:密码式(`Password` |
| enableClientCredentials | Boolean | true | 是否打开模式:凭证式(`Client Credentials` |
| isNewRefresh | Boolean | false | 是否在每次 `Refresh-Token` 刷新 `Access-Token` 时,产生一个新的 `Refresh-Token` |
| codeTimeout | long | 300 | Code授权码 保存的时间(单位:秒) 默认五分钟 |
| accessTokenTimeout | long | 7200 | `Access-Token` 保存的时间(单位:秒)默认两个小时 |
| refreshTokenTimeout | long | 2592000 | `Refresh-Token` 保存的时间(单位:秒) 默认30 天 |
| clientTokenTimeout | long | 7200 | `Client-Token` 保存的时间(单位:秒) 默认两个小时 |
| pastClientTokenTimeout | long | 7200 | `Past-Client-Token` 保存的时间(单位:秒) ,默认为-1代表延续 `Client-Token` 的有效时间 |
| openidDigestPrefix | String | openid_default_digest_prefix | 默认 openid 生成算法中使用的摘要前缀 |
| higherScope | String | | 指定高级权限,多个用逗号隔开 |
| lowerScope | String | | 指定低级权限,多个用逗号隔开 |
配置示例:
<!---------------------------- tabs:start ---------------------------->
@@ -313,44 +316,40 @@ sa-token.sso-client.is-slo=true
``` yaml
# Sa-Token 配置
sa-token:
token-name: satoken-server
token-name: sa-token-oauth2-server
# OAuth2.0 配置
oauth2:
is-code: true
is-implicit: true
is-password: true
is-client: true
oauth2-server:
enable-authorization-code: true
enable-implicit: true
enable-password: true
enable-client-credentials: true
```
<!------------- tab:properties 风格 ------------->
``` properties
# Sa-Token 配置
sa-token.token-name=satoken-server
sa-token.token-name=sa-token-oauth2-server
# OAuth2.0 配置
sa-token.oauth2.is-code=true
sa-token.oauth2.is-implicit=true
sa-token.oauth2.is-password=true
sa-token.oauth2.is-client=true
sa-token.oauth2-server.enable-authorization-code=true
sa-token.oauth2-server.enable-implicit=true
sa-token.oauth2-server.enable-password=true
sa-token.oauth2-server.enable-client-credentials=true
```
<!---------------------------- tabs:end ---------------------------->
##### SaClientModel属性定义
| 参数名称 | 类型 | 默认值 | 说明 |
| :-------- | :-------- | :-------- | :-------- |
| clientId | String | null | 应用id应该全局唯一 |
| clientSecret | String | null | 应用秘钥 |
| contractScope | String | null | 应用签约的所有权限, 多个用逗号隔开 |
| allowUrl | String | null | 应用允许授权的所有URL, 多个用逗号隔开 (可以使用 `*` 号通配符) |
| isCode | Boolean | false | 单独配置此 Client 是否打开模式:授权码(`Authorization Code` |
| isImplicit | Boolean | false | 单独配置此 Client 是否打开模式:隐藏式(`Implicit` |
| isPassword | Boolean | false | 单独配置此 Client 是否打开模式:密码式(`Password` |
| isClient | Boolean | false | 单独配置此 Client 是否打开模式:凭证式(`Client Credentials` |
| isAutoMode | Boolean | true | 是否自动判断此 Client 开放的授权模式。 参考:[详解](/use/config?id=配置项详解isAutoMode) |
| isNewRefresh | Boolean | 取全局配置 | 单独配置此Client是否在每次 `Refresh-Token` 刷新 `Access-Token` 时,产生一个新的 Refresh-Token [ 默认取全局配置 ] |
| accessTokenTimeout | long | 取全局配置 | 单独配置此Client`Access-Token` 保存的时间(单位:秒) [默认取全局配置] |
| refreshTokenTimeout | long | 取全局配置 | 单独配置此Client`Refresh-Token` 保存的时间(单位:秒) [默认取全局配置] |
| clientTokenTimeout | long | 取全局配置 | 单独配置此Client`Client-Token` 保存的时间(单位:秒) [默认取全局配置] |
| pastClientTokenTimeout | long | 取全局配置 | 单独配置此Client`Past-Client-Token` 保存的时间(单位:秒) [默认取全局配置] |
| 参数名称 | 类型 | 默认值 | 说明 |
| :-------- | :-------- | :-------- | :-------- |
| clientId | String | null | 应用id应该全局唯一 |
| clientSecret | String | null | 应用秘钥 |
| contractScopes | List<String> | null | 应用签约的所有权限 |
| allowUrls | List<String> | null | 应用允许授权的所有URL可以使用 `*` 号通配符) |
| allowGrantTypes | List<String> | new ArrayList<>() | 应用允许的所有 `grant_type` |
| isNewRefresh | Boolean | 取全局配置 | 单独配置此Client是否在每次 `Refresh-Token` 刷新 `Access-Token` 时,产生一个新的 Refresh-Token [ 默认取全局配置 ] |
| accessTokenTimeout | long | 取全局配置 | 单独配置此Client`Access-Token` 保存的时间(单位:秒) [默认取全局配置] |
| refreshTokenTimeout | long | 取全局配置 | 单独配置此Client`Refresh-Token` 保存的时间(单位:秒) [默认取全局配置] |
| clientTokenTimeout | long | 取全局配置 | 单独配置此Client`Client-Token` 保存的时间(单位:秒) [默认取全局配置] |
| pastClientTokenTimeout | long | 取全局配置 | 单独配置此Client`Past-Client-Token` 保存的时间(单位:秒) [默认取全局配置] |
@@ -392,14 +391,14 @@ sa-token.oauth2.is-client=true
但是 —— 有的场景下我们又确实需要在登录之前就使用 Token-Session 对象,这时候就把配置项 `tokenSessionCheckLogin` 值改为 `false` 即可。
<!--
#### 配置项详解isAutoMode
配置含义:是否自动判断此 Client 开放的授权模式。
- 此值为 true 时:四种模式(`isCode、isImplicit、isPassword、isClient`)是否生效,依靠全局设置;
- 此值为 false 时:四种模式(`isCode、isImplicit、isPassword、isClient`)是否生效,依靠局部配置+全局配置(两个都为 true 时才打开)
-->
#### 配置项详解isHttp