diff --git a/blade-core-boot/pom.xml b/blade-core-boot/pom.xml
index 7c1ab1e..b05be16 100644
--- a/blade-core-boot/pom.xml
+++ b/blade-core-boot/pom.xml
@@ -5,7 +5,7 @@
org.springblade
blade-tool
- 2.1.1
+ 2.2.0
4.0.0
diff --git a/blade-core-boot/src/main/resources/bootstrap.yml b/blade-core-boot/src/main/resources/bootstrap.yml
index de15ff2..06783df 100644
--- a/blade-core-boot/src/main/resources/bootstrap.yml
+++ b/blade-core-boot/src/main/resources/bootstrap.yml
@@ -29,6 +29,12 @@ spring:
add-mappings: false
datasource:
driver-class-name: com.mysql.jdbc.Driver
+ hikari:
+ connection-test-query: SELECT 1 FROM DUAL
+ connection-timeout: 30000
+ maximum-pool-size: 5
+ max-lifetime: 1800000
+ minimum-idle: 1
devtools:
restart:
log-condition-evaluation-delta: false
diff --git a/blade-core-cloud/pom.xml b/blade-core-cloud/pom.xml
index 4bf1274..8628617 100644
--- a/blade-core-cloud/pom.xml
+++ b/blade-core-cloud/pom.xml
@@ -5,7 +5,7 @@
blade-tool
org.springblade
- 2.1.1
+ 2.2.0
4.0.0
diff --git a/blade-core-launch/pom.xml b/blade-core-launch/pom.xml
index 43b1295..a1b4047 100644
--- a/blade-core-launch/pom.xml
+++ b/blade-core-launch/pom.xml
@@ -5,7 +5,7 @@
blade-tool
org.springblade
- 2.1.1
+ 2.2.0
4.0.0
diff --git a/blade-core-launch/src/main/java/org/springblade/core/launch/BladeApplication.java b/blade-core-launch/src/main/java/org/springblade/core/launch/BladeApplication.java
index 8b21bd2..9aa110c 100644
--- a/blade-core-launch/src/main/java/org/springblade/core/launch/BladeApplication.java
+++ b/blade-core-launch/src/main/java/org/springblade/core/launch/BladeApplication.java
@@ -93,6 +93,7 @@ public class BladeApplication {
props.setProperty("blade.is-local", String.valueOf(isLocalDev()));
props.setProperty("blade.dev-mode", profile.equals(AppConstant.PROD_CODE) ? "false" : "true");
props.setProperty("blade.service.version", AppConstant.APPLICATION_VERSION);
+ props.setProperty("spring.main.allow-bean-definition-overriding", "true");
props.setProperty("spring.cloud.nacos.discovery.server-addr", NacosConstant.NACOS_ADDR);
props.setProperty("spring.cloud.nacos.config.server-addr", NacosConstant.NACOS_ADDR);
props.setProperty("spring.cloud.nacos.config.prefix", NacosConstant.NACOS_CONFIG_PREFIX);
diff --git a/blade-core-launch/src/main/java/org/springblade/core/launch/constant/SentinelConstant.java b/blade-core-launch/src/main/java/org/springblade/core/launch/constant/SentinelConstant.java
index eaf7ed4..6cb0bc3 100644
--- a/blade-core-launch/src/main/java/org/springblade/core/launch/constant/SentinelConstant.java
+++ b/blade-core-launch/src/main/java/org/springblade/core/launch/constant/SentinelConstant.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.springblade.core.launch.constant;
/**
diff --git a/blade-core-launch/src/main/java/org/springblade/core/launch/constant/TokenConstant.java b/blade-core-launch/src/main/java/org/springblade/core/launch/constant/TokenConstant.java
new file mode 100644
index 0000000..3ee07c1
--- /dev/null
+++ b/blade-core-launch/src/main/java/org/springblade/core/launch/constant/TokenConstant.java
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.launch.constant;
+
+/**
+ * Token配置常量.
+ *
+ * @author Chill
+ */
+public interface TokenConstant {
+
+ String SIGN_KEY = "BladeX";
+ String AVATAR = "avatar";
+ String HEADER = "blade-auth";
+ String BEARER = "bearer";
+ String ACCESS_TOKEN = "access_token";
+ String REFRESH_TOKEN = "refresh_token";
+ String TOKEN_TYPE = "token_type";
+ String EXPIRES_IN = "expires_in";
+ String ACCOUNT = "account";
+ String USER_ID = "user_id";
+ String ROLE_ID = "role_id";
+ String USER_NAME = "user_name";
+ String ROLE_NAME = "role_name";
+ String TENANT_CODE = "tenant_code";
+ String CLIENT_ID = "client_id";
+ String LICENSE = "license";
+ String LICENSE_NAME = "powered by bladex";
+ String DEFAULT_AVATAR = "https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png";
+ Integer AUTH_LENGTH = 7;
+
+}
diff --git a/blade-core-log/pom.xml b/blade-core-log/pom.xml
index 36976e8..903825e 100644
--- a/blade-core-log/pom.xml
+++ b/blade-core-log/pom.xml
@@ -5,7 +5,7 @@
blade-tool
org.springblade
- 2.1.1
+ 2.2.0
4.0.0
diff --git a/blade-core-mybatis/pom.xml b/blade-core-mybatis/pom.xml
index 2aa136f..1a51835 100644
--- a/blade-core-mybatis/pom.xml
+++ b/blade-core-mybatis/pom.xml
@@ -5,7 +5,7 @@
blade-tool
org.springblade
- 2.1.1
+ 2.2.0
4.0.0
diff --git a/blade-core-secure/pom.xml b/blade-core-secure/pom.xml
index d8addd5..a63b07b 100644
--- a/blade-core-secure/pom.xml
+++ b/blade-core-secure/pom.xml
@@ -5,7 +5,7 @@
blade-tool
org.springblade
- 2.1.1
+ 2.2.0
4.0.0
@@ -28,6 +28,17 @@
blade-core-tool
${blade.tool.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-jdbc
+
+
+ tomcat-jdbc
+ org.apache.tomcat
+
+
+
diff --git a/blade-core-secure/src/main/java/org/springblade/core/secure/AuthInfo.java b/blade-core-secure/src/main/java/org/springblade/core/secure/AuthInfo.java
index 5eb486f..909d589 100644
--- a/blade-core-secure/src/main/java/org/springblade/core/secure/AuthInfo.java
+++ b/blade-core-secure/src/main/java/org/springblade/core/secure/AuthInfo.java
@@ -42,5 +42,5 @@ public class AuthInfo {
@ApiModelProperty(value = "过期时间")
private long expiresIn;
@ApiModelProperty(value = "许可证")
- private String license = "made by blade";
+ private String license = "powered by blade";
}
diff --git a/blade-core-secure/src/main/java/org/springblade/core/secure/BladeUser.java b/blade-core-secure/src/main/java/org/springblade/core/secure/BladeUser.java
index f10d2a9..2710976 100644
--- a/blade-core-secure/src/main/java/org/springblade/core/secure/BladeUser.java
+++ b/blade-core-secure/src/main/java/org/springblade/core/secure/BladeUser.java
@@ -29,6 +29,11 @@ import java.io.Serializable;
public class BladeUser implements Serializable {
private static final long serialVersionUID = 1L;
+ /**
+ * 客户端id
+ */
+ @ApiModelProperty(hidden = true)
+ private String clientId;
/**
* 用户id
diff --git a/blade-core-secure/src/main/java/org/springblade/core/secure/annotation/PreAuth.java b/blade-core-secure/src/main/java/org/springblade/core/secure/annotation/PreAuth.java
index 6cbd96a..1927cfc 100644
--- a/blade-core-secure/src/main/java/org/springblade/core/secure/annotation/PreAuth.java
+++ b/blade-core-secure/src/main/java/org/springblade/core/secure/annotation/PreAuth.java
@@ -20,7 +20,9 @@ import java.lang.annotation.*;
/**
* 权限注解 用于检查权限 规定访问权限
*
- * @author Chill
+ * @example @PreAuth("#userVO.id<10")
+ * @example @PreAuth("hasRole(#test, #test1)")
+ * @example @PreAuth("hasPermission(#test) and @PreAuth.hasPermission(#test)")
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
diff --git a/blade-core-secure/src/main/java/org/springblade/core/secure/config/RegistryConfiguration.java b/blade-core-secure/src/main/java/org/springblade/core/secure/config/RegistryConfiguration.java
index 9fd4d16..5c7fa37 100644
--- a/blade-core-secure/src/main/java/org/springblade/core/secure/config/RegistryConfiguration.java
+++ b/blade-core-secure/src/main/java/org/springblade/core/secure/config/RegistryConfiguration.java
@@ -24,7 +24,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
/**
- * secure模块api放行默认配置
+ * secure注册默认配置
*
* @author Chill
*/
diff --git a/blade-core-secure/src/main/java/org/springblade/core/secure/config/SecureConfiguration.java b/blade-core-secure/src/main/java/org/springblade/core/secure/config/SecureConfiguration.java
index 8e6917e..9f6df94 100644
--- a/blade-core-secure/src/main/java/org/springblade/core/secure/config/SecureConfiguration.java
+++ b/blade-core-secure/src/main/java/org/springblade/core/secure/config/SecureConfiguration.java
@@ -18,32 +18,50 @@ package org.springblade.core.secure.config;
import lombok.AllArgsConstructor;
import org.springblade.core.secure.aspect.AuthAspect;
+import org.springblade.core.secure.interceptor.ClientInterceptor;
import org.springblade.core.secure.interceptor.SecureInterceptor;
+import org.springblade.core.secure.props.BladeClientProperties;
+import org.springblade.core.secure.props.BladeSecureProperties;
+import org.springblade.core.secure.provider.ClientDetailsServiceImpl;
+import org.springblade.core.secure.provider.IClientDetailsService;
import org.springblade.core.secure.registry.SecureRegistry;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
+import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
- * 配置类
+ * 安全配置类
*
* @author Chill
*/
@Order
@Configuration
@AllArgsConstructor
+@EnableConfigurationProperties({BladeSecureProperties.class, BladeClientProperties.class})
public class SecureConfiguration implements WebMvcConfigurer {
private final SecureRegistry secureRegistry;
+ private final BladeSecureProperties secureProperties;
+
+ private final BladeClientProperties clientProperties;
+
+ private final JdbcTemplate jdbcTemplate;
+
@Override
public void addInterceptors(InterceptorRegistry registry) {
+ clientProperties.getClient().forEach(cs -> registry.addInterceptor(new ClientInterceptor(cs.getClientId())).addPathPatterns(cs.getPathPatterns()));
+
if (secureRegistry.isEnable()) {
registry.addInterceptor(new SecureInterceptor())
.excludePathPatterns(secureRegistry.getExcludePatterns())
- .excludePathPatterns(secureRegistry.getDefaultExcludePatterns());
+ .excludePathPatterns(secureRegistry.getDefaultExcludePatterns())
+ .excludePathPatterns(secureProperties.getExcludePatterns());
}
}
@@ -52,4 +70,10 @@ public class SecureConfiguration implements WebMvcConfigurer {
return new AuthAspect();
}
+ @Bean
+ @ConditionalOnMissingBean(IClientDetailsService.class)
+ public IClientDetailsService clientDetailsService() {
+ return new ClientDetailsServiceImpl(jdbcTemplate);
+ }
+
}
diff --git a/blade-core-secure/src/main/java/org/springblade/core/secure/constant/SecureConstant.java b/blade-core-secure/src/main/java/org/springblade/core/secure/constant/SecureConstant.java
new file mode 100644
index 0000000..f0f7534
--- /dev/null
+++ b/blade-core-secure/src/main/java/org/springblade/core/secure/constant/SecureConstant.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.secure.constant;
+
+/**
+ * 授权校验常量
+ *
+ * @author Chill
+ */
+public interface SecureConstant {
+
+ /**
+ * 认证请求头
+ */
+ String BASIC_HEADER_KEY = "Authorization";
+
+ /**
+ * 认证请求头前缀
+ */
+ String BASIC_HEADER_PREFIX = "Basic ";
+
+ /**
+ * blade_client表字段
+ */
+ String CLIENT_FIELDS = "client_id, client_secret, access_token_validity, refresh_token_validity";
+
+ /**
+ * blade_client查询语句
+ */
+ String BASE_STATEMENT = "select " + CLIENT_FIELDS + " from blade_client";
+
+ /**
+ * blade_client查询排序
+ */
+ String DEFAULT_FIND_STATEMENT = BASE_STATEMENT + " order by client_id";
+
+ /**
+ * 查询client_id
+ */
+ String DEFAULT_SELECT_STATEMENT = BASE_STATEMENT + " where client_id = ?";
+
+}
diff --git a/blade-core-secure/src/main/java/org/springblade/core/secure/exception/SecureException.java b/blade-core-secure/src/main/java/org/springblade/core/secure/exception/SecureException.java
index 18c689b..ddeecfd 100644
--- a/blade-core-secure/src/main/java/org/springblade/core/secure/exception/SecureException.java
+++ b/blade-core-secure/src/main/java/org/springblade/core/secure/exception/SecureException.java
@@ -32,7 +32,7 @@ public class SecureException extends RuntimeException {
public SecureException(String message) {
super(message);
- this.resultCode = ResultCode.INTERNAL_SERVER_ERROR;
+ this.resultCode = ResultCode.UN_AUTHORIZED;
}
public SecureException(IResultCode resultCode) {
diff --git a/blade-core-secure/src/main/java/org/springblade/core/secure/interceptor/ClientInterceptor.java b/blade-core-secure/src/main/java/org/springblade/core/secure/interceptor/ClientInterceptor.java
new file mode 100644
index 0000000..a39c925
--- /dev/null
+++ b/blade-core-secure/src/main/java/org/springblade/core/secure/interceptor/ClientInterceptor.java
@@ -0,0 +1,67 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.secure.interceptor;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springblade.core.secure.BladeUser;
+import org.springblade.core.secure.utils.SecureUtil;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.api.ResultCode;
+import org.springblade.core.tool.constant.BladeConstant;
+import org.springblade.core.tool.jackson.JsonUtil;
+import org.springblade.core.tool.utils.StringUtil;
+import org.springblade.core.tool.utils.WebUtil;
+import org.springframework.http.MediaType;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * 客户端校验
+ *
+ * @author Chill
+ */
+@Slf4j
+@AllArgsConstructor
+public class ClientInterceptor extends HandlerInterceptorAdapter {
+
+ private final String clientId;
+
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
+ BladeUser user = SecureUtil.getUser();
+ if (user != null && StringUtil.equals(clientId, SecureUtil.getClientIdFromHeader()) && StringUtil.equals(clientId, user.getClientId())) {
+ return true;
+ } else {
+ log.warn("客户端认证失败,请求接口:{},请求IP:{},请求参数:{}", request.getRequestURI(), WebUtil.getIP(request), JsonUtil.toJson(request.getParameterMap()));
+ R result = R.fail(ResultCode.UN_AUTHORIZED);
+ response.setHeader(BladeConstant.CONTENT_TYPE_NAME, MediaType.APPLICATION_JSON_UTF8_VALUE);
+ response.setCharacterEncoding(BladeConstant.UTF_8);
+ response.setStatus(HttpServletResponse.SC_OK);
+ try {
+ response.getWriter().write(Objects.requireNonNull(JsonUtil.toJson(result)));
+ } catch (IOException ex) {
+ log.error(ex.getMessage());
+ }
+ return false;
+ }
+ }
+
+}
diff --git a/blade-core-secure/src/main/java/org/springblade/core/secure/interceptor/SecureInterceptor.java b/blade-core-secure/src/main/java/org/springblade/core/secure/interceptor/SecureInterceptor.java
index 0c792b2..37f0d9c 100644
--- a/blade-core-secure/src/main/java/org/springblade/core/secure/interceptor/SecureInterceptor.java
+++ b/blade-core-secure/src/main/java/org/springblade/core/secure/interceptor/SecureInterceptor.java
@@ -15,13 +15,13 @@
*/
package org.springblade.core.secure.interceptor;
+import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.secure.utils.SecureUtil;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.api.ResultCode;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.jackson.JsonUtil;
-import org.springblade.core.tool.utils.StringPool;
import org.springblade.core.tool.utils.WebUtil;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
@@ -37,6 +37,7 @@ import java.util.Objects;
* @author Chill
*/
@Slf4j
+@AllArgsConstructor
public class SecureInterceptor extends HandlerInterceptorAdapter {
@Override
@@ -46,7 +47,7 @@ public class SecureInterceptor extends HandlerInterceptorAdapter {
} else {
log.warn("签名认证失败,请求接口:{},请求IP:{},请求参数:{}", request.getRequestURI(), WebUtil.getIP(request), JsonUtil.toJson(request.getParameterMap()));
R result = R.fail(ResultCode.UN_AUTHORIZED);
- response.setCharacterEncoding(StringPool.UTF_8);
+ response.setCharacterEncoding(BladeConstant.UTF_8);
response.setHeader(BladeConstant.CONTENT_TYPE_NAME, MediaType.APPLICATION_JSON_UTF8_VALUE);
response.setStatus(HttpServletResponse.SC_OK);
try {
diff --git a/blade-core-secure/src/main/java/org/springblade/core/secure/props/BladeClientProperties.java b/blade-core-secure/src/main/java/org/springblade/core/secure/props/BladeClientProperties.java
new file mode 100644
index 0000000..668f92a
--- /dev/null
+++ b/blade-core-secure/src/main/java/org/springblade/core/secure/props/BladeClientProperties.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.secure.props;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 客户端校验配置
+ *
+ * @author Chill
+ */
+@Data
+@ConfigurationProperties("blade.secure")
+public class BladeClientProperties {
+
+ private final List client = new ArrayList<>();
+
+}
diff --git a/blade-core-secure/src/main/java/org/springblade/core/secure/props/BladeSecureProperties.java b/blade-core-secure/src/main/java/org/springblade/core/secure/props/BladeSecureProperties.java
new file mode 100644
index 0000000..7ee3766
--- /dev/null
+++ b/blade-core-secure/src/main/java/org/springblade/core/secure/props/BladeSecureProperties.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.secure.props;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * secure放行额外配置
+ *
+ * @author Chill
+ */
+@Data
+@ConfigurationProperties("blade.secure.url")
+public class BladeSecureProperties {
+
+ private final List excludePatterns = new ArrayList<>();
+
+}
diff --git a/blade-core-secure/src/main/java/org/springblade/core/secure/props/ClientSecure.java b/blade-core-secure/src/main/java/org/springblade/core/secure/props/ClientSecure.java
new file mode 100644
index 0000000..e22481a
--- /dev/null
+++ b/blade-core-secure/src/main/java/org/springblade/core/secure/props/ClientSecure.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.secure.props;
+
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 客户端令牌认证信息
+ *
+ * @author Chill
+ */
+@Data
+public class ClientSecure {
+
+ private String clientId;
+
+ private final List pathPatterns = new ArrayList<>();
+
+}
diff --git a/blade-core-secure/src/main/java/org/springblade/core/secure/provider/ClientDetails.java b/blade-core-secure/src/main/java/org/springblade/core/secure/provider/ClientDetails.java
new file mode 100644
index 0000000..6df96b1
--- /dev/null
+++ b/blade-core-secure/src/main/java/org/springblade/core/secure/provider/ClientDetails.java
@@ -0,0 +1,51 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.secure.provider;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 客户端详情
+ *
+ * @author Chill
+ */
+@Data
+public class ClientDetails implements IClientDetails {
+
+ /**
+ * 客户端id
+ */
+ @ApiModelProperty(value = "客户端id")
+ private String clientId;
+ /**
+ * 客户端密钥
+ */
+ @ApiModelProperty(value = "客户端密钥")
+ private String clientSecret;
+
+ /**
+ * 令牌过期秒数
+ */
+ @ApiModelProperty(value = "令牌过期秒数")
+ private Integer accessTokenValidity;
+ /**
+ * 刷新令牌过期秒数
+ */
+ @ApiModelProperty(value = "刷新令牌过期秒数")
+ private Integer refreshTokenValidity;
+
+}
diff --git a/blade-core-secure/src/main/java/org/springblade/core/secure/provider/ClientDetailsServiceImpl.java b/blade-core-secure/src/main/java/org/springblade/core/secure/provider/ClientDetailsServiceImpl.java
new file mode 100644
index 0000000..66be625
--- /dev/null
+++ b/blade-core-secure/src/main/java/org/springblade/core/secure/provider/ClientDetailsServiceImpl.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.secure.provider;
+
+import lombok.AllArgsConstructor;
+import org.springblade.core.secure.constant.SecureConstant;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+/**
+ * 获取客户端详情
+ *
+ * @author Chill
+ */
+@AllArgsConstructor
+public class ClientDetailsServiceImpl implements IClientDetailsService {
+
+ private final JdbcTemplate jdbcTemplate;
+
+ @Override
+ public IClientDetails loadClientByClientId(String clientId) {
+ try {
+ return jdbcTemplate.queryForObject(SecureConstant.DEFAULT_SELECT_STATEMENT, new String[]{clientId}, new BeanPropertyRowMapper<>(ClientDetails.class));
+ } catch (Exception ex) {
+ return null;
+ }
+ }
+
+}
diff --git a/blade-core-secure/src/main/java/org/springblade/core/secure/provider/IClientDetails.java b/blade-core-secure/src/main/java/org/springblade/core/secure/provider/IClientDetails.java
new file mode 100644
index 0000000..eb0b191
--- /dev/null
+++ b/blade-core-secure/src/main/java/org/springblade/core/secure/provider/IClientDetails.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.secure.provider;
+
+import java.io.Serializable;
+
+/**
+ * 多终端详情接口
+ *
+ * @author Chill
+ */
+public interface IClientDetails extends Serializable {
+
+ /**
+ * 客户端id.
+ *
+ * @return String.
+ */
+ String getClientId();
+
+ /**
+ * 客户端密钥.
+ *
+ * @return String.
+ */
+ String getClientSecret();
+
+ /**
+ * 客户端token过期时间
+ *
+ * @return Integer
+ */
+ Integer getAccessTokenValidity();
+
+ /**
+ * 客户端刷新token过期时间
+ *
+ * @return Integer
+ */
+ Integer getRefreshTokenValidity();
+
+}
diff --git a/blade-core-secure/src/main/java/org/springblade/core/secure/provider/IClientDetailsService.java b/blade-core-secure/src/main/java/org/springblade/core/secure/provider/IClientDetailsService.java
new file mode 100644
index 0000000..52d3803
--- /dev/null
+++ b/blade-core-secure/src/main/java/org/springblade/core/secure/provider/IClientDetailsService.java
@@ -0,0 +1,33 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.secure.provider;
+
+/**
+ * 多终端注册接口
+ *
+ * @author Chill
+ */
+public interface IClientDetailsService {
+
+ /**
+ * 根据clientId获取Client详情
+ *
+ * @param clientId 客户端id
+ * @return
+ */
+ IClientDetails loadClientByClientId(String clientId);
+
+}
diff --git a/blade-core-secure/src/main/java/org/springblade/core/secure/registry/SecureRegistry.java b/blade-core-secure/src/main/java/org/springblade/core/secure/registry/SecureRegistry.java
index cdfe955..0f4544b 100644
--- a/blade-core-secure/src/main/java/org/springblade/core/secure/registry/SecureRegistry.java
+++ b/blade-core-secure/src/main/java/org/springblade/core/secure/registry/SecureRegistry.java
@@ -50,9 +50,6 @@ public class SecureRegistry {
/**
* 设置放行api
- *
- * @param patterns api配置
- * @return SecureRegistry
*/
public SecureRegistry excludePathPatterns(String... patterns) {
return excludePathPatterns(Arrays.asList(patterns));
@@ -60,9 +57,6 @@ public class SecureRegistry {
/**
* 设置放行api
- *
- * @param patterns api配置
- * @return SecureRegistry
*/
public SecureRegistry excludePathPatterns(List patterns) {
this.excludePatterns.addAll(patterns);
diff --git a/blade-core-secure/src/main/java/org/springblade/core/secure/utils/SecureUtil.java b/blade-core-secure/src/main/java/org/springblade/core/secure/utils/SecureUtil.java
index 9d00da6..b353b6b 100644
--- a/blade-core-secure/src/main/java/org/springblade/core/secure/utils/SecureUtil.java
+++ b/blade-core-secure/src/main/java/org/springblade/core/secure/utils/SecureUtil.java
@@ -19,19 +19,19 @@ import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
+import lombok.SneakyThrows;
+import org.springblade.core.launch.constant.TokenConstant;
import org.springblade.core.secure.BladeUser;
-import org.springblade.core.tool.utils.Charsets;
-import org.springblade.core.tool.utils.Func;
-import org.springblade.core.tool.utils.StringPool;
-import org.springblade.core.tool.utils.WebUtil;
+import org.springblade.core.secure.constant.SecureConstant;
+import org.springblade.core.secure.exception.SecureException;
+import org.springblade.core.secure.provider.IClientDetails;
+import org.springblade.core.secure.provider.IClientDetailsService;
+import org.springblade.core.tool.utils.*;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.security.Key;
-import java.util.Base64;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.Map;
+import java.util.*;
/**
* Secure工具类
@@ -39,18 +39,25 @@ import java.util.Map;
* @author Chill
*/
public class SecureUtil {
- public static final String BLADE_USER_REQUEST_ATTR = "_BLADE_USER_REQUEST_ATTR_";
+ private static final String BLADE_USER_REQUEST_ATTR = "_BLADE_USER_REQUEST_ATTR_";
- public final static String HEADER = "blade-auth";
- public final static String BEARER = "bearer";
- public final static String ACCOUNT = "account";
- public final static String USER_ID = "userId";
- public final static String ROLE_ID = "roleId";
- public final static String USER_NAME = "userName";
- public final static String ROLE_NAME = "roleName";
- public final static String TENANT_CODE = "tenantCode";
- public final static Integer AUTH_LENGTH = 7;
- public static String BASE64_SECURITY = Base64.getEncoder().encodeToString("BladeX".getBytes(Charsets.UTF_8));
+ private final static String HEADER = TokenConstant.HEADER;
+ private final static String BEARER = TokenConstant.BEARER;
+ private final static String ACCOUNT = TokenConstant.ACCOUNT;
+ private final static String USER_ID = TokenConstant.USER_ID;
+ private final static String ROLE_ID = TokenConstant.ROLE_ID;
+ private final static String USER_NAME = TokenConstant.USER_NAME;
+ private final static String ROLE_NAME = TokenConstant.ROLE_NAME;
+ private final static String TENANT_CODE = TokenConstant.TENANT_CODE;
+ private final static String CLIENT_ID = TokenConstant.CLIENT_ID;
+ private final static Integer AUTH_LENGTH = TokenConstant.AUTH_LENGTH;
+ private static String BASE64_SECURITY = Base64.getEncoder().encodeToString(TokenConstant.SIGN_KEY.getBytes(Charsets.UTF_8));
+
+ private static IClientDetailsService clientDetailsService;
+
+ static {
+ clientDetailsService = SpringUtil.getBean(IClientDetailsService.class);
+ }
/**
* 获取用户信息
@@ -59,8 +66,11 @@ public class SecureUtil {
*/
public static BladeUser getUser() {
HttpServletRequest request = WebUtil.getRequest();
+ if (request == null) {
+ return null;
+ }
// 优先从 request 中获取
- BladeUser bladeUser = (BladeUser) request.getAttribute(BLADE_USER_REQUEST_ATTR);
+ Object bladeUser = request.getAttribute(BLADE_USER_REQUEST_ATTR);
if (bladeUser == null) {
bladeUser = getUser(request);
if (bladeUser != null) {
@@ -68,7 +78,7 @@ public class SecureUtil {
request.setAttribute(BLADE_USER_REQUEST_ATTR, bladeUser);
}
}
- return bladeUser;
+ return (BladeUser) bladeUser;
}
/**
@@ -82,6 +92,7 @@ public class SecureUtil {
if (claims == null) {
return null;
}
+ String clientId = Func.toStr(claims.get(SecureUtil.CLIENT_ID));
Integer userId = Func.toInt(claims.get(SecureUtil.USER_ID));
String tenantCode = Func.toStr(claims.get(SecureUtil.TENANT_CODE));
String roleId = Func.toStr(claims.get(SecureUtil.ROLE_ID));
@@ -89,6 +100,7 @@ public class SecureUtil {
String roleName = Func.toStr(claims.get(SecureUtil.ROLE_NAME));
String userName = Func.toStr(claims.get(SecureUtil.USER_NAME));
BladeUser bladeUser = new BladeUser();
+ bladeUser.setClientId(clientId);
bladeUser.setUserId(userId);
bladeUser.setTenantCode(tenantCode);
bladeUser.setAccount(account);
@@ -183,7 +195,6 @@ public class SecureUtil {
return (null == user) ? StringPool.EMPTY : user.getRoleName();
}
-
/**
* 获取租户编号
*
@@ -205,6 +216,27 @@ public class SecureUtil {
return (null == user) ? StringPool.EMPTY : user.getTenantCode();
}
+ /**
+ * 获取客户端id
+ *
+ * @return tenantCode
+ */
+ public static String getClientId() {
+ BladeUser user = getUser();
+ return (null == user) ? StringPool.EMPTY : user.getClientId();
+ }
+
+ /**
+ * 获取客户端id
+ *
+ * @param request request
+ * @return tenantCode
+ */
+ public static String getClientId(HttpServletRequest request) {
+ BladeUser user = getUser(request);
+ return (null == user) ? StringPool.EMPTY : user.getClientId();
+ }
+
/**
* 获取Claims
*
@@ -229,7 +261,7 @@ public class SecureUtil {
* @return header
*/
public static String getHeader() {
- return getHeader(WebUtil.getRequest());
+ return getHeader(Objects.requireNonNull(WebUtil.getRequest()));
}
/**
@@ -250,17 +282,16 @@ public class SecureUtil {
*/
public static Claims parseJWT(String jsonWebToken) {
try {
- Claims claims = Jwts.parser()
+ return Jwts.parser()
.setSigningKey(Base64.getDecoder().decode(BASE64_SECURITY))
.parseClaimsJws(jsonWebToken).getBody();
- return claims;
} catch (Exception ex) {
return null;
}
}
/**
- * 创建jwt
+ * 创建令牌
*
* @param user user
* @param audience audience
@@ -269,6 +300,17 @@ public class SecureUtil {
* @return jwt
*/
public static String createJWT(Map user, String audience, String issuer, boolean isExpire) {
+
+ String[] tokens = extractAndDecodeHeader();
+ assert tokens.length == 2;
+ String clientId = tokens[0];
+ String clientSecret = tokens[1];
+
+ // 校验客户端信息
+ if (!validateClient(clientId, clientSecret)) {
+ throw new SecureException("客户端认证失败!");
+ }
+
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
long nowMillis = System.currentTimeMillis();
@@ -287,6 +329,9 @@ public class SecureUtil {
//设置JWT参数
user.forEach(builder::claim);
+ //设置应用id
+ builder.claim(CLIENT_ID, clientId);
+
//添加Token过期时间
if (isExpire) {
long expMillis = nowMillis + getExpire();
@@ -313,4 +358,65 @@ public class SecureUtil {
return cal.getTimeInMillis() - System.currentTimeMillis();
}
+ /**
+ * 获取过期时间的秒数(次日凌晨3点)
+ *
+ * @return expire
+ */
+ public static int getExpireSeconds() {
+ return (int) (getExpire() / 1000);
+ }
+
+ /**
+ * 客户端信息解码
+ */
+ @SneakyThrows
+ public static String[] extractAndDecodeHeader() {
+ // 获取请求头客户端信息
+ String header = Objects.requireNonNull(WebUtil.getRequest()).getHeader(SecureConstant.BASIC_HEADER_KEY);
+ if (header == null || !header.startsWith(SecureConstant.BASIC_HEADER_PREFIX)) {
+ throw new SecureException("No client information in request header");
+ }
+ byte[] base64Token = header.substring(6).getBytes(Charsets.UTF_8_NAME);
+
+ byte[] decoded;
+ try {
+ decoded = Base64.getDecoder().decode(base64Token);
+ } catch (IllegalArgumentException var7) {
+ throw new RuntimeException("Failed to decode basic authentication token");
+ }
+
+ String token = new String(decoded, Charsets.UTF_8_NAME);
+ int index = token.indexOf(StringPool.COLON);
+ if (index == -1) {
+ throw new RuntimeException("Invalid basic authentication token");
+ } else {
+ return new String[]{token.substring(0, index), token.substring(index + 1)};
+ }
+ }
+
+ /**
+ * 获取请求头中的客户端id
+ */
+ public static String getClientIdFromHeader() {
+ String[] tokens = extractAndDecodeHeader();
+ assert tokens.length == 2;
+ return tokens[0];
+ }
+
+ /**
+ * 校验Client
+ *
+ * @param clientId 客户端id
+ * @param clientSecret 客户端密钥
+ * @return boolean
+ */
+ private static boolean validateClient(String clientId, String clientSecret) {
+ IClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);
+ if (clientDetails != null) {
+ return StringUtil.equals(clientId, clientDetails.getClientId()) && StringUtil.equals(clientSecret, clientDetails.getClientSecret());
+ }
+ return false;
+ }
+
}
diff --git a/blade-core-swagger/pom.xml b/blade-core-swagger/pom.xml
index 9290121..aa30748 100644
--- a/blade-core-swagger/pom.xml
+++ b/blade-core-swagger/pom.xml
@@ -5,7 +5,7 @@
blade-tool
org.springblade
- 2.1.1
+ 2.2.0
4.0.0
diff --git a/blade-core-tool/pom.xml b/blade-core-tool/pom.xml
index 7a48dd1..a15876d 100644
--- a/blade-core-tool/pom.xml
+++ b/blade-core-tool/pom.xml
@@ -6,7 +6,7 @@
org.springblade
blade-tool
- 2.1.1
+ 2.2.0
4.0.0
diff --git a/blade-core-tool/src/main/java/org/springblade/core/tool/utils/Charsets.java b/blade-core-tool/src/main/java/org/springblade/core/tool/utils/Charsets.java
index 5b14e45..f9ef657 100644
--- a/blade-core-tool/src/main/java/org/springblade/core/tool/utils/Charsets.java
+++ b/blade-core-tool/src/main/java/org/springblade/core/tool/utils/Charsets.java
@@ -16,6 +16,7 @@
package org.springblade.core.tool.utils;
+import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.charset.UnsupportedCharsetException;
@@ -29,15 +30,20 @@ public class Charsets {
/**
* 字符集ISO-8859-1
*/
- public static final java.nio.charset.Charset ISO_8859_1 = StandardCharsets.ISO_8859_1;
+ public static final Charset ISO_8859_1 = StandardCharsets.ISO_8859_1;
+ public static final String ISO_8859_1_NAME = ISO_8859_1.name();
+
/**
* 字符集GBK
*/
- public static final java.nio.charset.Charset GBK = java.nio.charset.Charset.forName(StringPool.GBK);
+ public static final Charset GBK = Charset.forName(StringPool.GBK);
+ public static final String GBK_NAME = GBK.name();
+
/**
* 字符集utf-8
*/
- public static final java.nio.charset.Charset UTF_8 = StandardCharsets.UTF_8;
+ public static final Charset UTF_8 = StandardCharsets.UTF_8;
+ public static final String UTF_8_NAME = UTF_8.name();
/**
* 转换为Charset对象
diff --git a/pom.xml b/pom.xml
index 4e98e1a..b127552 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springblade
blade-tool
- 2.1.1
+ 2.2.0
pom
blade-tool
@@ -36,7 +36,7 @@
- 2.1.1
+ 2.2.0
1.8
3.8.0