mirror of
https://github.com/chillzhuang/blade-tool
synced 2024-12-12 12:19:27 +08:00
🎉 2.2.0.RELEASE
This commit is contained in:
parent
7d088af59f
commit
70a1574a8a
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-tool</artifactId>
|
||||
<version>2.1.1</version>
|
||||
<version>2.2.0</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -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
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>blade-tool</artifactId>
|
||||
<groupId>org.springblade</groupId>
|
||||
<version>2.1.1</version>
|
||||
<version>2.2.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>blade-tool</artifactId>
|
||||
<groupId>org.springblade</groupId>
|
||||
<version>2.1.1</version>
|
||||
<version>2.2.0</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -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);
|
||||
|
@ -1,3 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* 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;
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* 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;
|
||||
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>blade-tool</artifactId>
|
||||
<groupId>org.springblade</groupId>
|
||||
<version>2.1.1</version>
|
||||
<version>2.2.0</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>blade-tool</artifactId>
|
||||
<groupId>org.springblade</groupId>
|
||||
<version>2.1.1</version>
|
||||
<version>2.2.0</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>blade-tool</artifactId>
|
||||
<groupId>org.springblade</groupId>
|
||||
<version>2.1.1</version>
|
||||
<version>2.2.0</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@ -28,6 +28,17 @@
|
||||
<artifactId>blade-core-tool</artifactId>
|
||||
<version>${blade.tool.version}</version>
|
||||
</dependency>
|
||||
<!--Jdbc-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>tomcat-jdbc</artifactId>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
@ -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";
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -24,7 +24,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
/**
|
||||
* secure模块api放行默认配置
|
||||
* secure注册默认配置
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* 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 = ?";
|
||||
|
||||
}
|
@ -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) {
|
||||
|
@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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 {
|
||||
|
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* 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<ClientSecure> client = new ArrayList<>();
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* 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<String> excludePatterns = new ArrayList<>();
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* 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<String> pathPatterns = new ArrayList<>();
|
||||
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* 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;
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* 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();
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* 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);
|
||||
|
||||
}
|
@ -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<String> patterns) {
|
||||
this.excludePatterns.addAll(patterns);
|
||||
|
@ -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<String, String> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>blade-tool</artifactId>
|
||||
<groupId>org.springblade</groupId>
|
||||
<version>2.1.1</version>
|
||||
<version>2.2.0</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-tool</artifactId>
|
||||
<version>2.1.1</version>
|
||||
<version>2.2.0</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -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对象
|
||||
|
4
pom.xml
4
pom.xml
@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-tool</artifactId>
|
||||
<version>2.1.1</version>
|
||||
<version>2.2.0</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>blade-tool</name>
|
||||
<description>
|
||||
@ -36,7 +36,7 @@
|
||||
</scm>
|
||||
|
||||
<properties>
|
||||
<blade.tool.version>2.1.1</blade.tool.version>
|
||||
<blade.tool.version>2.2.0</blade.tool.version>
|
||||
|
||||
<java.version>1.8</java.version>
|
||||
<maven.plugin.version>3.8.0</maven.plugin.version>
|
||||
|
Loading…
Reference in New Issue
Block a user