Introducing new features. up springboot 3.1.0

This commit is contained in:
lbw 2023-05-26 15:46:52 +08:00
parent 4aaf739854
commit 8e2a302a73
467 changed files with 545 additions and 69983 deletions

View File

@ -1 +0,0 @@
java-baseline=8

View File

@ -1,54 +1,11 @@
<p align="center">
<img src="https://img.shields.io/badge/Pig-3.6-success.svg" alt="Build Status">
<img src="https://img.shields.io/badge/Spring%20Cloud-2021-blue.svg" alt="Coverage Status">
<img src="https://img.shields.io/badge/Spring%20Boot-2.7-blue.svg" alt="Downloads">
<img src="https://img.shields.io/badge/Vue-3.2-blue.svg" alt="Downloads">
<img src="https://img.shields.io/github/license/pig-mesh/pig"/>
</p>
## 系统说明
- 基于 Spring Cloud 2021 、Spring Boot 2.7、 OAuth2 的 RBAC **权限管理系统**
- 基于数据驱动视图的理念封装 element-plus即使没有 vue 的使用经验也能快速上手
- 提供对常见容器化支持 Docker、Kubernetes、Rancher2 支持
- 提供 lambda 、stream api 、webflux 的生产实践
## 文档视频
[ 🚀🚀🚀 低代码数据可视化](http://datav.avuejs.com)
[ 配套文档 wiki.pigx.vip](https://wiki.pigx.vip)
[ 配套视频 tv.pigx.vip](https://www.bilibili.com/video/BV12t411B7e9)
[PIGX 在线体验 pigx.pigx.vip](http://pigx.pigx.vip)
[产品白皮书 paper.pigx.vip](https://paper.pigx.vip)
## 微信群 [禁广告]
![](https://minio.pigx.vip/oss/1648184189.png)
## 快速开始
### 分支说明
| 分支 | 说明 |
|-----------------|-------------------------------------------------------------------|
| master | java8 + springboot 2.7 + springcloud 2021 |
| sca-springboot3 | java17 + springboot 3.0 + springcloud 2022 + spring cloud alibaba |
| sct-springboot3 | java17 + springboot 3.0 + springcloud 2022 + spring cloud tencent |
### 核心依赖
| 依赖 | 版本 |
| ---------------------- |----------------|
| Spring Boot | 3.0.6 |
| Spring Cloud | 2022.0.2 |
| Spring Cloud Alibaba | 2022.0.0.0-RC1 |
| Spring Authorization Server | 1.0.2 |
| Spring Boot | 3.1.0 |
| Spring Cloud | 2022.0.3 |
| Spring Cloud Alibaba | 2022.0.0.0-RC2 |
| Spring Authorization Server | 1.1.0 |
| Mybatis Plus | 3.5.3.1 |
| hutool | 5.8.18 |
@ -78,9 +35,7 @@ pig
└── pig-upms-biz -- 通用用户权限管理系统业务处理模块[4000]
└── pig-visual
└── pig-monitor -- 服务监控 [5001]
├── pig-codegen -- 图形化代码生成 [5002]
├── pig-sentinel-dashboard -- 流量高可用 [5003]
└── pig-xxl-job-admin -- 分布式定时任务管理台 [5004]
└── pig-codegen -- 图形化代码生成 [5002]
```
### 本地开发 运行

View File

@ -1,4 +1,4 @@
FROM mysql/mysql-server:8.0.31
FROM mysql/mysql-server:8.0.33
MAINTAINER lengleng(wangiegie@gmail.com)

View File

@ -37,7 +37,7 @@ CREATE TABLE `config_info` (
-- Records of config_info
-- ----------------------------
BEGIN;
INSERT INTO `config_info` VALUES (1, 'application-dev.yml', 'DEFAULT_GROUP', '# 密根密码\njasypt:\n encryptor:\n password: pig\n algorithm: PBEWithMD5AndDES\n iv-generator-classname: org.jasypt.iv.NoIvGenerator\n \n# Spring 相关\nspring:\n cache:\n type: redis\n data:\n redis:\n host: pig-redis\n port: 6379\n cloud:\n sentinel:\n eager: true\n transport:\n dashboard: pig-sentinel:5003\n\n# 暴露监控端点\nmanagement:\n endpoints:\n web:\n exposure:\n include: \"*\" \n endpoint:\n health:\n show-details: ALWAYS\n\n\n# feign 配置\nfeign:\n sentinel:\n enabled: true\n okhttp:\n enabled: true\n httpclient:\n enabled: false\n client:\n config:\n default:\n connectTimeout: 10000\n readTimeout: 10000\n compression:\n request:\n enabled: true\n response:\n enabled: true\n\n# mybaits-plus配置\nmybatis-plus:\n mapper-locations: classpath:/mapper/*Mapper.xml\n global-config:\n banner: false\n db-config:\n id-type: auto\n table-underline: true\n logic-delete-value: 1\n logic-not-delete-value: 0\n configuration:\n map-underscore-to-camel-case: true\n\n# spring security 配置\nsecurity:\n oauth2:\n # 通用放行URL服务个性化请在对应配置文件覆盖\n ignore:\n urls:\n - /v3/api-docs\n - /actuator/**\n\n# swagger 配置\nswagger:\n enabled: true\n title: Pig Swagger API\n gateway: http://${GATEWAY_HOST:pig-gateway}:${GATEWAY-PORT:9999}\n token-url: ${swagger.gateway}/auth/oauth2/token\n scope: server\n services:\n pig-upms-biz: admin\n pig-codegen: gen', 'f2d0080b18e6872e694764b687d936f8', '2022-05-08 12:10:37', '2022-12-23 16:24:33', 'nacos', '127.0.0.1', '', '', '', '', '', 'yaml', '', '');
INSERT INTO `config_info` VALUES (1, 'application-dev.yml', 'DEFAULT_GROUP', '# 配置文件加密根密码\njasypt:\n encryptor:\n password: pig\n algorithm: PBEWithMD5AndDES\n iv-generator-classname: org.jasypt.iv.NoIvGenerator\n \n# Spring 相关\nspring:\n cache:\n type: redis\n redis:\n host: pig-redis\n cloud:\n sentinel:\n eager: true\n transport:\n dashboard: pig-sentinel:5003\n\n# 暴露监控端点\nmanagement:\n endpoints:\n web:\n exposure:\n include: \"*\" \n endpoint:\n health:\n show-details: ALWAYS\n\n\n# feign 配置\nfeign:\n sentinel:\n enabled: true\n okhttp:\n enabled: true\n httpclient:\n enabled: false\n client:\n config:\n default:\n connectTimeout: 10000\n readTimeout: 10000\n compression:\n request:\n enabled: true\n response:\n enabled: true\n\n# mybaits-plus配置\nmybatis-plus:\n mapper-locations: classpath:/mapper/*Mapper.xml\n global-config:\n banner: false\n db-config:\n id-type: auto\n table-underline: true\n logic-delete-value: 1\n logic-not-delete-value: 0\n configuration:\n map-underscore-to-camel-case: true\n\n# swagger 配置\nswagger:\n enabled: true\n title: Pig Swagger API\n gateway: http://${GATEWAY_HOST:pig-gateway}:${GATEWAY-PORT:9999}\n token-url: ${swagger.gateway}/auth/oauth2/token\n scope: server', 'c9b41bce3b5ce5802d6592cab001f791', '2022-05-08 12:10:37', '2023-05-26 13:57:59', 'nacos', '127.0.0.1', '', '', '', '', '', 'yaml', '', '');
INSERT INTO `config_info` VALUES (2, 'pig-auth-dev.yml', 'DEFAULT_GROUP', '# 数据源\nspring:\n freemarker:\n allow-request-override: false\n allow-session-override: false\n cache: true\n charset: UTF-8\n check-template-location: true\n content-type: text/html\n enabled: true\n expose-request-attributes: false\n expose-session-attributes: false\n expose-spring-macro-helpers: true\n prefer-file-system-access: true\n suffix: .ftl\n template-loader-path: classpath:/templates/', '74f53b71c7799aa754da75662378b93c', '2022-05-08 12:10:37', '2022-06-04 14:15:35', 'nacos', '127.0.0.1', '', '', '', '', '', 'yaml', '', '');
INSERT INTO `config_info` VALUES (3, 'pig-codegen-dev.yml', 'DEFAULT_GROUP', '## spring security 配置1\nsecurity:\n oauth2:\n client:\n client-id: ENC(27v1agvAug87ANOVnbKdsw==)\n client-secret: ENC(VbnkopxrwgbFVKp+UxJ2pg==)\n scope: server\n\n# 数据源配置\nspring:\n datasource:\n type: com.zaxxer.hikari.HikariDataSource\n driver-class-name: com.mysql.cj.jdbc.Driver\n username: root\n password: root\n url: jdbc:mysql://pig-mysql:3306/pig_codegen?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true\n resources:\n static-locations: classpath:/static/,classpath:/views/\n', '6c6e48b793671dc2a0adffe2e2c27fb0', '2022-05-08 12:10:37', '2022-12-15 23:05:35', 'nacos', '127.0.0.1', '', '', '', '', '', 'yaml', '', '');
INSERT INTO `config_info` VALUES (4, 'pig-gateway-dev.yml', 'DEFAULT_GROUP', 'spring:\n cloud:\n gateway:\n locator:\n enabled: true\n routes:\n # 认证中心\n - id: pig-auth\n uri: lb://pig-auth\n predicates:\n - Path=/auth/**\n filters:\n # 验证码处理\n - ValidateCodeGatewayFilter\n # 前端密码解密\n - PasswordDecoderFilter\n #UPMS 模块\n - id: pig-upms-biz\n uri: lb://pig-upms-biz\n predicates:\n - Path=/admin/**\n filters:\n # 限流配置\n - name: RequestRateLimiter\n args:\n key-resolver: \'#{@remoteAddrKeyResolver}\'\n redis-rate-limiter.replenishRate: 100\n redis-rate-limiter.burstCapacity: 200\n # 代码生成模块\n - id: pig-codegen\n uri: lb://pig-codegen\n predicates:\n - Path=/gen/**\n # 固定路由转发配置 无修改\n - id: openapi\n uri: lb://pig-gateway\n predicates:\n - Path=/v3/api-docs/**\n filters:\n - RewritePath=/v3/api-docs/(?<path>.*), /$\\{path}/$\\{path}/v3/api-docs\n\ngateway:\n encode-key: \'thanks,pig4cloud\'\n ignore-clients:\n - test\n - client', '000988cf0102382d3f23df35027b47fd', '2022-05-08 12:10:37', '2022-06-07 14:00:11', 'nacos', '127.0.0.1', '', '', '', '', '', 'yaml', '', '');

View File

@ -1,120 +0,0 @@
DROP DATABASE IF EXISTS `pig_job`;
CREATE DATABASE `pig_job` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
use `pig_job`;
SET NAMES utf8;
CREATE TABLE `xxl_job_info` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`job_group` int(11) NOT NULL COMMENT '执行器主键ID',
`job_desc` varchar(255) NOT NULL,
`add_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
`author` varchar(64) DEFAULT NULL COMMENT '作者',
`alarm_email` varchar(255) DEFAULT NULL COMMENT '报警邮件',
`schedule_type` varchar(50) NOT NULL DEFAULT 'NONE' COMMENT '调度类型',
`schedule_conf` varchar(128) DEFAULT NULL COMMENT '调度配置,值含义取决于调度类型',
`misfire_strategy` varchar(50) NOT NULL DEFAULT 'DO_NOTHING' COMMENT '调度过期策略',
`executor_route_strategy` varchar(50) DEFAULT NULL COMMENT '执行器路由策略',
`executor_handler` varchar(255) DEFAULT NULL COMMENT '执行器任务handler',
`executor_param` varchar(512) DEFAULT NULL COMMENT '执行器任务参数',
`executor_block_strategy` varchar(50) DEFAULT NULL COMMENT '阻塞处理策略',
`executor_timeout` int(11) NOT NULL DEFAULT '0' COMMENT '任务执行超时时间,单位秒',
`executor_fail_retry_count` int(11) NOT NULL DEFAULT '0' COMMENT '失败重试次数',
`glue_type` varchar(50) NOT NULL COMMENT 'GLUE类型',
`glue_source` mediumtext COMMENT 'GLUE源代码',
`glue_remark` varchar(128) DEFAULT NULL COMMENT 'GLUE备注',
`glue_updatetime` datetime DEFAULT NULL COMMENT 'GLUE更新时间',
`child_jobid` varchar(255) DEFAULT NULL COMMENT '子任务ID多个逗号分隔',
`trigger_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '调度状态0-停止1-运行',
`trigger_last_time` bigint(13) NOT NULL DEFAULT '0' COMMENT '上次调度时间',
`trigger_next_time` bigint(13) NOT NULL DEFAULT '0' COMMENT '下次调度时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `xxl_job_log` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`job_group` int(11) NOT NULL COMMENT '执行器主键ID',
`job_id` int(11) NOT NULL COMMENT '任务主键ID',
`executor_address` varchar(255) DEFAULT NULL COMMENT '执行器地址,本次执行的地址',
`executor_handler` varchar(255) DEFAULT NULL COMMENT '执行器任务handler',
`executor_param` varchar(512) DEFAULT NULL COMMENT '执行器任务参数',
`executor_sharding_param` varchar(20) DEFAULT NULL COMMENT '执行器任务分片参数,格式如 1/2',
`executor_fail_retry_count` int(11) NOT NULL DEFAULT '0' COMMENT '失败重试次数',
`trigger_time` datetime DEFAULT NULL COMMENT '调度-时间',
`trigger_code` int(11) NOT NULL COMMENT '调度-结果',
`trigger_msg` text COMMENT '调度-日志',
`handle_time` datetime DEFAULT NULL COMMENT '执行-时间',
`handle_code` int(11) NOT NULL COMMENT '执行-状态',
`handle_msg` text COMMENT '执行-日志',
`alarm_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '告警状态0-默认、1-无需告警、2-告警成功、3-告警失败',
PRIMARY KEY (`id`),
KEY `I_trigger_time` (`trigger_time`),
KEY `I_handle_code` (`handle_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `xxl_job_log_report` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`trigger_day` datetime DEFAULT NULL COMMENT '调度-时间',
`running_count` int(11) NOT NULL DEFAULT '0' COMMENT '运行中-日志数量',
`suc_count` int(11) NOT NULL DEFAULT '0' COMMENT '执行成功-日志数量',
`fail_count` int(11) NOT NULL DEFAULT '0' COMMENT '执行失败-日志数量',
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `i_trigger_day` (`trigger_day`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `xxl_job_logglue` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`job_id` int(11) NOT NULL COMMENT '任务主键ID',
`glue_type` varchar(50) DEFAULT NULL COMMENT 'GLUE类型',
`glue_source` mediumtext COMMENT 'GLUE源代码',
`glue_remark` varchar(128) NOT NULL COMMENT 'GLUE备注',
`add_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `xxl_job_registry` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`registry_group` varchar(50) NOT NULL,
`registry_key` varchar(255) NOT NULL,
`registry_value` varchar(255) NOT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `i_g_k_v` (`registry_group`,`registry_key`,`registry_value`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `xxl_job_group` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`app_name` varchar(64) NOT NULL COMMENT '执行器AppName',
`title` varchar(12) NOT NULL COMMENT '执行器名称',
`address_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '执行器地址类型0=自动注册、1=手动录入',
`address_list` text COMMENT '执行器地址列表,多地址逗号分隔',
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `xxl_job_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL COMMENT '账号',
`password` varchar(50) NOT NULL COMMENT '密码',
`role` tinyint(4) NOT NULL COMMENT '角色0-普通用户、1-管理员',
`permission` varchar(255) DEFAULT NULL COMMENT '权限执行器ID列表多个逗号分割',
PRIMARY KEY (`id`),
UNIQUE KEY `i_username` (`username`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `xxl_job_lock` (
`lock_name` varchar(50) NOT NULL COMMENT '锁名称',
PRIMARY KEY (`lock_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `xxl_job_group`(`id`, `app_name`, `title`, `address_type`, `address_list`, `update_time`) VALUES (1, 'xxl-job-executor-sample', '示例执行器', 0, NULL, '2018-11-03 22:21:31' );
INSERT INTO `xxl_job_info`(`id`, `job_group`, `job_desc`, `add_time`, `update_time`, `author`, `alarm_email`, `schedule_type`, `schedule_conf`, `misfire_strategy`, `executor_route_strategy`, `executor_handler`, `executor_param`, `executor_block_strategy`, `executor_timeout`, `executor_fail_retry_count`, `glue_type`, `glue_source`, `glue_remark`, `glue_updatetime`, `child_jobid`) VALUES (1, 1, '测试任务1', '2018-11-03 22:21:31', '2018-11-03 22:21:31', 'XXL', '', 'CRON', '0 0 0 * * ? *', 'DO_NOTHING', 'FIRST', 'demoJobHandler', '', 'SERIAL_EXECUTION', 0, 0, 'BEAN', '', 'GLUE代码初始化', '2018-11-03 22:21:31', '');
INSERT INTO `xxl_job_user`(`id`, `username`, `password`, `role`, `permission`) VALUES (1, 'admin', 'e10adc3949ba59abbe56e057f20f883e', 1, NULL);
INSERT INTO `xxl_job_lock` ( `lock_name`) VALUES ( 'schedule_lock');
commit;

View File

@ -66,15 +66,6 @@ services:
hostname: pig-monitor
image: pig-monitor
pig-sentinel:
build:
context: ./pig-visual/pig-sentinel-dashboard
restart: always
image: pig-sentinel
container_name: pig-sentinel
ports:
- 5003:5003
pig-codegen:
build:
context: ./pig-visual/pig-codegen
@ -82,13 +73,3 @@ services:
container_name: pig-codegen
hostname: pig-codegen
image: pig-codegen
pig-job:
build:
context: ./pig-visual/pig-xxl-job-admin
restart: always
container_name: pig-job
hostname: pig-job
image: pig-job
ports:
- 5004:5004

View File

@ -1,4 +1,4 @@
FROM moxm/java:1.8-full
FROM alibabadragonwell/dragonwell:17-anolis
RUN mkdir -p /pig-auth

View File

@ -67,22 +67,26 @@ public class AuthorizationServerConfiguration {
http.apply(authorizationServerConfigurer.tokenEndpoint((tokenEndpoint) -> {// 个性化认证授权端点
tokenEndpoint.accessTokenRequestConverter(accessTokenRequestConverter()) // 注入自定义的授权认证Converter
.accessTokenResponseHandler(new PigAuthenticationSuccessEventHandler()) // 登录成功处理器
.errorResponseHandler(new PigAuthenticationFailureEventHandler());// 登录失败处理器
.accessTokenResponseHandler(new PigAuthenticationSuccessEventHandler()) // 登录成功处理器
.errorResponseHandler(new PigAuthenticationFailureEventHandler());// 登录失败处理器
}).clientAuthentication(oAuth2ClientAuthenticationConfigurer -> // 个性化客户端认证
oAuth2ClientAuthenticationConfigurer.errorResponseHandler(new PigAuthenticationFailureEventHandler()))// 处理客户端认证异常
.authorizationEndpoint(authorizationEndpoint -> authorizationEndpoint// 授权码端点个性化confirm页面
.consentPage(SecurityConstants.CUSTOM_CONSENT_PAGE_URI)));
.authorizationEndpoint(authorizationEndpoint -> authorizationEndpoint// 授权码端点个性化confirm页面
.consentPage(SecurityConstants.CUSTOM_CONSENT_PAGE_URI)));
DefaultSecurityFilterChain securityFilterChain = http.authorizeHttpRequests(authorizeRequests -> {
// 自定义接口端点暴露
authorizeRequests.requestMatchers("/token/**", "/actuator/**", "/css/**", "/error").permitAll();
authorizeRequests.anyRequest().authenticated();
}).apply(authorizationServerConfigurer.authorizationService(authorizationService)// redis存储token的实现
})
.apply(authorizationServerConfigurer.authorizationService(authorizationService)// redis存储token的实现
.authorizationServerSettings(
AuthorizationServerSettings.builder().issuer(SecurityConstants.PROJECT_LICENSE).build()))
// 授权码登录的登录页个性化
.and().apply(new FormIdentityLoginConfigurer()).and().build();
// 授权码登录的登录页个性化
.and()
.apply(new FormIdentityLoginConfigurer())
.and()
.build();
// 注入自定义授权模式实现
addCustomOAuth2GrantAuthenticationProvider(http);

View File

@ -22,9 +22,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
import org.springframework.security.config.annotation.web.configurers.RequestCacheConfigurer;
import org.springframework.security.web.SecurityFilterChain;
/**
@ -44,11 +41,15 @@ public class WebSecurityConfiguration {
*/
@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(authorizeRequests -> authorizeRequests.requestMatchers("/token/*").permitAll()// 开放自定义的部分端点
.anyRequest().authenticated()).headers(httpSecurityHeadersConfigurer -> {
// 避免iframe同源无法登录
httpSecurityHeadersConfigurer.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin);
}).apply(new FormIdentityLoginConfigurer()); // 表单登录个性化
http.authorizeHttpRequests(authorizeRequests -> authorizeRequests.requestMatchers("/token/*")
.permitAll()// 开放自定义的部分端点
.anyRequest()
.authenticated())
.headers()
.frameOptions()
.sameOrigin()// 避免iframe同源无法登录
.and()
.apply(new FormIdentityLoginConfigurer()); // 表单登录个性化
// 处理 UsernamePasswordAuthenticationToken
http.authenticationProvider(new PigDaoAuthenticationProvider());
return http.build();
@ -56,7 +57,7 @@ public class WebSecurityConfiguration {
/**
* 暴露静态资源
* <p>
*
* https://github.com/spring-projects/spring-security/issues/10938
* @param http
* @return
@ -66,9 +67,13 @@ public class WebSecurityConfiguration {
@Order(0)
SecurityFilterChain resources(HttpSecurity http) throws Exception {
http.securityMatchers((matchers) -> matchers.requestMatchers("/actuator/**", "/css/**", "/error"))
.authorizeHttpRequests((authorize) -> authorize.anyRequest().permitAll())
.requestCache(RequestCacheConfigurer::disable).securityContext(AbstractHttpConfigurer::disable)
.sessionManagement(AbstractHttpConfigurer::disable);
.authorizeHttpRequests((authorize) -> authorize.anyRequest().permitAll())
.requestCache()
.disable()
.securityContext()
.disable()
.sessionManagement()
.disable();
return http.build();
}

View File

@ -107,8 +107,9 @@ public class PigTokenEndpoint {
@RequestParam(OAuth2ParameterNames.CLIENT_ID) String clientId,
@RequestParam(OAuth2ParameterNames.SCOPE) String scope,
@RequestParam(OAuth2ParameterNames.STATE) String state) {
SysOauthClientDetails clientDetails = RetOps.of(clientDetailsService.getClientDetailsById(clientId)).getData()
.orElseThrow(() -> new OAuthClientException("clientId 不合法"));
SysOauthClientDetails clientDetails = RetOps.of(clientDetailsService.getClientDetailsById(clientId))
.getData()
.orElseThrow(() -> new OAuthClientException("clientId 不合法"));
Set<String> authorizedScopes = StringUtils.commaDelimitedListToSet(clientDetails.getScope());
modelAndView.addObject("clientId", clientId);

View File

@ -30,7 +30,7 @@ public class CustomeOAuth2AccessTokenGenerator implements OAuth2TokenGenerator<O
@Override
public OAuth2AccessToken generate(OAuth2TokenContext context) {
if (!OAuth2TokenType.ACCESS_TOKEN.equals(context.getTokenType()) || !OAuth2TokenFormat.REFERENCE
.equals(context.getRegisteredClient().getTokenSettings().getAccessTokenFormat())) {
.equals(context.getRegisteredClient().getTokenSettings().getAccessTokenFormat())) {
return null;
}

View File

@ -83,10 +83,11 @@ public abstract class OAuth2ResourceOwnerBaseAuthenticationConverter<T extends O
}
// 扩展信息
Map<String, Object> additionalParameters = parameters.entrySet().stream()
.filter(e -> !e.getKey().equals(OAuth2ParameterNames.GRANT_TYPE)
&& !e.getKey().equals(OAuth2ParameterNames.SCOPE))
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get(0)));
Map<String, Object> additionalParameters = parameters.entrySet()
.stream()
.filter(e -> !e.getKey().equals(OAuth2ParameterNames.GRANT_TYPE)
&& !e.getKey().equals(OAuth2ParameterNames.SCOPE))
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get(0)));
// 创建token
return buildToken(clientPrincipal, requestedScopes, additionalParameters);

View File

@ -139,7 +139,7 @@ public abstract class OAuth2ResourceOwnerBaseAuthenticationProvider<T extends OA
LOGGER.debug("got usernamePasswordAuthenticationToken=" + usernamePasswordAuthenticationToken);
Authentication usernamePasswordAuthentication = authenticationManager
.authenticate(usernamePasswordAuthenticationToken);
.authenticate(usernamePasswordAuthenticationToken);
// @formatter:off
DefaultOAuth2TokenContext.Builder tokenContextBuilder = DefaultOAuth2TokenContext.builder()
@ -152,10 +152,11 @@ public abstract class OAuth2ResourceOwnerBaseAuthenticationProvider<T extends OA
// @formatter:on
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization
.withRegisteredClient(registeredClient).principalName(usernamePasswordAuthentication.getName())
.authorizationGrantType(AuthorizationGrantType.PASSWORD)
// 0.4.0 新增的方法
.authorizedScopes(authorizedScopes);
.withRegisteredClient(registeredClient)
.principalName(usernamePasswordAuthentication.getName())
.authorizationGrantType(AuthorizationGrantType.PASSWORD)
// 0.4.0 新增的方法
.authorizedScopes(authorizedScopes);
// ----- Access token -----
OAuth2TokenContext tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.ACCESS_TOKEN).build();
@ -170,12 +171,12 @@ public abstract class OAuth2ResourceOwnerBaseAuthenticationProvider<T extends OA
generatedAccessToken.getExpiresAt(), tokenContext.getAuthorizedScopes());
if (generatedAccessToken instanceof ClaimAccessor) {
authorizationBuilder.id(accessToken.getTokenValue())
.token(accessToken,
(metadata) -> metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME,
((ClaimAccessor) generatedAccessToken).getClaims()))
// 0.4.0 新增的方法
.authorizedScopes(authorizedScopes)
.attribute(Principal.class.getName(), usernamePasswordAuthentication);
.token(accessToken,
(metadata) -> metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME,
((ClaimAccessor) generatedAccessToken).getClaims()))
// 0.4.0 新增的方法
.authorizedScopes(authorizedScopes)
.attribute(Principal.class.getName(), usernamePasswordAuthentication);
}
else {
authorizationBuilder.id(accessToken.getTokenValue()).accessToken(accessToken);
@ -243,7 +244,7 @@ public abstract class OAuth2ResourceOwnerBaseAuthenticationProvider<T extends OA
}
if (authenticationException instanceof LockedException) {
return new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodesExpand.USER_LOCKED, this.messages
.getMessage("AbstractUserDetailsAuthenticationProvider.locked", "User account is locked"), ""));
.getMessage("AbstractUserDetailsAuthenticationProvider.locked", "User account is locked"), ""));
}
if (authenticationException instanceof DisabledException) {
return new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodesExpand.USER_DISABLE,
@ -252,7 +253,7 @@ public abstract class OAuth2ResourceOwnerBaseAuthenticationProvider<T extends OA
}
if (authenticationException instanceof AccountExpiredException) {
return new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodesExpand.USER_EXPIRED, this.messages
.getMessage("AbstractUserDetailsAuthenticationProvider.expired", "User account has expired"), ""));
.getMessage("AbstractUserDetailsAuthenticationProvider.expired", "User account has expired"), ""));
}
if (authenticationException instanceof CredentialsExpiredException) {
return new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodesExpand.CREDENTIALS_EXPIRED,

View File

@ -8,7 +8,7 @@ import org.springframework.security.config.annotation.web.configurers.AbstractHt
/**
* @author lengleng
* @data 2022-06-04
* <p>
*
* 基于授权码模式 统一认证登录 spring security & sas 都可以使用 所以抽取成 HttpConfigurer
*/
public final class FormIdentityLoginConfigurer
@ -21,13 +21,14 @@ public final class FormIdentityLoginConfigurer
formLogin.loginProcessingUrl("/token/form");
formLogin.failureHandler(new FormAuthenticationFailureHandler());
}).logout(httpSecurityLogoutConfigurer -> {
// SSO登出成功处理
httpSecurityLogoutConfigurer.logoutSuccessHandler(new SsoLogoutSuccessHandler()).deleteCookies("JSESSIONID")
.invalidateHttpSession(true);
}
).csrf(AbstractHttpConfigurer::disable);
})
.logout() // SSO登出成功处理
.logoutSuccessHandler(new SsoLogoutSuccessHandler())
.deleteCookies("JSESSIONID")
.invalidateHttpSession(true)
.and()
.csrf()
.disable();
}
}

View File

@ -77,13 +77,13 @@ public class PigDaoAuthenticationProvider extends AbstractUserDetailsAuthenticat
if (authentication.getCredentials() == null) {
this.logger.debug("Failed to authenticate since no credentials provided");
throw new BadCredentialsException(this.messages
.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
}
String presentedPassword = authentication.getCredentials().toString();
if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
this.logger.debug("Failed to authenticate since password does not match stored value");
throw new BadCredentialsException(this.messages
.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
}
}
@ -92,8 +92,9 @@ public class PigDaoAuthenticationProvider extends AbstractUserDetailsAuthenticat
protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) {
prepareTimingAttackProtection();
HttpServletRequest request = WebUtils.getRequest().orElseThrow(
(Supplier<Throwable>) () -> new InternalAuthenticationServiceException("web request is empty"));
HttpServletRequest request = WebUtils.getRequest()
.orElseThrow(
(Supplier<Throwable>) () -> new InternalAuthenticationServiceException("web request is empty"));
String grantType = WebUtils.getRequest().get().getParameter(OAuth2ParameterNames.GRANT_TYPE);
String clientId = WebUtils.getRequest().get().getParameter(OAuth2ParameterNames.CLIENT_ID);
@ -103,12 +104,13 @@ public class PigDaoAuthenticationProvider extends AbstractUserDetailsAuthenticat
}
Map<String, PigUserDetailsService> userDetailsServiceMap = SpringUtil
.getBeansOfType(PigUserDetailsService.class);
.getBeansOfType(PigUserDetailsService.class);
String finalClientId = clientId;
Optional<PigUserDetailsService> optional = userDetailsServiceMap.values().stream()
.filter(service -> service.support(finalClientId, grantType))
.max(Comparator.comparingInt(Ordered::getOrder));
Optional<PigUserDetailsService> optional = userDetailsServiceMap.values()
.stream()
.filter(service -> service.support(finalClientId, grantType))
.max(Comparator.comparingInt(Ordered::getOrder));
if (!optional.isPresent()) {
throw new InternalAuthenticationServiceException("UserDetailsService error , not register");

View File

@ -99,7 +99,8 @@ public class PigAuthenticationSuccessEventHandler implements AuthenticationSucce
Map<String, Object> additionalParameters = accessTokenAuthentication.getAdditionalParameters();
OAuth2AccessTokenResponse.Builder builder = OAuth2AccessTokenResponse.withToken(accessToken.getTokenValue())
.tokenType(accessToken.getTokenType()).scopes(accessToken.getScopes());
.tokenType(accessToken.getTokenType())
.scopes(accessToken.getScopes());
if (accessToken.getIssuedAt() != null && accessToken.getExpiresAt() != null) {
builder.expiresIn(ChronoUnit.SECONDS.between(accessToken.getIssuedAt(), accessToken.getExpiresAt()));
}

View File

@ -52,7 +52,7 @@ public class OAuth2ResourceOwnerSmsAuthenticationProvider
public void checkClient(RegisteredClient registeredClient) {
assert registeredClient != null;
if (!registeredClient.getAuthorizationGrantTypes()
.contains(new AuthorizationGrantType(SecurityConstants.APP))) {
.contains(new AuthorizationGrantType(SecurityConstants.APP))) {
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT);
}
}

View File

@ -26,7 +26,7 @@
<springdoc.version>2.0.0</springdoc.version>
<swagger.core.version>2.2.7</swagger.core.version>
<mybatis-plus.version>3.5.3.1</mybatis-plus.version>
<mysql.version>8.0.31</mysql.version>
<mysql.version>8.0.33</mysql.version>
<seata.version>1.6.1</seata.version>
<excel.version>3.0.0</excel.version>
<asm.version>7.1</asm.version>

View File

@ -111,7 +111,7 @@ public class WebUtils extends org.springframework.web.util.WebUtils {
*/
public Optional<HttpServletRequest> getRequest() {
return Optional
.ofNullable(((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest());
.ofNullable(((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest());
}
/**

View File

@ -106,8 +106,8 @@ public final class PigSentinelFeign {
private Object getFromContext(String name, String type, Class<?> fallbackType, Class<?> targetType) {
Object fallbackInstance = feignClientFactory.getInstance(name, fallbackType);
if (fallbackInstance == null) {
throw new IllegalStateException(String.format(
"No %s instance of type %s found for feign client %s", type, fallbackType, name));
throw new IllegalStateException(String
.format("No %s instance of type %s found for feign client %s", type, fallbackType, name));
}
if (!targetType.isAssignableFrom(fallbackType)) {

View File

@ -101,7 +101,7 @@ public class PigSentinelInvocationHandler implements InvocationHandler {
if (target instanceof Target.HardCodedTarget) {
Target.HardCodedTarget<?> hardCodedTarget = (Target.HardCodedTarget) target;
MethodMetadata methodMetadata = SentinelContractHolder.METADATA_MAP
.get(hardCodedTarget.type().getName() + Feign.configKey(hardCodedTarget.type(), method));
.get(hardCodedTarget.type().getName() + Feign.configKey(hardCodedTarget.type(), method));
// resource default is HttpMethod:protocol://url
if (methodMetadata == null) {
result = methodHandler.invoke(args);

View File

@ -88,8 +88,8 @@ public class GlobalBizExceptionHandler {
@ExceptionHandler(AccessDeniedException.class)
@ResponseStatus(HttpStatus.FORBIDDEN)
public R handleAccessDeniedException(AccessDeniedException e) {
String msg = SpringSecurityMessageSource.getAccessor().getMessage("AbstractAccessDecisionManager.accessDenied",
e.getMessage());
String msg = SpringSecurityMessageSource.getAccessor()
.getMessage("AbstractAccessDecisionManager.accessDenied", e.getMessage());
log.warn("拒绝授权异常信息 ex={}", msg);
return R.failed(e.getLocalizedMessage());
}

View File

@ -91,7 +91,7 @@ public class PigFeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
validate(attributes);
BeanDefinitionBuilder definition = BeanDefinitionBuilder
.genericBeanDefinition(FeignClientFactoryBean.class);
.genericBeanDefinition(FeignClientFactoryBean.class);
definition.addPropertyValue("url", getUrl(attributes));
definition.addPropertyValue("path", getPath(attributes));
String name = getName(attributes);

View File

@ -61,10 +61,13 @@ public class XxlJobAutoConfiguration {
// 如果配置为空则获取注册中心的服务列表 "http://pig-xxl:9080/xxl-job-admin"
if (!StringUtils.hasText(xxlJobProperties.getAdmin().getAddresses())) {
String serverList = discoveryClient.getServices().stream().filter(s -> s.contains(XXL_JOB_ADMIN))
.flatMap(s -> discoveryClient.getInstances(s).stream()).map(instance -> String
.format("http://%s:%s/%s", instance.getHost(), instance.getPort(), XXL_JOB_ADMIN))
.collect(Collectors.joining(","));
String serverList = discoveryClient.getServices()
.stream()
.filter(s -> s.contains(XXL_JOB_ADMIN))
.flatMap(s -> discoveryClient.getInstances(s).stream())
.map(instance -> String.format("http://%s:%s/%s", instance.getHost(), instance.getPort(),
XXL_JOB_ADMIN))
.collect(Collectors.joining(","));
xxlJobSpringExecutor.setAdminAddresses(serverList);
}
else {

View File

@ -45,7 +45,7 @@ public class SysLogUtils {
public SysLog getSysLog() {
HttpServletRequest request = ((ServletRequestAttributes) Objects
.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
SysLog sysLog = new SysLog();
sysLog.setType(LogTypeEnum.NORMAL.getType());
sysLog.setRequestUri(URLUtil.getPath(request.getRequestURI()));

View File

@ -88,10 +88,12 @@ public class SqlFilterArgumentResolver implements HandlerMethodArgumentResolver
}
List<OrderItem> orderItemList = new ArrayList<>();
Optional.ofNullable(ascs).ifPresent(s -> orderItemList.addAll(
Arrays.stream(s).filter(sqlInjectPredicate()).map(OrderItem::asc).collect(Collectors.toList())));
Optional.ofNullable(descs).ifPresent(s -> orderItemList.addAll(
Arrays.stream(s).filter(sqlInjectPredicate()).map(OrderItem::desc).collect(Collectors.toList())));
Optional.ofNullable(ascs)
.ifPresent(s -> orderItemList.addAll(
Arrays.stream(s).filter(sqlInjectPredicate()).map(OrderItem::asc).collect(Collectors.toList())));
Optional.ofNullable(descs)
.ifPresent(s -> orderItemList.addAll(
Arrays.stream(s).filter(sqlInjectPredicate()).map(OrderItem::desc).collect(Collectors.toList())));
page.addOrder(orderItemList);
return page;

View File

@ -46,8 +46,10 @@ public class PermissionService {
return false;
}
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
return authorities.stream().map(GrantedAuthority::getAuthority).filter(StringUtils::hasText)
.anyMatch(x -> PatternMatchUtils.simpleMatch(permissions, x));
return authorities.stream()
.map(GrantedAuthority::getAuthority)
.filter(StringUtils::hasText)
.anyMatch(x -> PatternMatchUtils.simpleMatch(permissions, x));
}
}

View File

@ -61,13 +61,17 @@ public class PermitAllUrlProperties implements InitializingBean {
// 获取方法上边的注解 替代path variable *
Inner method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Inner.class);
Optional.ofNullable(method).ifPresent(inner -> Objects.requireNonNull(info.getPathPatternsCondition())
.getPatternValues().forEach(url -> urls.add(ReUtil.replaceAll(url, PATTERN, "*"))));
Optional.ofNullable(method)
.ifPresent(inner -> Objects.requireNonNull(info.getPathPatternsCondition())
.getPatternValues()
.forEach(url -> urls.add(ReUtil.replaceAll(url, PATTERN, "*"))));
// 获取类上边的注解, 替代path variable *
Inner controller = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), Inner.class);
Optional.ofNullable(controller).ifPresent(inner -> Objects.requireNonNull(info.getPathPatternsCondition())
.getPatternValues().forEach(url -> urls.add(ReUtil.replaceAll(url, PATTERN, "*"))));
Optional.ofNullable(controller)
.ifPresent(inner -> Objects.requireNonNull(info.getPathPatternsCondition())
.getPatternValues()
.forEach(url -> urls.add(ReUtil.replaceAll(url, PATTERN, "*"))));
});
}

View File

@ -55,8 +55,9 @@ public class PigBearerTokenExtractor implements BearerTokenResolver {
@Override
public String resolve(HttpServletRequest request) {
boolean match = urlProperties.getUrls().stream()
.anyMatch(url -> pathMatcher.match(url, request.getRequestURI()));
boolean match = urlProperties.getUrls()
.stream()
.anyMatch(url -> pathMatcher.match(url, request.getRequestURI()));
if (match) {
return null;
@ -68,7 +69,7 @@ public class PigBearerTokenExtractor implements BearerTokenResolver {
if (authorizationHeaderToken != null) {
if (parameterToken != null) {
final BearerTokenError error = BearerTokenErrors
.invalidRequest("Found multiple bearer tokens in the request");
.invalidRequest("Found multiple bearer tokens in the request");
throw new OAuth2AuthenticationException(error);
}
return authorizationHeaderToken;

View File

@ -48,12 +48,13 @@ public class PigCustomOpaqueTokenIntrospector implements OpaqueTokenIntrospector
}
Map<String, PigUserDetailsService> userDetailsServiceMap = SpringUtil
.getBeansOfType(PigUserDetailsService.class);
.getBeansOfType(PigUserDetailsService.class);
Optional<PigUserDetailsService> optional = userDetailsServiceMap.values().stream()
.filter(service -> service.support(Objects.requireNonNull(oldAuthorization).getRegisteredClientId(),
oldAuthorization.getAuthorizationGrantType().getValue()))
.max(Comparator.comparingInt(Ordered::getOrder));
Optional<PigUserDetailsService> optional = userDetailsServiceMap.values()
.stream()
.filter(service -> service.support(Objects.requireNonNull(oldAuthorization).getRegisteredClientId(),
oldAuthorization.getAuthorizationGrantType().getValue()))
.max(Comparator.comparingInt(Ordered::getOrder));
UserDetails userDetails = null;
try {

View File

@ -24,15 +24,13 @@ import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
import org.springframework.security.web.SecurityFilterChain;
/**
* @author lengleng
* @date 2022-06-04
* <p>
*
* 资源服务器认证授权配置
*/
@Slf4j
@ -53,15 +51,20 @@ public class PigResourceServerConfiguration {
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(authorizeRequests -> authorizeRequests
.requestMatchers(ArrayUtil.toArray(permitAllUrl.getUrls(), String.class)).permitAll().anyRequest()
.authenticated())
.oauth2ResourceServer(
oauth2 -> oauth2.opaqueToken(token -> token.introspector(customOpaqueTokenIntrospector))
.authenticationEntryPoint(resourceAuthExceptionEntryPoint)
.bearerTokenResolver(pigBearerTokenExtractor))
.headers(httpSecurityHeadersConfigurer -> httpSecurityHeadersConfigurer
.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
.csrf(AbstractHttpConfigurer::disable);
.requestMatchers(ArrayUtil.toArray(permitAllUrl.getUrls(), String.class))
.permitAll()
.anyRequest()
.authenticated())
.oauth2ResourceServer(
oauth2 -> oauth2.opaqueToken(token -> token.introspector(customOpaqueTokenIntrospector))
.authenticationEntryPoint(resourceAuthExceptionEntryPoint)
.bearerTokenResolver(pigBearerTokenExtractor))
.headers()
.frameOptions()
.disable()
.and()
.csrf()
.disable();
return http.build();
}

View File

@ -19,8 +19,8 @@ public class PigRedisOAuth2AuthorizationConsentService implements OAuth2Authoriz
public void save(OAuth2AuthorizationConsent authorizationConsent) {
Assert.notNull(authorizationConsent, "authorizationConsent cannot be null");
redisTemplate.opsForValue().set(buildKey(authorizationConsent), authorizationConsent, TIMEOUT,
TimeUnit.MINUTES);
redisTemplate.opsForValue()
.set(buildKey(authorizationConsent), authorizationConsent, TIMEOUT, TimeUnit.MINUTES);
}
@ -35,7 +35,7 @@ public class PigRedisOAuth2AuthorizationConsentService implements OAuth2Authoriz
Assert.hasText(registeredClientId, "registeredClientId cannot be empty");
Assert.hasText(principalName, "principalName cannot be empty");
return (OAuth2AuthorizationConsent) redisTemplate.opsForValue()
.get(buildKey(registeredClientId, principalName));
.get(buildKey(registeredClientId, principalName));
}
private static String buildKey(String registeredClientId, String principalName) {

View File

@ -39,35 +39,38 @@ public class PigRedisOAuth2AuthorizationService implements OAuth2AuthorizationSe
if (isState(authorization)) {
String token = authorization.getAttribute("state");
redisTemplate.setValueSerializer(RedisSerializer.java());
redisTemplate.opsForValue().set(buildKey(OAuth2ParameterNames.STATE, token), authorization, TIMEOUT,
TimeUnit.MINUTES);
redisTemplate.opsForValue()
.set(buildKey(OAuth2ParameterNames.STATE, token), authorization, TIMEOUT, TimeUnit.MINUTES);
}
if (isCode(authorization)) {
OAuth2Authorization.Token<OAuth2AuthorizationCode> authorizationCode = authorization
.getToken(OAuth2AuthorizationCode.class);
.getToken(OAuth2AuthorizationCode.class);
OAuth2AuthorizationCode authorizationCodeToken = authorizationCode.getToken();
long between = ChronoUnit.MINUTES.between(authorizationCodeToken.getIssuedAt(),
authorizationCodeToken.getExpiresAt());
redisTemplate.setValueSerializer(RedisSerializer.java());
redisTemplate.opsForValue().set(buildKey(OAuth2ParameterNames.CODE, authorizationCodeToken.getTokenValue()),
authorization, between, TimeUnit.MINUTES);
redisTemplate.opsForValue()
.set(buildKey(OAuth2ParameterNames.CODE, authorizationCodeToken.getTokenValue()), authorization,
between, TimeUnit.MINUTES);
}
if (isRefreshToken(authorization)) {
OAuth2RefreshToken refreshToken = authorization.getRefreshToken().getToken();
long between = ChronoUnit.SECONDS.between(refreshToken.getIssuedAt(), refreshToken.getExpiresAt());
redisTemplate.setValueSerializer(RedisSerializer.java());
redisTemplate.opsForValue().set(buildKey(OAuth2ParameterNames.REFRESH_TOKEN, refreshToken.getTokenValue()),
authorization, between, TimeUnit.SECONDS);
redisTemplate.opsForValue()
.set(buildKey(OAuth2ParameterNames.REFRESH_TOKEN, refreshToken.getTokenValue()), authorization, between,
TimeUnit.SECONDS);
}
if (isAccessToken(authorization)) {
OAuth2AccessToken accessToken = authorization.getAccessToken().getToken();
long between = ChronoUnit.SECONDS.between(accessToken.getIssuedAt(), accessToken.getExpiresAt());
redisTemplate.setValueSerializer(RedisSerializer.java());
redisTemplate.opsForValue().set(buildKey(OAuth2ParameterNames.ACCESS_TOKEN, accessToken.getTokenValue()),
authorization, between, TimeUnit.SECONDS);
redisTemplate.opsForValue()
.set(buildKey(OAuth2ParameterNames.ACCESS_TOKEN, accessToken.getTokenValue()), authorization, between,
TimeUnit.SECONDS);
}
}
@ -83,7 +86,7 @@ public class PigRedisOAuth2AuthorizationService implements OAuth2AuthorizationSe
if (isCode(authorization)) {
OAuth2Authorization.Token<OAuth2AuthorizationCode> authorizationCode = authorization
.getToken(OAuth2AuthorizationCode.class);
.getToken(OAuth2AuthorizationCode.class);
OAuth2AuthorizationCode authorizationCodeToken = authorizationCode.getToken();
keys.add(buildKey(OAuth2ParameterNames.CODE, authorizationCodeToken.getTokenValue()));
}
@ -125,7 +128,7 @@ public class PigRedisOAuth2AuthorizationService implements OAuth2AuthorizationSe
private static boolean isCode(OAuth2Authorization authorization) {
OAuth2Authorization.Token<OAuth2AuthorizationCode> authorizationCode = authorization
.getToken(OAuth2AuthorizationCode.class);
.getToken(OAuth2AuthorizationCode.class);
return Objects.nonNull(authorizationCode);
}

View File

@ -56,7 +56,6 @@ public class PigRemoteRegisteredClientRepository implements RegisteredClientRepo
*/
@Override
public void save(RegisteredClient registeredClient) {
throw new UnsupportedOperationException();
}
/**
@ -87,38 +86,44 @@ public class PigRemoteRegisteredClientRepository implements RegisteredClientRepo
@Cacheable(value = CacheConstants.CLIENT_DETAILS_KEY, key = "#clientId", unless = "#result == null")
public RegisteredClient findByClientId(String clientId) {
SysOauthClientDetails clientDetails = RetOps.of(clientDetailsService.getClientDetailsById(clientId)).getData()
.orElseThrow(() -> new OAuth2AuthorizationCodeRequestAuthenticationException(
new OAuth2Error("客户端查询异常,请检查数据库链接"), null));
SysOauthClientDetails clientDetails = RetOps.of(clientDetailsService.getClientDetailsById(clientId))
.getData()
.orElseThrow(() -> new OAuth2AuthorizationCodeRequestAuthenticationException(
new OAuth2Error("客户端查询异常,请检查数据库链接"), null));
RegisteredClient.Builder builder = RegisteredClient.withId(clientDetails.getClientId())
.clientId(clientDetails.getClientId())
.clientSecret(SecurityConstants.NOOP + clientDetails.getClientSecret())
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC);
.clientId(clientDetails.getClientId())
.clientSecret(SecurityConstants.NOOP + clientDetails.getClientSecret())
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC);
// 授权模式
Optional.ofNullable(clientDetails.getAuthorizedGrantTypes())
.ifPresent(grants -> StringUtils.commaDelimitedListToSet(grants)
.forEach(s -> builder.authorizationGrantType(new AuthorizationGrantType(s))));
.ifPresent(grants -> StringUtils.commaDelimitedListToSet(grants)
.forEach(s -> builder.authorizationGrantType(new AuthorizationGrantType(s))));
// 回调地址
Optional.ofNullable(clientDetails.getWebServerRedirectUri()).ifPresent(redirectUri -> Arrays
.stream(redirectUri.split(StrUtil.COMMA)).filter(StrUtil::isNotBlank).forEach(builder::redirectUri));
Optional.ofNullable(clientDetails.getWebServerRedirectUri())
.ifPresent(redirectUri -> Arrays.stream(redirectUri.split(StrUtil.COMMA))
.filter(StrUtil::isNotBlank)
.forEach(builder::redirectUri));
// scope
Optional.ofNullable(clientDetails.getScope()).ifPresent(
scope -> Arrays.stream(scope.split(StrUtil.COMMA)).filter(StrUtil::isNotBlank).forEach(builder::scope));
Optional.ofNullable(clientDetails.getScope())
.ifPresent(scope -> Arrays.stream(scope.split(StrUtil.COMMA))
.filter(StrUtil::isNotBlank)
.forEach(builder::scope));
return builder
.tokenSettings(TokenSettings.builder().accessTokenFormat(OAuth2TokenFormat.REFERENCE)
.accessTokenTimeToLive(Duration.ofSeconds(Optional
.ofNullable(clientDetails.getAccessTokenValidity()).orElse(accessTokenValiditySeconds)))
.refreshTokenTimeToLive(
Duration.ofSeconds(Optional.ofNullable(clientDetails.getRefreshTokenValidity())
.orElse(refreshTokenValiditySeconds)))
.build())
.clientSettings(ClientSettings.builder()
.requireAuthorizationConsent(!BooleanUtil.toBoolean(clientDetails.getAutoapprove())).build())
.build();
.tokenSettings(TokenSettings.builder()
.accessTokenFormat(OAuth2TokenFormat.REFERENCE)
.accessTokenTimeToLive(Duration.ofSeconds(
Optional.ofNullable(clientDetails.getAccessTokenValidity()).orElse(accessTokenValiditySeconds)))
.refreshTokenTimeToLive(Duration.ofSeconds(Optional.ofNullable(clientDetails.getRefreshTokenValidity())
.orElse(refreshTokenValiditySeconds)))
.build())
.clientSettings(ClientSettings.builder()
.requireAuthorizationConsent(!BooleanUtil.toBoolean(clientDetails.getAutoapprove()))
.build())
.build();
}

View File

@ -62,7 +62,7 @@ public interface PigUserDetailsService extends UserDetailsService, Ordered {
}
Collection<GrantedAuthority> authorities = AuthorityUtils
.createAuthorityList(dbAuthsSet.toArray(new String[0]));
.createAuthorityList(dbAuthsSet.toArray(new String[0]));
SysUser user = info.getSysUser();
// 构造security用户

View File

@ -39,7 +39,7 @@ public class OAuth2EndpointUtils {
public boolean matchesPkceTokenRequest(HttpServletRequest request) {
return AuthorizationGrantType.AUTHORIZATION_CODE.getValue()
.equals(request.getParameter(OAuth2ParameterNames.GRANT_TYPE))
.equals(request.getParameter(OAuth2ParameterNames.GRANT_TYPE))
&& request.getParameter(OAuth2ParameterNames.CODE) != null
&& request.getParameter(PkceParameterNames.CODE_VERIFIER) != null;
}
@ -63,7 +63,8 @@ public class OAuth2EndpointUtils {
OAuth2RefreshToken refreshToken = authentication.getRefreshToken().getToken();
OAuth2AccessTokenResponse.Builder builder = OAuth2AccessTokenResponse.withToken(accessToken.getTokenValue())
.tokenType(accessToken.getTokenType()).scopes(accessToken.getScopes());
.tokenType(accessToken.getTokenType())
.scopes(accessToken.getScopes());
if (accessToken.getIssuedAt() != null && accessToken.getExpiresAt() != null) {
builder.expiresIn(ChronoUnit.SECONDS.between(accessToken.getIssuedAt(), accessToken.getExpiresAt()));
}

View File

@ -74,11 +74,12 @@ public class SecurityUtils {
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
List<Long> roleIds = new ArrayList<>();
authorities.stream().filter(granted -> StrUtil.startWith(granted.getAuthority(), SecurityConstants.ROLE))
.forEach(granted -> {
String id = StrUtil.removePrefix(granted.getAuthority(), SecurityConstants.ROLE);
roleIds.add(Long.parseLong(id));
});
authorities.stream()
.filter(granted -> StrUtil.startWith(granted.getAuthority(), SecurityConstants.ROLE))
.forEach(granted -> {
String id = StrUtil.removePrefix(granted.getAuthority(), SecurityConstants.ROLE);
roleIds.add(Long.parseLong(id));
});
return roleIds;
}

View File

@ -16,7 +16,7 @@
package com.pig4cloud.pig.common.swagger.annotation;
import com.pig4cloud.pig.common.swagger.config.SwaggerAutoConfiguration;
import com.pig4cloud.pig.common.swagger.config.OpenAPIDefinitionImportSelector;
import com.pig4cloud.pig.common.swagger.support.SwaggerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Import;
@ -29,12 +29,26 @@ import java.lang.annotation.*;
* @author lengleng
* @date 2022-03-26
*/
@Target({ ElementType.TYPE })
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@EnableConfigurationProperties(SwaggerProperties.class)
@Import({ SwaggerAutoConfiguration.class })
@Import(OpenAPIDefinitionImportSelector.class)
public @interface EnablePigDoc {
/**
* 网关路由前缀
*
* @return String
*/
String value();
/**
* 是否是微服务架构
*
* @return true
*/
boolean isMicro() default true;
}

View File

@ -25,10 +25,12 @@ import io.swagger.v3.oas.models.security.Scopes;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import lombok.Setter;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.context.annotation.Bean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.http.HttpHeaders;
import java.util.ArrayList;
@ -49,27 +51,14 @@ import java.util.List;
*/
@RequiredArgsConstructor
@ConditionalOnProperty(name = "swagger.enabled", matchIfMissing = true)
@ConditionalOnMissingClass("org.springframework.cloud.gateway.config.GatewayAutoConfiguration")
public class SwaggerAutoConfiguration {
public class OpenAPIDefinition extends OpenAPI implements InitializingBean, ApplicationContextAware {
private final SwaggerProperties swaggerProperties;
@Setter
private String path;
private final ServiceInstance serviceInstance;
private ApplicationContext applicationContext;
@Bean
public OpenAPI springOpenAPI() {
OpenAPI openAPI = new OpenAPI().info(new Info().title(swaggerProperties.getTitle()));
// oauth2.0 password
openAPI.schemaRequirement(HttpHeaders.AUTHORIZATION, this.securityScheme());
// servers
List<Server> serverList = new ArrayList<>();
String path = swaggerProperties.getServices().get(serviceInstance.getServiceId());
serverList.add(new Server().url(swaggerProperties.getGateway() + "/" + path));
openAPI.servers(serverList);
return openAPI;
}
private SecurityScheme securityScheme() {
private SecurityScheme securityScheme(SwaggerProperties swaggerProperties) {
OAuthFlow clientCredential = new OAuthFlow();
clientCredential.setTokenUrl(swaggerProperties.getTokenUrl());
clientCredential.setScopes(new Scopes().addString(swaggerProperties.getScope(), swaggerProperties.getScope()));
@ -81,4 +70,21 @@ public class SwaggerAutoConfiguration {
return securityScheme;
}
@Override
public void afterPropertiesSet() throws Exception {
SwaggerProperties swaggerProperties = applicationContext.getBean(SwaggerProperties.class);
this.info(new Info().title(swaggerProperties.getTitle()));
// oauth2.0 password
this.schemaRequirement(HttpHeaders.AUTHORIZATION, this.securityScheme(swaggerProperties));
// servers
List<Server> serverList = new ArrayList<>();
serverList.add(new Server().url(swaggerProperties.getGateway() + "/" + path));
this.servers(serverList);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}

View File

@ -0,0 +1,41 @@
package com.pig4cloud.pig.common.swagger.config;
import com.pig4cloud.pig.common.swagger.annotation.EnablePigDoc;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import java.util.Map;
import java.util.Objects;
/**
* openapi 配置类
*
* @author lengleng
* @date 2023/1/1
*/
public class OpenAPIDefinitionImportSelector implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(EnablePigDoc.class.getName(), true);
Object value = annotationAttributes.get("value");
if (Objects.isNull(value)) {
return;
}
BeanDefinitionBuilder openAPIMetadataRegister = BeanDefinitionBuilder.genericBeanDefinition(OpenAPIMetadataRegister.class);
openAPIMetadataRegister.addPropertyValue("path", value);
registry.registerBeanDefinition("openAPIMetadataRegister", openAPIMetadataRegister.getBeanDefinition());
BeanDefinitionBuilder openAPIDefinition = BeanDefinitionBuilder.genericBeanDefinition(OpenAPIDefinition.class);
openAPIDefinition.addPropertyValue("path", value);
registry.registerBeanDefinition("openAPIDefinition", openAPIDefinition.getBeanDefinition());
}
}

View File

@ -0,0 +1,33 @@
package com.pig4cloud.pig.common.swagger.config;
import lombok.Setter;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* @author lengleng
* @date 2023/1/4
*/
public class OpenAPIMetadataRegister implements InitializingBean, ApplicationContextAware {
private ApplicationContext applicationContext;
@Setter
private String path;
@Override
public void afterPropertiesSet() {
ServiceInstance serviceInstance = applicationContext.getBean(ServiceInstance.class);
serviceInstance.getMetadata().put("spring-doc", path);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}

View File

@ -75,8 +75,10 @@ public class PigXssAutoConfiguration implements WebMvcConfigurer {
}
com.pig4cloud.pig.common.xss.core.XssCleanInterceptor interceptor = new com.pig4cloud.pig.common.xss.core.XssCleanInterceptor(
xssProperties);
registry.addInterceptor(interceptor).addPathPatterns(patterns)
.excludePathPatterns(xssProperties.getPathExcludePatterns()).order(Ordered.LOWEST_PRECEDENCE);
registry.addInterceptor(interceptor)
.addPathPatterns(patterns)
.excludePathPatterns(xssProperties.getPathExcludePatterns())
.order(Ordered.LOWEST_PRECEDENCE);
}
}

View File

@ -40,10 +40,10 @@ public class DefaultXssCleaner implements XssCleaner {
private static Document.OutputSettings getOutputSettings(PigXssProperties properties) {
return new Document.OutputSettings()
// 2. 转义没找到关闭的方法目前这个规则最少
.escapeMode(Entities.EscapeMode.xhtml)
// 3. 保留换行
.prettyPrint(properties.isPrettyPrint());
// 2. 转义没找到关闭的方法目前这个规则最少
.escapeMode(Entities.EscapeMode.xhtml)
// 3. 保留换行
.prettyPrint(properties.isPrettyPrint());
}
@Override

View File

@ -1,4 +1,4 @@
FROM moxm/java:1.8-full
FROM alibabadragonwell/dragonwell:17-anolis
RUN mkdir -p /pig-gateway

View File

@ -38,8 +38,9 @@ public class RateLimiterConfiguration {
@Bean
public KeyResolver remoteAddrKeyResolver() {
return exchange -> Mono
.just(Objects.requireNonNull(Objects.requireNonNull(exchange.getRequest().getRemoteAddress()))
.getAddress().getHostAddress());
.just(Objects.requireNonNull(Objects.requireNonNull(exchange.getRequest().getRemoteAddress()))
.getAddress()
.getHostAddress());
}
}

View File

@ -1,9 +1,12 @@
package com.pig4cloud.pig.gateway.config;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import org.springdoc.core.properties.AbstractSwaggerUiConfigProperties;
import org.springdoc.core.properties.SwaggerUiConfigProperties;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.context.annotation.Configuration;
import java.util.HashSet;
@ -21,14 +24,26 @@ public class SpringDocConfiguration implements InitializingBean {
private final SwaggerUiConfigProperties swaggerUiConfigProperties;
private final DiscoveryClient discoveryClient;
@Override
public void afterPropertiesSet() throws Exception {
Set<AbstractSwaggerUiConfigProperties.SwaggerUrl> swaggerUrlSet = new HashSet<>();
AbstractSwaggerUiConfigProperties.SwaggerUrl swaggerUrl = new AbstractSwaggerUiConfigProperties.SwaggerUrl();
swaggerUrl.setName("admin");
swaggerUrl.setUrl("/admin/v3/api-docs");
swaggerUrlSet.add(swaggerUrl);
for (String serviceId : discoveryClient.getServices()) {
for (ServiceInstance instance : discoveryClient.getInstances(serviceId)) {
String doc = instance.getMetadata().get("spring-doc");
if (StrUtil.isNotBlank(doc)) {
AbstractSwaggerUiConfigProperties.SwaggerUrl swaggerUrl = new AbstractSwaggerUiConfigProperties.SwaggerUrl();
swaggerUrl.setName(serviceId);
swaggerUrl.setUrl(String.format("/%s/v3/api-docs", doc));
swaggerUrlSet.add(swaggerUrl);
}
}
}
swaggerUiConfigProperties.setUrls(swaggerUrlSet);
}
}

View File

@ -70,8 +70,9 @@ public class PigRequestGlobalFilter implements GlobalFilter, Ordered {
// 2. 重写StripPrefix
addOriginalRequestUrl(exchange, request.getURI());
String rawPath = request.getURI().getRawPath();
String newPath = "/" + Arrays.stream(StringUtils.tokenizeToStringArray(rawPath, "/")).skip(1L)
.collect(Collectors.joining("/"));
String newPath = "/" + Arrays.stream(StringUtils.tokenizeToStringArray(rawPath, "/"))
.skip(1L)
.collect(Collectors.joining("/"));
ServerHttpRequest newRequest = request.mutate().path(newPath).build();
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, newRequest.getURI());

View File

@ -59,15 +59,16 @@ public class ImageCodeHandler implements HandlerFunction<ServerResponse> {
// 保存验证码信息
Optional<String> randomStr = serverRequest.queryParam("randomStr");
redisTemplate.setKeySerializer(new StringRedisSerializer());
randomStr.ifPresent(s -> redisTemplate.opsForValue().set(CacheConstants.DEFAULT_CODE_KEY + s, result,
SecurityConstants.CODE_TIME, TimeUnit.SECONDS));
randomStr.ifPresent(s -> redisTemplate.opsForValue()
.set(CacheConstants.DEFAULT_CODE_KEY + s, result, SecurityConstants.CODE_TIME, TimeUnit.SECONDS));
// 转换流信息写出
FastByteArrayOutputStream os = new FastByteArrayOutputStream();
captcha.out(os);
return ServerResponse.status(HttpStatus.OK).contentType(MediaType.IMAGE_JPEG)
.body(BodyInserters.fromResource(new ByteArrayResource(os.toByteArray())));
return ServerResponse.status(HttpStatus.OK)
.contentType(MediaType.IMAGE_JPEG)
.body(BodyInserters.fromResource(new ByteArrayResource(os.toByteArray())));
}
}

View File

@ -8,6 +8,9 @@ spring:
nacos:
discovery:
server-addr: ${NACOS_HOST:pig-register}:${NACOS_PORT:8848}
watch:
enabled: true
watch-delay: 1000
config:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
config:

View File

@ -1,4 +1,4 @@
FROM moxm/java:1.8-full
FROM alibabadragonwell/dragonwell:17-anolis
RUN mkdir -p /pig-register

View File

@ -28,8 +28,8 @@
<properties>
<nacos.version>2.2.0.PIGOEM</nacos.version>
<spring-boot-dependencies.version>2.7.7</spring-boot-dependencies.version>
<spring-cloud.version>2021.0.5</spring-cloud.version>
<spring-boot-dependencies.version>2.7.10</spring-boot-dependencies.version>
<spring-cloud.version>2021.0.7</spring-cloud.version>
<spring-boot-admin.version>2.7.8</spring-boot-admin.version>
</properties>
@ -131,6 +131,7 @@
<exclude>**/*.woff</exclude>
<exclude>**/*.woff2</exclude>
<exclude>**/*.ttf</exclude>
<exclude>**/*.eot</exclude>
</excludes>
</resource>
<resource>
@ -140,6 +141,7 @@
<include>**/*.woff</include>
<include>**/*.woff2</include>
<include>**/*.ttf</include>
<include>**/*.eot</include>
</includes>
</resource>
</resources>

View File

@ -77,7 +77,7 @@ public class HealthController {
if (!isConfigReadiness && !isNamingReadiness) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("Config and Naming are not in readiness");
.body("Config and Naming are not in readiness");
}
if (!isConfigReadiness) {

View File

@ -57,7 +57,7 @@ public class ConsoleExceptionHandler {
LOGGER.error("CONSOLE {}", uri, e);
if (uri.contains(Commons.NACOS_SERVER_VERSION_V2)) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(RestResultUtils.failed(ExceptionUtil.getAllExceptionMsg(e)));
.body(RestResultUtils.failed(ExceptionUtil.getAllExceptionMsg(e)));
}
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ExceptionUtil.getAllExceptionMsg(e));
}

View File

@ -59,7 +59,7 @@ public class NacosApiExceptionHandler {
public ResponseEntity<Result<String>> handleNacosApiException(NacosApiException e) {
LOGGER.error("got exception. {} {}", e.getErrAbstract(), e.getErrMsg());
return ResponseEntity.status(e.getErrCode())
.body(new Result<>(e.getDetailErrCode(), e.getErrAbstract(), e.getErrMsg()));
.body(new Result<>(e.getDetailErrCode(), e.getErrAbstract(), e.getErrMsg()));
}
@ExceptionHandler(NacosException.class)

View File

@ -1,4 +1,4 @@
FROM moxm/java:1.8-full
FROM alibabadragonwell/dragonwell:17-anolis
RUN mkdir -p /pig-upms-biz

View File

@ -27,7 +27,7 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
* @author lengleng
* @date 2018年06月21日 用户统一管理系统
*/
@EnablePigDoc
@EnablePigDoc("admin")
@EnablePigResourceServer
@EnablePigFeignClients
@EnableDiscoveryClient

View File

@ -76,7 +76,7 @@ public class DictController {
@GetMapping("/page")
public R<IPage<SysDict>> getDictPage(Page page, SysDict sysDict) {
return R.ok(sysDictService.page(page, Wrappers.<SysDict>lambdaQuery()
.like(StrUtil.isNotBlank(sysDict.getDictKey()), SysDict::getDictKey, sysDict.getDictKey())));
.like(StrUtil.isNotBlank(sysDict.getDictKey()), SysDict::getDictKey, sysDict.getDictKey())));
}
/**

View File

@ -65,7 +65,7 @@ public class FileController {
@GetMapping("/page")
public R<IPage<SysFile>> getSysFilePage(Page page, SysFile sysFile) {
return R.ok(sysFileService.page(page, Wrappers.<SysFile>lambdaQuery()
.like(StrUtil.isNotBlank(sysFile.getFileName()), SysFile::getFileName, sysFile.getFileName())));
.like(StrUtil.isNotBlank(sysFile.getFileName()), SysFile::getFileName, sysFile.getFileName())));
}
/**

View File

@ -56,8 +56,11 @@ public class MenuController {
@GetMapping
public R<List<Tree<Long>>> getUserMenu(Long parentId) {
// 获取符合条件的菜单
Set<SysMenu> menuSet = SecurityUtils.getRoles().stream().map(sysMenuService::findMenuByRoleId)
.flatMap(Collection::stream).collect(Collectors.toSet());
Set<SysMenu> menuSet = SecurityUtils.getRoles()
.stream()
.map(sysMenuService::findMenuByRoleId)
.flatMap(Collection::stream)
.collect(Collectors.toSet());
return R.ok(sysMenuService.filterMenu(menuSet, parentId));
}
@ -79,8 +82,8 @@ public class MenuController {
*/
@GetMapping("/tree/{roleId}")
public R<List<Long>> getRoleTree(@PathVariable Long roleId) {
return R.ok(
sysMenuService.findMenuByRoleId(roleId).stream().map(SysMenu::getMenuId).collect(Collectors.toList()));
return R
.ok(sysMenuService.findMenuByRoleId(roleId).stream().map(SysMenu::getMenuId).collect(Collectors.toList()));
}
/**

View File

@ -59,7 +59,7 @@ public class OauthClientDetailsController {
@GetMapping("/{clientId}")
public R<List<SysOauthClientDetails>> getByClientId(@PathVariable String clientId) {
return R.ok(sysOauthClientDetailsService
.list(Wrappers.<SysOauthClientDetails>lambdaQuery().eq(SysOauthClientDetails::getClientId, clientId)));
.list(Wrappers.<SysOauthClientDetails>lambdaQuery().eq(SysOauthClientDetails::getClientId, clientId)));
}
/**

View File

@ -71,10 +71,10 @@ public class PublicParamController {
public R getSysPublicParamPage(Page page, SysPublicParam sysPublicParam) {
return R.ok(sysPublicParamService.page(page,
Wrappers.<SysPublicParam>lambdaQuery()
.like(StrUtil.isNotBlank(sysPublicParam.getPublicName()), SysPublicParam::getPublicName,
sysPublicParam.getPublicName())
.like(StrUtil.isNotBlank(sysPublicParam.getPublicKey()), SysPublicParam::getPublicKey,
sysPublicParam.getPublicKey())));
.like(StrUtil.isNotBlank(sysPublicParam.getPublicName()), SysPublicParam::getPublicName,
sysPublicParam.getPublicName())
.like(StrUtil.isNotBlank(sysPublicParam.getPublicKey()), SysPublicParam::getPublicKey,
sysPublicParam.getPublicKey())));
}
/**

View File

@ -76,8 +76,8 @@ public class AppServiceImpl implements AppService {
String code = RandomUtil.randomNumbers(Integer.parseInt(SecurityConstants.CODE_SIZE));
log.info("手机号生成验证码成功:{},{}", sms.getPhone(), code);
redisTemplate.opsForValue().set(CacheConstants.DEFAULT_CODE_KEY + sms.getPhone(), code,
SecurityConstants.CODE_TIME, TimeUnit.SECONDS);
redisTemplate.opsForValue()
.set(CacheConstants.DEFAULT_CODE_KEY + sms.getPhone(), code, SecurityConstants.CODE_TIME, TimeUnit.SECONDS);
// 调用短信通道发送
this.smsClient.sendCode(code, sms.getPhone());

View File

@ -55,10 +55,12 @@ public class SysDeptRelationServiceImpl extends ServiceImpl<SysDeptRelationMappe
// 增加部门关系表
List<SysDeptRelation> relationList = sysDeptRelationMapper.selectList(
Wrappers.<SysDeptRelation>query().lambda().eq(SysDeptRelation::getDescendant, sysDept.getParentId()))
.stream().map(relation -> {
relation.setDescendant(sysDept.getDeptId());
return relation;
}).collect(Collectors.toList());
.stream()
.map(relation -> {
relation.setDescendant(sysDept.getDeptId());
return relation;
})
.collect(Collectors.toList());
if (CollUtil.isNotEmpty(relationList)) {
this.saveBatch(relationList);
}

View File

@ -75,8 +75,10 @@ public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> impl
public Boolean removeDeptById(Long id) {
// 级联删除部门
List<Long> idList = sysDeptRelationService
.list(Wrappers.<SysDeptRelation>query().lambda().eq(SysDeptRelation::getAncestor, id)).stream()
.map(SysDeptRelation::getDescendant).collect(Collectors.toList());
.list(Wrappers.<SysDeptRelation>query().lambda().eq(SysDeptRelation::getAncestor, id))
.stream()
.map(SysDeptRelation::getDescendant)
.collect(Collectors.toList());
if (CollUtil.isNotEmpty(idList)) {
this.removeByIds(idList);
@ -108,7 +110,8 @@ public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> impl
@Override
public List<Long> listChildDeptId(Long deptId) {
List<SysDeptRelation> deptRelations = sysDeptRelationService.list(Wrappers.<SysDeptRelation>lambdaQuery()
.eq(SysDeptRelation::getAncestor, deptId).ne(SysDeptRelation::getDescendant, deptId));
.eq(SysDeptRelation::getAncestor, deptId)
.ne(SysDeptRelation::getDescendant, deptId));
if (CollUtil.isNotEmpty(deptRelations)) {
return deptRelations.stream().map(SysDeptRelation::getDescendant).collect(Collectors.toList());
}
@ -132,8 +135,10 @@ public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> impl
public List<Tree<Long>> listCurrentUserDeptTrees() {
Long deptId = SecurityUtils.getUser().getDeptId();
List<Long> descendantIdList = sysDeptRelationService
.list(Wrappers.<SysDeptRelation>query().lambda().eq(SysDeptRelation::getAncestor, deptId)).stream()
.map(SysDeptRelation::getDescendant).collect(Collectors.toList());
.list(Wrappers.<SysDeptRelation>query().lambda().eq(SysDeptRelation::getAncestor, deptId))
.stream()
.map(SysDeptRelation::getDescendant)
.collect(Collectors.toList());
List<SysDept> deptList = baseMapper.selectBatchIds(descendantIdList);
Optional<SysDept> dept = deptList.stream().filter(item -> item.getDeptId().intValue() == deptId).findFirst();
@ -147,19 +152,22 @@ public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> impl
* @return
*/
private List<Tree<Long>> getDeptTree(List<SysDept> depts, Long parentId) {
List<TreeNode<Long>> collect = depts.stream().filter(dept -> dept.getDeptId().intValue() != dept.getParentId())
.sorted(Comparator.comparingInt(SysDept::getSortOrder)).map(dept -> {
TreeNode<Long> treeNode = new TreeNode();
treeNode.setId(dept.getDeptId());
treeNode.setParentId(dept.getParentId());
treeNode.setName(dept.getName());
treeNode.setWeight(dept.getSortOrder());
// 扩展属性
Map<String, Object> extra = new HashMap<>(4);
extra.put("createTime", dept.getCreateTime());
treeNode.setExtra(extra);
return treeNode;
}).collect(Collectors.toList());
List<TreeNode<Long>> collect = depts.stream()
.filter(dept -> dept.getDeptId().intValue() != dept.getParentId())
.sorted(Comparator.comparingInt(SysDept::getSortOrder))
.map(dept -> {
TreeNode<Long> treeNode = new TreeNode();
treeNode.setId(dept.getDeptId());
treeNode.setParentId(dept.getParentId());
treeNode.setName(dept.getName());
treeNode.setWeight(dept.getSortOrder());
// 扩展属性
Map<String, Object> extra = new HashMap<>(4);
extra.put("createTime", dept.getCreateTime());
treeNode.setExtra(extra);
return treeNode;
})
.collect(Collectors.toList());
return TreeUtil.build(collect, parentId);
}

View File

@ -63,12 +63,12 @@ public class SysLogServiceImpl extends ServiceImpl<SysLogMapper, SysLog> impleme
*/
private LambdaQueryWrapper buildQueryWrapper(SysLogDTO sysLog) {
LambdaQueryWrapper<SysLog> wrapper = Wrappers.<SysLog>lambdaQuery()
.eq(StrUtil.isNotBlank(sysLog.getType()), SysLog::getType, sysLog.getType())
.like(StrUtil.isNotBlank(sysLog.getRemoteAddr()), SysLog::getRemoteAddr, sysLog.getRemoteAddr());
.eq(StrUtil.isNotBlank(sysLog.getType()), SysLog::getType, sysLog.getType())
.like(StrUtil.isNotBlank(sysLog.getRemoteAddr()), SysLog::getRemoteAddr, sysLog.getRemoteAddr());
if (ArrayUtil.isNotEmpty(sysLog.getCreateTime())) {
wrapper.ge(SysLog::getCreateTime, sysLog.getCreateTime()[0]).le(SysLog::getCreateTime,
sysLog.getCreateTime()[1]);
wrapper.ge(SysLog::getCreateTime, sysLog.getCreateTime()[0])
.le(SysLog::getCreateTime, sysLog.getCreateTime()[1]);
}
return wrapper;

View File

@ -103,8 +103,10 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
public List<Tree<Long>> treeMenu(boolean lazy, Long parentId) {
if (!lazy) {
List<TreeNode<Long>> collect = baseMapper
.selectList(Wrappers.<SysMenu>lambdaQuery().orderByAsc(SysMenu::getSortOrder)).stream()
.map(getNodeFunction()).collect(Collectors.toList());
.selectList(Wrappers.<SysMenu>lambdaQuery().orderByAsc(SysMenu::getSortOrder))
.stream()
.map(getNodeFunction())
.collect(Collectors.toList());
return TreeUtil.build(collect, CommonConstants.MENU_TREE_ROOT_ID);
}
@ -112,9 +114,11 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
Long parent = parentId == null ? CommonConstants.MENU_TREE_ROOT_ID : parentId;
List<TreeNode<Long>> collect = baseMapper
.selectList(Wrappers.<SysMenu>lambdaQuery().eq(SysMenu::getParentId, parent)
.orderByAsc(SysMenu::getSortOrder))
.stream().map(getNodeFunction()).collect(Collectors.toList());
.selectList(
Wrappers.<SysMenu>lambdaQuery().eq(SysMenu::getParentId, parent).orderByAsc(SysMenu::getSortOrder))
.stream()
.map(getNodeFunction())
.collect(Collectors.toList());
return TreeUtil.build(collect, parent);
}
@ -128,8 +132,10 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
@Override
public List<Tree<Long>> filterMenu(Set<SysMenu> all, Long parentId) {
List<TreeNode<Long>> collect = all.stream()
.filter(menu -> MenuTypeEnum.LEFT_MENU.getType().equals(menu.getType()))
.filter(menu -> StrUtil.isNotBlank(menu.getPath())).map(getNodeFunction()).collect(Collectors.toList());
.filter(menu -> MenuTypeEnum.LEFT_MENU.getType().equals(menu.getType()))
.filter(menu -> StrUtil.isNotBlank(menu.getPath()))
.map(getNodeFunction())
.collect(Collectors.toList());
Long parent = parentId == null ? CommonConstants.MENU_TREE_ROOT_ID : parentId;
return TreeUtil.build(collect, parent);
}

View File

@ -63,8 +63,9 @@ public class SysPostServiceImpl extends ServiceImpl<SysPostMapper, SysPost> impl
for (PostExcelVO excel : excelVOList) {
Set<String> errorMsg = new HashSet<>();
// 检验岗位名称或者岗位编码是否存在
boolean existPost = postList.stream().anyMatch(post -> excel.getPostName().equals(post.getPostName())
|| excel.getPostCode().equals(post.getPostCode()));
boolean existPost = postList.stream()
.anyMatch(post -> excel.getPostName().equals(post.getPostName())
|| excel.getPostCode().equals(post.getPostCode()));
if (existPost) {
errorMsg.add(MsgUtils.getMessage(ErrorCodes.SYS_POST_NAMEORCODE_EXISTING, excel.getPostName(),

View File

@ -47,7 +47,7 @@ public class SysPublicParamServiceImpl extends ServiceImpl<SysPublicParamMapper,
@Cacheable(value = CacheConstants.PARAMS_DETAILS, key = "#publicKey", unless = "#result == null ")
public String getSysPublicParamKeyToValue(String publicKey) {
SysPublicParam sysPublicParam = this.baseMapper
.selectOne(Wrappers.<SysPublicParam>lambdaQuery().eq(SysPublicParam::getPublicKey, publicKey));
.selectOne(Wrappers.<SysPublicParam>lambdaQuery().eq(SysPublicParam::getPublicKey, publicKey));
if (sysPublicParam != null) {
return sysPublicParam.getPublicValue();

View File

@ -87,8 +87,9 @@ public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> impl
for (RoleExcelVO excel : excelVOList) {
Set<String> errorMsg = new HashSet<>();
// 检验角色名称或者角色编码是否存在
boolean existRole = roleList.stream().anyMatch(sysRole -> excel.getRoleName().equals(sysRole.getRoleName())
|| excel.getRoleCode().equals(sysRole.getRoleCode()));
boolean existRole = roleList.stream()
.anyMatch(sysRole -> excel.getRoleName().equals(sysRole.getRoleName())
|| excel.getRoleCode().equals(sysRole.getRoleCode()));
if (existRole) {
errorMsg.add(MsgUtils.getMessage(ErrorCodes.SYS_ROLE_NAMEORCODE_EXISTING, excel.getRoleName(),

View File

@ -130,9 +130,13 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
List<SysPost> postList = sysPostMapper.listPostsByUserId(sysUser.getUserId());
userInfo.setPostList(postList);
// 设置权限列表menu.permission
Set<String> permissions = roleIds.stream().map(sysMenuService::findMenuByRoleId).flatMap(Collection::stream)
.filter(m -> MenuTypeEnum.BUTTON.getType().equals(m.getType())).map(SysMenu::getPermission)
.filter(StrUtil::isNotBlank).collect(Collectors.toSet());
Set<String> permissions = roleIds.stream()
.map(sysMenuService::findMenuByRoleId)
.flatMap(Collection::stream)
.filter(m -> MenuTypeEnum.BUTTON.getType().equals(m.getType()))
.map(SysMenu::getPermission)
.filter(StrUtil::isNotBlank)
.collect(Collectors.toSet());
userInfo.setPermissions(ArrayUtil.toArray(permissions, String.class));
return userInfo;
@ -213,7 +217,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
this.updateById(sysUser);
sysUserRoleMapper
.delete(Wrappers.<SysUserRole>update().lambda().eq(SysUserRole::getUserId, userDto.getUserId()));
.delete(Wrappers.<SysUserRole>update().lambda().eq(SysUserRole::getUserId, userDto.getUserId()));
userDto.getRole().forEach(roleId -> {
SysUserRole userRole = new SysUserRole();
userRole.setUserId(sysUser.getUserId());
@ -260,11 +264,15 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
List<UserExcelVO> userExcelVOList = voList.stream().map(userVO -> {
UserExcelVO excelVO = new UserExcelVO();
BeanUtils.copyProperties(userVO, excelVO);
String roleNameList = userVO.getRoleList().stream().map(SysRole::getRoleName)
.collect(Collectors.joining(StrUtil.COMMA));
String roleNameList = userVO.getRoleList()
.stream()
.map(SysRole::getRoleName)
.collect(Collectors.joining(StrUtil.COMMA));
excelVO.setRoleNameList(roleNameList);
String postNameList = userVO.getPostList().stream().map(SysPost::getPostName)
.collect(Collectors.joining(StrUtil.COMMA));
String postNameList = userVO.getPostList()
.stream()
.map(SysPost::getPostName)
.collect(Collectors.joining(StrUtil.COMMA));
excelVO.setPostNameList(postNameList);
return excelVO;
}).collect(Collectors.toList());
@ -293,7 +301,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
Set<String> errorMsg = new HashSet<>();
// 校验用户名是否存在
boolean exsitUserName = userList.stream()
.anyMatch(sysUser -> excel.getUsername().equals(sysUser.getUsername()));
.anyMatch(sysUser -> excel.getUsername().equals(sysUser.getUsername()));
if (exsitUserName) {
errorMsg.add(MsgUtils.getMessage(ErrorCodes.SYS_USER_USERNAME_EXISTING, excel.getUsername()));
@ -301,7 +309,8 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
// 判断输入的部门名称列表是否合法
Optional<SysDept> deptOptional = deptList.stream()
.filter(dept -> excel.getDeptName().equals(dept.getName())).findFirst();
.filter(dept -> excel.getDeptName().equals(dept.getName()))
.findFirst();
if (!deptOptional.isPresent()) {
errorMsg.add(MsgUtils.getMessage(ErrorCodes.SYS_DEPT_DEPTNAME_INEXISTENCE, excel.getDeptName()));
}
@ -309,8 +318,8 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
// 判断输入的角色名称列表是否合法
List<String> roleNameList = StrUtil.split(excel.getRoleNameList(), StrUtil.COMMA);
List<SysRole> roleCollList = roleList.stream()
.filter(role -> roleNameList.stream().anyMatch(name -> role.getRoleName().equals(name)))
.collect(Collectors.toList());
.filter(role -> roleNameList.stream().anyMatch(name -> role.getRoleName().equals(name)))
.collect(Collectors.toList());
if (roleCollList.size() != roleNameList.size()) {
errorMsg.add(MsgUtils.getMessage(ErrorCodes.SYS_ROLE_ROLENAME_INEXISTENCE, excel.getRoleNameList()));
@ -319,8 +328,8 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
// 判断输入的岗位名称列表是否合法
List<String> postNameList = StrUtil.split(excel.getPostNameList(), StrUtil.COMMA);
List<SysPost> postCollList = postList.stream()
.filter(post -> postNameList.stream().anyMatch(name -> post.getPostName().equals(name)))
.collect(Collectors.toList());
.filter(post -> postNameList.stream().anyMatch(name -> post.getPostName().equals(name)))
.collect(Collectors.toList());
if (postCollList.size() != postNameList.size()) {
errorMsg.add(MsgUtils.getMessage(ErrorCodes.SYS_POST_POSTNAME_INEXISTENCE, excel.getPostNameList()));
@ -393,7 +402,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
String defaultRole = ParamResolver.getStr("USER_DEFAULT_ROLE");
// 默认角色
SysRole sysRole = sysRoleMapper
.selectOne(Wrappers.<SysRole>lambdaQuery().eq(SysRole::getRoleCode, defaultRole));
.selectOne(Wrappers.<SysRole>lambdaQuery().eq(SysRole::getRoleCode, defaultRole));
if (sysRole == null) {
return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_PARAM_CONFIG_ERROR, "USER_DEFAULT_ROLE"));

View File

@ -1,4 +1,4 @@
FROM moxm/java:1.8-full
FROM alibabadragonwell/dragonwell:17-anolis
RUN mkdir -p /pig-codegen

View File

@ -19,7 +19,6 @@ package com.pig4cloud.pig.codegen;
import com.pig4cloud.pig.common.datasource.annotation.EnableDynamicDataSource;
import com.pig4cloud.pig.common.feign.annotation.EnablePigFeignClients;
import com.pig4cloud.pig.common.security.annotation.EnablePigResourceServer;
import com.pig4cloud.pig.common.swagger.annotation.EnablePigDoc;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@ -28,7 +27,6 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
* @author lengleng
* @date 2020/03/11 代码生成模块
*/
@EnablePigDoc
@EnableDynamicDataSource
@EnablePigFeignClients
@EnableDiscoveryClient

View File

@ -82,7 +82,7 @@ public class GenDatasourceConfServiceImpl extends ServiceImpl<GenDatasourceConfM
}
// 先移除
SpringContextHolder.getBean(DynamicRoutingDataSource.class)
.removeDataSource(baseMapper.selectById(conf.getId()).getName());
.removeDataSource(baseMapper.selectById(conf.getId()).getName());
// 再添加
addDynamicDataSource(conf);
@ -103,7 +103,7 @@ public class GenDatasourceConfServiceImpl extends ServiceImpl<GenDatasourceConfM
@Override
public Boolean removeByDsId(Long dsId) {
SpringContextHolder.getBean(DynamicRoutingDataSource.class)
.removeDataSource(baseMapper.selectById(dsId).getName());
.removeDataSource(baseMapper.selectById(dsId).getName());
this.baseMapper.deleteById(dsId);
return Boolean.TRUE;
}
@ -121,8 +121,8 @@ public class GenDatasourceConfServiceImpl extends ServiceImpl<GenDatasourceConfM
dataSourceProperty.setPassword(conf.getPassword());
dataSourceProperty.setLazy(true);
DataSource dataSource = hikariDataSourceCreator.createDataSource(dataSourceProperty);
SpringContextHolder.getBean(DynamicRoutingDataSource.class).addDataSource(dataSourceProperty.getPoolName(),
dataSource);
SpringContextHolder.getBean(DynamicRoutingDataSource.class)
.addDataSource(dataSourceProperty.getPoolName(), dataSource);
}
/**

View File

@ -63,8 +63,9 @@ public class GenFormConfServiceImpl extends ServiceImpl<GenFormConfMapper, GenFo
@Override
@SneakyThrows
public String getForm(String dsName, String tableName) {
GenFormConf form = getOne(Wrappers.<GenFormConf>lambdaQuery().eq(GenFormConf::getTableName, tableName)
.orderByDesc(GenFormConf::getCreateTime), false);
GenFormConf form = getOne(Wrappers.<GenFormConf>lambdaQuery()
.eq(GenFormConf::getTableName, tableName)
.orderByDesc(GenFormConf::getCreateTime), false);
if (form != null) {
return form.getFormInfo();

View File

@ -77,7 +77,8 @@ public class GeneratorServiceImpl implements GeneratorService {
public Map<String, String> previewCode(GenConfig genConfig) {
// 根据tableName 查询最新的表单配置
List<GenFormConf> formConfList = genFormConfMapper.selectList(Wrappers.<GenFormConf>lambdaQuery()
.eq(GenFormConf::getTableName, genConfig.getTableName()).orderByDesc(GenFormConf::getCreateTime));
.eq(GenFormConf::getTableName, genConfig.getTableName())
.orderByDesc(GenFormConf::getCreateTime));
String tableNames = genConfig.getTableName();
String dsName = genConfig.getDsName();
@ -111,7 +112,8 @@ public class GeneratorServiceImpl implements GeneratorService {
public byte[] generatorCode(GenConfig genConfig) {
// 根据tableName 查询最新的表单配置
List<GenFormConf> formConfList = genFormConfMapper.selectList(Wrappers.<GenFormConf>lambdaQuery()
.eq(GenFormConf::getTableName, genConfig.getTableName()).orderByDesc(GenFormConf::getCreateTime));
.eq(GenFormConf::getTableName, genConfig.getTableName())
.orderByDesc(GenFormConf::getCreateTime));
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ZipOutputStream zip = new ZipOutputStream(outputStream);

View File

@ -36,8 +36,11 @@ public enum StyleTypeEnum {
private String description;
public static String getDecs(String style) {
return Arrays.stream(StyleTypeEnum.values()).filter(styleTypeEnum -> styleTypeEnum.getStyle().equals(style))
.findFirst().orElse(ELEMENT).getDescription();
return Arrays.stream(StyleTypeEnum.values())
.filter(styleTypeEnum -> styleTypeEnum.getStyle().equals(style))
.findFirst()
.orElse(ELEMENT)
.getDescription();
}
}

View File

@ -1,4 +1,4 @@
FROM moxm/java:1.8-full
FROM alibabadragonwell/dragonwell:17-anolis
RUN mkdir -p /pig-monitor

View File

@ -20,8 +20,6 @@ import de.codecentric.boot.admin.server.config.AdminServerProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
@ -51,21 +49,28 @@ public class WebSecurityConfigurer {
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setTargetUrlParameter("redirectTo");
successHandler.setDefaultTargetUrl(adminContextPath + "/");
http.headers(httpSecurityHeadersConfigurer -> {
httpSecurityHeadersConfigurer.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable);
}).authorizeHttpRequests(authorizationManagerRequestMatcherRegistry -> {
authorizationManagerRequestMatcherRegistry
.requestMatchers(adminContextPath + "/assets/**", adminContextPath + "/login",
adminContextPath + "/instances/**", adminContextPath + "/actuator/**")
.permitAll().anyRequest().authenticated();
}).formLogin(httpSecurityFormLoginConfigurer -> {
httpSecurityFormLoginConfigurer.loginPage(adminContextPath + "/login");
httpSecurityFormLoginConfigurer.successHandler(successHandler);
}).logout(httpSecurityLogoutConfigurer -> {
httpSecurityLogoutConfigurer.logoutUrl(adminContextPath + "/logout");
}).httpBasic(httpSecurityHttpBasicConfigurer -> {
}).csrf(AbstractHttpConfigurer::disable);
http.headers()
.frameOptions()
.disable()
.and()
.authorizeHttpRequests()
.requestMatchers(adminContextPath + "/assets/**", adminContextPath + "/login",
adminContextPath + "/instances/**", adminContextPath + "/actuator/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage(adminContextPath + "/login")
.successHandler(successHandler)
.and()
.logout()
.logoutUrl(adminContextPath + "/logout")
.and()
.httpBasic()
.and()
.csrf()
.disable();
return http.build();
}

View File

@ -20,10 +20,11 @@ public class NacosServiceInstanceConverter extends DefaultServiceInstanceConvert
@Override
protected Map<String, String> getMetadata(ServiceInstance instance) {
return (instance.getMetadata() != null)
? instance.getMetadata().entrySet().stream().filter((e) -> e.getKey() != null && e.getValue() != null)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))
: emptyMap();
return (instance.getMetadata() != null) ? instance.getMetadata()
.entrySet()
.stream()
.filter((e) -> e.getKey() != null && e.getValue() != null)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)) : emptyMap();
}
}

View File

@ -1,15 +0,0 @@
FROM moxm/java:1.8-full
RUN mkdir -p /pig-sentinel-dashboard
WORKDIR /pig-sentinel-dashboard
ARG JAR_FILE=target/pig-sentinel-dashboard.jar
COPY ${JAR_FILE} app.jar
EXPOSE 5003
ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms128m -Xmx256m -Djava.security.egd=file:/dev/./urandom"
CMD sleep 60; java $JAVA_OPTS -jar app.jar

View File

@ -1,157 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.pig4cloud</groupId>
<artifactId>pig-visual</artifactId>
<version>3.6.4</version>
</parent>
<artifactId>pig-sentinel-dashboard</artifactId>
<packaging>jar</packaging>
<properties>
<spring-boot-dependencies.version>2.7.7</spring-boot-dependencies.version>
<spring-cloud.version>2021.0.5</spring-cloud.version>
<spring-boot-admin.version>2.7.8</spring-boot-admin.version>
<spring-cloud-alibaba.version>2021.0.4.0</spring-cloud-alibaba.version>
</properties>
<dependencies>
<!--注册中心客户端-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-web-servlet</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-parameter-flow-control</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-api-gateway-adapter-common</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--undertow容器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.5</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpasyncclient</artifactId>
<version>4.1.3</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore-nio</artifactId>
<version>4.4.6</version>
</dependency>
</dependencies>
<!--依赖版本声明-->
<dependencyManagement>
<dependencies>
<!-- SpringBoot 依赖配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot-dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- SpringCloud 微服务 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- SpringBoot Admin -->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>${spring-boot-admin.version}</version>
</dependency>
<!-- spring cloud alibaba 依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<finalName>pig-sentinel-dashboard</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/webapp/</directory>
<excludes>
<exclude>resources/node_modules/**</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
<skip>false</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,39 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 com.alibaba.csp.sentinel.dashboard;
import com.alibaba.csp.sentinel.init.InitExecutor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Sentinel dashboard application.
*
* @author Carpenter Lee
*/
@SpringBootApplication
public class PigSentinelApplication {
public static void main(String[] args) {
triggerSentinelInit();
SpringApplication.run(PigSentinelApplication.class, args);
}
private static void triggerSentinelInit() {
new Thread(() -> InitExecutor.doInit()).start();
}
}

View File

@ -1,44 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 com.alibaba.csp.sentinel.dashboard.auth;
import java.lang.annotation.*;
/**
* @author lkxiaolou 无改动
* @since 1.7.1
*/
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target({ ElementType.METHOD })
public @interface AuthAction {
/**
* @return the privilege type
*/
AuthService.PrivilegeType value();
/**
* @return the target name to control
*/
String targetName() default "app";
/**
* @return the message when permission is denied
*/
String message() default "Permission denied";
}

View File

@ -1,112 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 com.alibaba.csp.sentinel.dashboard.auth;
/**
* Interface for authentication and authorization. 不需要改
*
* @author Carpenter Lee
* @since 1.5.0
*/
public interface AuthService<R> {
/**
* Get the authentication user.
* @param request the request contains the user information
* @return the auth user represent the current user, when the user is illegal, a null
* value will return.
*/
AuthUser getAuthUser(R request);
/**
* Privilege type.
*/
enum PrivilegeType {
/**
* Read rule
*/
READ_RULE,
/**
* Create or modify rule
*/
WRITE_RULE,
/**
* Delete rule
*/
DELETE_RULE,
/**
* Read metrics
*/
READ_METRIC,
/**
* Add machine
*/
ADD_MACHINE,
/**
* All privileges above are granted.
*/
ALL
}
/**
* Represents the current user.
*/
interface AuthUser {
/**
* Query whether current user has the specific privilege to the target, the target
* may be an app name or an ip address, or other destination.
* <p>
* This method will use return value to represent whether user has the specific
* privileges to the target, but to throw a RuntimeException to represent no auth
* is also a good way.
* </p>
* @param target the target to check
* @param privilegeType the privilege type to check
* @return if current user has the specific privileges to the target, return true,
* otherwise return false.
*/
boolean authTarget(String target, PrivilegeType privilegeType);
/**
* Check whether current user is a super-user.
* @return if current user is super user return true, else return false.
*/
boolean isSuperUser();
/**
* Get current user's nick name.
* @return current user's nick name.
*/
String getNickName();
/**
* Get current user's login name.
* @return current user's login name.
*/
String getLoginName();
/**
* Get current user's ID.
* @return ID of current user
*/
String getId();
}
}

View File

@ -1,29 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 com.alibaba.csp.sentinel.dashboard.auth;
import org.springframework.web.servlet.HandlerInterceptor;
/**
* The web interceptor for privilege-based authorization. 不需要改
*
* @author lkxiaolou
* @author wxq
* @since 1.7.1
*/
public interface AuthorizationInterceptor extends HandlerInterceptor {
}

View File

@ -1,75 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 com.alibaba.csp.sentinel.dashboard.auth;
import com.alibaba.csp.sentinel.dashboard.domain.Result;
import com.alibaba.fastjson.JSON;
import org.springframework.web.method.HandlerMethod;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
/**
* The web interceptor for privilege-based authorization. 不需要
* <p>
* move from old {@link AuthorizationInterceptor}.
*
* @author lkxiaolou
* @author wxq
* @since 1.7.1
*/
public class DefaultAuthorizationInterceptor implements AuthorizationInterceptor {
private final AuthService<HttpServletRequest> authService;
public DefaultAuthorizationInterceptor(AuthService<HttpServletRequest> authService) {
this.authService = authService;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (handler.getClass().isAssignableFrom(HandlerMethod.class)) {
Method method = ((HandlerMethod) handler).getMethod();
AuthAction authAction = method.getAnnotation(AuthAction.class);
if (authAction != null) {
AuthService.AuthUser authUser = authService.getAuthUser(request);
if (authUser == null) {
responseNoPrivilegeMsg(response, authAction.message());
return false;
}
String target = request.getParameter(authAction.targetName());
if (!authUser.authTarget(target, authAction.value())) {
responseNoPrivilegeMsg(response, authAction.message());
return false;
}
}
}
return true;
}
private void responseNoPrivilegeMsg(HttpServletResponse response, String message) throws IOException {
Result result = Result.ofFail(-1, message);
response.addHeader("Content-Type", "application/json;charset=UTF-8");
response.getOutputStream().write(JSON.toJSONBytes(result));
}
}

View File

@ -1,131 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 com.alibaba.csp.sentinel.dashboard.auth;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.util.AntPathMatcher;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
/**
* <p>
* The Servlet filter for authentication.
* </p>
*
* <p>
* Note: some urls are excluded as they needn't auth, such as:
* </p>
* <ul>
* <li>index url: {@code /}</li>
* <li>authentication request url: {@code /login}, {@code /logout}</li>
* <li>machine registry: {@code /registry/machine}</li>
* <li>static resources</li>
* </ul>
* <p>
* The excluded urls and urlSuffixes could be configured in {@code application.properties}
* file.
*
* @author cdfive 不需要
* @since 1.6.0
*/
public class DefaultLoginAuthenticationFilter implements LoginAuthenticationFilter {
private static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
private static final String URL_SUFFIX_DOT = ".";
/**
* 忽略鉴权的url
*/
@Value("#{'${auth.filter.exclude-urls}'.split(',')}")
private List<String> authFilterExcludeUrls;
/**
* 根据后缀不需要鉴权的url
*/
@Value("#{'${auth.filter.exclude-url-suffixes}'.split(',')}")
private List<String> authFilterExcludeUrlSuffixes;
/**
* Authentication using AuthService interface.
*/
private final AuthService<HttpServletRequest> authService;
public DefaultLoginAuthenticationFilter(AuthService<HttpServletRequest> authService) {
this.authService = authService;
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String servletPath = httpRequest.getServletPath();
// Exclude the urls which needn't auth
boolean authFilterExcludeMatch = authFilterExcludeUrls.stream()
.anyMatch(authFilterExcludeUrl -> PATH_MATCHER.match(authFilterExcludeUrl, servletPath));
if (authFilterExcludeMatch) {
chain.doFilter(request, response);
return;
}
// Exclude the urls with suffixes which needn't auth
for (String authFilterExcludeUrlSuffix : authFilterExcludeUrlSuffixes) {
if (StringUtils.isBlank(authFilterExcludeUrlSuffix)) {
continue;
}
// Add . for url suffix so that we needn't add . in property file
if (!authFilterExcludeUrlSuffix.startsWith(URL_SUFFIX_DOT)) {
authFilterExcludeUrlSuffix = URL_SUFFIX_DOT + authFilterExcludeUrlSuffix;
}
if (servletPath.endsWith(authFilterExcludeUrlSuffix)) {
chain.doFilter(request, response);
return;
}
}
AuthService.AuthUser authUser = authService.getAuthUser(httpRequest);
HttpServletResponse httpResponse = (HttpServletResponse) response;
if (authUser == null) {
// If auth fail, set response status code to 401
httpResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
}
else {
chain.doFilter(request, response);
}
}
@Override
public void destroy() {
}
}

View File

@ -1,73 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 com.alibaba.csp.sentinel.dashboard.auth;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
/**
* A fake AuthService implementation, which will pass all user auth checking.
*
* @author Carpenter Lee
* @since 1.5.0
*/
public class FakeAuthServiceImpl implements AuthService<HttpServletRequest> {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
public FakeAuthServiceImpl() {
this.logger.warn("there is no auth, use {} by implementation {}", AuthService.class, this.getClass());
}
@Override
public AuthUser getAuthUser(HttpServletRequest request) {
return new AuthUserImpl();
}
static final class AuthUserImpl implements AuthUser {
@Override
public boolean authTarget(String target, PrivilegeType privilegeType) {
// fake implementation, always return true
return true;
}
@Override
public boolean isSuperUser() {
// fake implementation, always return true
return true;
}
@Override
public String getNickName() {
return "FAKE_NICK_NAME";
}
@Override
public String getLoginName() {
return "FAKE_LOGIN_NAME";
}
@Override
public String getId() {
return "FAKE_EMP_ID";
}
}
}

View File

@ -1,44 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 com.alibaba.csp.sentinel.dashboard.auth;
import javax.servlet.Filter;
/**
* <p>
* The Servlet filter for authentication.
* </p>
*
* <p>
* Note: some urls are excluded as they needn't auth, such as:
* </p>
* <ul>
* <li>index url: {@code /}</li>
* <li>authentication request url: {@code /login}, {@code /logout}</li>
* <li>machine registry: {@code /registry/machine}</li>
* <li>static resources</li>
* </ul>
* <p>
* The excluded urls and urlSuffixes could be configured in {@code application.properties}
* file.
*
* @author cdfive 不需要
* @author wxq
* @since 1.6.0
*/
public interface LoginAuthenticationFilter extends Filter {
}

View File

@ -1,75 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 com.alibaba.csp.sentinel.dashboard.auth;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* @author cdfive 不需要
* @since 1.6.0
*/
public class SimpleWebAuthServiceImpl implements AuthService<HttpServletRequest> {
public static final String WEB_SESSION_KEY = "session_sentinel_admin";
@Override
public AuthUser getAuthUser(HttpServletRequest request) {
HttpSession session = request.getSession();
Object sentinelUserObj = session.getAttribute(SimpleWebAuthServiceImpl.WEB_SESSION_KEY);
if (sentinelUserObj != null && sentinelUserObj instanceof AuthUser) {
return (AuthUser) sentinelUserObj;
}
return null;
}
public static final class SimpleWebAuthUserImpl implements AuthUser {
private String username;
public SimpleWebAuthUserImpl(String username) {
this.username = username;
}
@Override
public boolean authTarget(String target, PrivilegeType privilegeType) {
return true;
}
@Override
public boolean isSuperUser() {
return true;
}
@Override
public String getNickName() {
return username;
}
@Override
public String getLoginName() {
return username;
}
@Override
public String getId() {
return username;
}
}
}

View File

@ -1,35 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 com.alibaba.csp.sentinel.dashboard.client;
/**
* @author Eric Zhao
*/
public class CommandFailedException extends RuntimeException {
public CommandFailedException() {
}
public CommandFailedException(String message) {
super(message);
}
@Override
public synchronized Throwable fillInStackTrace() {
return this;
}
}

View File

@ -1,36 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 com.alibaba.csp.sentinel.dashboard.client;
/**
* @author Eric Zhao
* @since 0.2.1
*/
public class CommandNotFoundException extends Exception {
public CommandNotFoundException() {
}
public CommandNotFoundException(String message) {
super(message);
}
@Override
public synchronized Throwable fillInStackTrace() {
return this;
}
}

View File

@ -1,884 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 com.alibaba.csp.sentinel.dashboard.client;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.command.CommandConstants;
import com.alibaba.csp.sentinel.command.vo.NodeVo;
import com.alibaba.csp.sentinel.config.SentinelConfig;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.SentinelVersion;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.ApiDefinitionEntity;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.GatewayFlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.*;
import com.alibaba.csp.sentinel.dashboard.discovery.AppManagement;
import com.alibaba.csp.sentinel.dashboard.domain.cluster.ClusterClientInfoVO;
import com.alibaba.csp.sentinel.dashboard.domain.cluster.config.ClusterClientConfig;
import com.alibaba.csp.sentinel.dashboard.domain.cluster.config.ServerFlowConfig;
import com.alibaba.csp.sentinel.dashboard.domain.cluster.config.ServerTransportConfig;
import com.alibaba.csp.sentinel.dashboard.domain.cluster.state.ClusterServerStateVO;
import com.alibaba.csp.sentinel.dashboard.domain.cluster.state.ClusterStateSimpleEntity;
import com.alibaba.csp.sentinel.dashboard.util.AsyncUtils;
import com.alibaba.csp.sentinel.dashboard.util.VersionUtils;
import com.alibaba.csp.sentinel.slots.block.Rule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.fastjson.JSON;
import org.apache.http.Consts;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.DefaultRedirectStrategy;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
/**
* Communicate with Sentinel client.
*
* @author leyou
*/
@Component
public class SentinelApiClient {
private static Logger logger = LoggerFactory.getLogger(SentinelApiClient.class);
private static final Charset DEFAULT_CHARSET = Charset.forName(SentinelConfig.charset());
private static final String HTTP_HEADER_CONTENT_TYPE = "Content-Type";
private static final String HTTP_HEADER_CONTENT_TYPE_URLENCODED = ContentType.create(URLEncodedUtils.CONTENT_TYPE)
.toString();
private static final String RESOURCE_URL_PATH = "jsonTree";
private static final String CLUSTER_NODE_PATH = "clusterNode";
private static final String GET_RULES_PATH = "getRules";
private static final String SET_RULES_PATH = "setRules";
private static final String GET_PARAM_RULE_PATH = "getParamFlowRules";
private static final String SET_PARAM_RULE_PATH = "setParamFlowRules";
private static final String FETCH_CLUSTER_MODE_PATH = "getClusterMode";
private static final String MODIFY_CLUSTER_MODE_PATH = "setClusterMode";
private static final String FETCH_CLUSTER_CLIENT_CONFIG_PATH = "cluster/client/fetchConfig";
private static final String MODIFY_CLUSTER_CLIENT_CONFIG_PATH = "cluster/client/modifyConfig";
private static final String FETCH_CLUSTER_SERVER_BASIC_INFO_PATH = "cluster/server/info";
private static final String MODIFY_CLUSTER_SERVER_TRANSPORT_CONFIG_PATH = "cluster/server/modifyTransportConfig";
private static final String MODIFY_CLUSTER_SERVER_FLOW_CONFIG_PATH = "cluster/server/modifyFlowConfig";
private static final String MODIFY_CLUSTER_SERVER_NAMESPACE_SET_PATH = "cluster/server/modifyNamespaceSet";
private static final String FETCH_GATEWAY_API_PATH = "gateway/getApiDefinitions";
private static final String MODIFY_GATEWAY_API_PATH = "gateway/updateApiDefinitions";
private static final String FETCH_GATEWAY_FLOW_RULE_PATH = "gateway/getRules";
private static final String MODIFY_GATEWAY_FLOW_RULE_PATH = "gateway/updateRules";
private static final String FLOW_RULE_TYPE = "flow";
private static final String DEGRADE_RULE_TYPE = "degrade";
private static final String SYSTEM_RULE_TYPE = "system";
private static final String AUTHORITY_TYPE = "authority";
private CloseableHttpAsyncClient httpClient;
private static final SentinelVersion version160 = new SentinelVersion(1, 6, 0);
private static final SentinelVersion version171 = new SentinelVersion(1, 7, 1);
@Autowired
private AppManagement appManagement;
public SentinelApiClient() {
IOReactorConfig ioConfig = IOReactorConfig.custom().setConnectTimeout(3000).setSoTimeout(10000)
.setIoThreadCount(Runtime.getRuntime().availableProcessors() * 2).build();
httpClient = HttpAsyncClients.custom().setRedirectStrategy(new DefaultRedirectStrategy() {
@Override
protected boolean isRedirectable(final String method) {
return false;
}
}).setMaxConnTotal(4000).setMaxConnPerRoute(1000).setDefaultIOReactorConfig(ioConfig).build();
httpClient.start();
}
private boolean isSuccess(int statusCode) {
return statusCode >= 200 && statusCode < 300;
}
private boolean isCommandNotFound(int statusCode, String body) {
return statusCode == 400 && StringUtil.isNotEmpty(body)
&& body.contains(CommandConstants.MSG_UNKNOWN_COMMAND_PREFIX);
}
protected boolean isSupportPost(String app, String ip, int port) {
return StringUtil.isNotEmpty(app)
&& Optional.ofNullable(appManagement.getDetailApp(app)).flatMap(e -> e.getMachine(ip, port))
.flatMap(m -> VersionUtils.parseVersion(m.getVersion()).map(v -> v.greaterOrEqual(version160)))
.orElse(false);
}
/**
* Check whether target instance (identified by tuple of app-ip:port) supports the
* form of "xxxxx; xx=xx" in "Content-Type" header.
* @param app target app name
* @param ip target node's address
* @param port target node's port
*/
protected boolean isSupportEnhancedContentType(String app, String ip, int port) {
return StringUtil.isNotEmpty(app)
&& Optional.ofNullable(appManagement.getDetailApp(app)).flatMap(e -> e.getMachine(ip, port))
.flatMap(m -> VersionUtils.parseVersion(m.getVersion()).map(v -> v.greaterOrEqual(version171)))
.orElse(false);
}
private StringBuilder queryString(Map<String, String> params) {
StringBuilder queryStringBuilder = new StringBuilder();
for (Entry<String, String> entry : params.entrySet()) {
if (StringUtil.isEmpty(entry.getValue())) {
continue;
}
String name = urlEncode(entry.getKey());
String value = urlEncode(entry.getValue());
if (name != null && value != null) {
if (queryStringBuilder.length() > 0) {
queryStringBuilder.append('&');
}
queryStringBuilder.append(name).append('=').append(value);
}
}
return queryStringBuilder;
}
/**
* Build an `HttpUriRequest` in POST way.
* @param url
* @param params
* @param supportEnhancedContentType see
* {@link #isSupportEnhancedContentType(String, String, int)}
* @return
*/
protected static HttpUriRequest postRequest(String url, Map<String, String> params,
boolean supportEnhancedContentType) {
HttpPost httpPost = new HttpPost(url);
if (params != null && params.size() > 0) {
List<NameValuePair> list = new ArrayList<>(params.size());
for (Entry<String, String> entry : params.entrySet()) {
list.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
httpPost.setEntity(new UrlEncodedFormEntity(list, Consts.UTF_8));
if (!supportEnhancedContentType) {
httpPost.setHeader(HTTP_HEADER_CONTENT_TYPE, HTTP_HEADER_CONTENT_TYPE_URLENCODED);
}
}
return httpPost;
}
private String urlEncode(String str) {
try {
return URLEncoder.encode(str, DEFAULT_CHARSET.name());
}
catch (UnsupportedEncodingException e) {
logger.info("encode string error: {}", str, e);
return null;
}
}
private String getBody(HttpResponse response) throws Exception {
Charset charset = null;
try {
String contentTypeStr = response.getFirstHeader(HTTP_HEADER_CONTENT_TYPE).getValue();
if (StringUtil.isNotEmpty(contentTypeStr)) {
ContentType contentType = ContentType.parse(contentTypeStr);
charset = contentType.getCharset();
}
}
catch (Exception ignore) {
}
return EntityUtils.toString(response.getEntity(), charset != null ? charset : DEFAULT_CHARSET);
}
/**
* With no param
* @param ip
* @param port
* @param api
* @return
*/
private CompletableFuture<String> executeCommand(String ip, int port, String api, boolean useHttpPost) {
return executeCommand(ip, port, api, null, useHttpPost);
}
/**
* No app specified, force to GET
* @param ip
* @param port
* @param api
* @param params
* @return
*/
private CompletableFuture<String> executeCommand(String ip, int port, String api, Map<String, String> params,
boolean useHttpPost) {
return executeCommand(null, ip, port, api, params, useHttpPost);
}
/**
* Prefer to execute request using POST
* @param app
* @param ip
* @param port
* @param api
* @param params
* @return
*/
private CompletableFuture<String> executeCommand(String app, String ip, int port, String api,
Map<String, String> params, boolean useHttpPost) {
CompletableFuture<String> future = new CompletableFuture<>();
if (StringUtil.isBlank(ip) || StringUtil.isBlank(api)) {
future.completeExceptionally(new IllegalArgumentException("Bad URL or command name"));
return future;
}
StringBuilder urlBuilder = new StringBuilder();
urlBuilder.append("http://");
urlBuilder.append(ip).append(':').append(port).append('/').append(api);
if (params == null) {
params = Collections.emptyMap();
}
if (!useHttpPost || !isSupportPost(app, ip, port)) {
// Using GET in older versions, append parameters after url
if (!params.isEmpty()) {
if (urlBuilder.indexOf("?") == -1) {
urlBuilder.append('?');
}
else {
urlBuilder.append('&');
}
urlBuilder.append(queryString(params));
}
return executeCommand(new HttpGet(urlBuilder.toString()));
}
else {
// Using POST
return executeCommand(
postRequest(urlBuilder.toString(), params, isSupportEnhancedContentType(app, ip, port)));
}
}
private CompletableFuture<String> executeCommand(HttpUriRequest request) {
CompletableFuture<String> future = new CompletableFuture<>();
httpClient.execute(request, new FutureCallback<HttpResponse>() {
@Override
public void completed(final HttpResponse response) {
int statusCode = response.getStatusLine().getStatusCode();
try {
String value = getBody(response);
if (isSuccess(statusCode)) {
future.complete(value);
}
else {
if (isCommandNotFound(statusCode, value)) {
future.completeExceptionally(new CommandNotFoundException(request.getURI().getPath()));
}
else {
future.completeExceptionally(new CommandFailedException(value));
}
}
}
catch (Exception ex) {
future.completeExceptionally(ex);
logger.error("HTTP request failed: {}", request.getURI().toString(), ex);
}
}
@Override
public void failed(final Exception ex) {
future.completeExceptionally(ex);
logger.error("HTTP request failed: {}", request.getURI().toString(), ex);
}
@Override
public void cancelled() {
future.complete(null);
}
});
return future;
}
public void close() throws Exception {
httpClient.close();
}
@Nullable
private <T> CompletableFuture<List<T>> fetchItemsAsync(String ip, int port, String api, String type,
Class<T> ruleType) {
AssertUtil.notEmpty(ip, "Bad machine IP");
AssertUtil.isTrue(port > 0, "Bad machine port");
Map<String, String> params = null;
if (StringUtil.isNotEmpty(type)) {
params = new HashMap<>(1);
params.put("type", type);
}
return executeCommand(ip, port, api, params, false).thenApply(json -> JSON.parseArray(json, ruleType));
}
@Nullable
private <T> List<T> fetchItems(String ip, int port, String api, String type, Class<T> ruleType) {
try {
AssertUtil.notEmpty(ip, "Bad machine IP");
AssertUtil.isTrue(port > 0, "Bad machine port");
Map<String, String> params = null;
if (StringUtil.isNotEmpty(type)) {
params = new HashMap<>(1);
params.put("type", type);
}
return fetchItemsAsync(ip, port, api, type, ruleType).get();
}
catch (InterruptedException | ExecutionException e) {
logger.error("Error when fetching items from api: {} -> {}", api, type, e);
return null;
}
catch (Exception e) {
logger.error("Error when fetching items: {} -> {}", api, type, e);
return null;
}
}
private <T extends Rule> List<T> fetchRules(String ip, int port, String type, Class<T> ruleType) {
return fetchItems(ip, port, GET_RULES_PATH, type, ruleType);
}
private boolean setRules(String app, String ip, int port, String type, List<? extends RuleEntity> entities) {
if (entities == null) {
return true;
}
try {
AssertUtil.notEmpty(app, "Bad app name");
AssertUtil.notEmpty(ip, "Bad machine IP");
AssertUtil.isTrue(port > 0, "Bad machine port");
String data = JSON.toJSONString(entities.stream().map(r -> r.toRule()).collect(Collectors.toList()));
Map<String, String> params = new HashMap<>(2);
params.put("type", type);
params.put("data", data);
String result = executeCommand(app, ip, port, SET_RULES_PATH, params, true).get();
logger.info("setRules result: {}, type={}", result, type);
return true;
}
catch (InterruptedException e) {
logger.warn("setRules API failed: {}", type, e);
return false;
}
catch (ExecutionException e) {
logger.warn("setRules API failed: {}", type, e.getCause());
return false;
}
catch (Exception e) {
logger.error("setRules API failed, type={}", type, e);
return false;
}
}
private CompletableFuture<Void> setRulesAsync(String app, String ip, int port, String type,
List<? extends RuleEntity> entities) {
try {
AssertUtil.notNull(entities, "rules cannot be null");
AssertUtil.notEmpty(app, "Bad app name");
AssertUtil.notEmpty(ip, "Bad machine IP");
AssertUtil.isTrue(port > 0, "Bad machine port");
String data = JSON.toJSONString(entities.stream().map(r -> r.toRule()).collect(Collectors.toList()));
Map<String, String> params = new HashMap<>(2);
params.put("type", type);
params.put("data", data);
return executeCommand(app, ip, port, SET_RULES_PATH, params, true).thenCompose(r -> {
if ("success".equalsIgnoreCase(r.trim())) {
return CompletableFuture.completedFuture(null);
}
return AsyncUtils.newFailedFuture(new CommandFailedException(r));
});
}
catch (Exception e) {
logger.error("setRulesAsync API failed, type={}", type, e);
return AsyncUtils.newFailedFuture(e);
}
}
public List<NodeVo> fetchResourceOfMachine(String ip, int port, String type) {
return fetchItems(ip, port, RESOURCE_URL_PATH, type, NodeVo.class);
}
/**
* Fetch cluster node.
* @param ip ip to fetch
* @param port port of the ip
* @param includeZero whether zero value should in the result list.
* @return
*/
public List<NodeVo> fetchClusterNodeOfMachine(String ip, int port, boolean includeZero) {
String type = "notZero";
if (includeZero) {
type = "zero";
}
return fetchItems(ip, port, CLUSTER_NODE_PATH, type, NodeVo.class);
}
public List<FlowRuleEntity> fetchFlowRuleOfMachine(String app, String ip, int port) {
List<FlowRule> rules = fetchRules(ip, port, FLOW_RULE_TYPE, FlowRule.class);
if (rules != null) {
return rules.stream().map(rule -> FlowRuleEntity.fromFlowRule(app, ip, port, rule))
.collect(Collectors.toList());
}
else {
return null;
}
}
public List<DegradeRuleEntity> fetchDegradeRuleOfMachine(String app, String ip, int port) {
List<DegradeRule> rules = fetchRules(ip, port, DEGRADE_RULE_TYPE, DegradeRule.class);
if (rules != null) {
return rules.stream().map(rule -> DegradeRuleEntity.fromDegradeRule(app, ip, port, rule))
.collect(Collectors.toList());
}
else {
return null;
}
}
public List<SystemRuleEntity> fetchSystemRuleOfMachine(String app, String ip, int port) {
List<SystemRule> rules = fetchRules(ip, port, SYSTEM_RULE_TYPE, SystemRule.class);
if (rules != null) {
return rules.stream().map(rule -> SystemRuleEntity.fromSystemRule(app, ip, port, rule))
.collect(Collectors.toList());
}
else {
return null;
}
}
/**
* Fetch all parameter flow rules from provided machine.
* @param app application name
* @param ip machine client IP
* @param port machine client port
* @return all retrieved parameter flow rules
* @since 0.2.1
*/
public CompletableFuture<List<ParamFlowRuleEntity>> fetchParamFlowRulesOfMachine(String app, String ip, int port) {
try {
AssertUtil.notEmpty(app, "Bad app name");
AssertUtil.notEmpty(ip, "Bad machine IP");
AssertUtil.isTrue(port > 0, "Bad machine port");
return fetchItemsAsync(ip, port, GET_PARAM_RULE_PATH, null, ParamFlowRule.class)
.thenApply(rules -> rules.stream().map(e -> ParamFlowRuleEntity.fromParamFlowRule(app, ip, port, e))
.collect(Collectors.toList()));
}
catch (Exception e) {
logger.error("Error when fetching parameter flow rules", e);
return AsyncUtils.newFailedFuture(e);
}
}
/**
* Fetch all authority rules from provided machine.
* @param app application name
* @param ip machine client IP
* @param port machine client port
* @return all retrieved authority rules
* @since 0.2.1
*/
public List<AuthorityRuleEntity> fetchAuthorityRulesOfMachine(String app, String ip, int port) {
AssertUtil.notEmpty(app, "Bad app name");
AssertUtil.notEmpty(ip, "Bad machine IP");
AssertUtil.isTrue(port > 0, "Bad machine port");
Map<String, String> params = new HashMap<>(1);
params.put("type", AUTHORITY_TYPE);
List<AuthorityRule> rules = fetchRules(ip, port, AUTHORITY_TYPE, AuthorityRule.class);
return Optional.ofNullable(rules).map(r -> r.stream()
.map(e -> AuthorityRuleEntity.fromAuthorityRule(app, ip, port, e)).collect(Collectors.toList()))
.orElse(null);
}
/**
* set rules of the machine. rules == null will return immediately; rules.isEmpty()
* means setting the rules to empty.
* @param app
* @param ip
* @param port
* @param rules
* @return whether successfully set the rules.
*/
public boolean setFlowRuleOfMachine(String app, String ip, int port, List<FlowRuleEntity> rules) {
return setRules(app, ip, port, FLOW_RULE_TYPE, rules);
}
public CompletableFuture<Void> setFlowRuleOfMachineAsync(String app, String ip, int port,
List<FlowRuleEntity> rules) {
return setRulesAsync(app, ip, port, FLOW_RULE_TYPE, rules);
}
/**
* set rules of the machine. rules == null will return immediately; rules.isEmpty()
* means setting the rules to empty.
* @param app
* @param ip
* @param port
* @param rules
* @return whether successfully set the rules.
*/
public boolean setDegradeRuleOfMachine(String app, String ip, int port, List<DegradeRuleEntity> rules) {
return setRules(app, ip, port, DEGRADE_RULE_TYPE, rules);
}
/**
* set rules of the machine. rules == null will return immediately; rules.isEmpty()
* means setting the rules to empty.
* @param app
* @param ip
* @param port
* @param rules
* @return whether successfully set the rules.
*/
public boolean setSystemRuleOfMachine(String app, String ip, int port, List<SystemRuleEntity> rules) {
return setRules(app, ip, port, SYSTEM_RULE_TYPE, rules);
}
public boolean setAuthorityRuleOfMachine(String app, String ip, int port, List<AuthorityRuleEntity> rules) {
return setRules(app, ip, port, AUTHORITY_TYPE, rules);
}
public CompletableFuture<Void> setParamFlowRuleOfMachine(String app, String ip, int port,
List<ParamFlowRuleEntity> rules) {
if (rules == null) {
return CompletableFuture.completedFuture(null);
}
if (StringUtil.isBlank(ip) || port <= 0) {
return AsyncUtils.newFailedFuture(new IllegalArgumentException("Invalid parameter"));
}
try {
String data = JSON
.toJSONString(rules.stream().map(ParamFlowRuleEntity::getRule).collect(Collectors.toList()));
Map<String, String> params = new HashMap<>(1);
params.put("data", data);
return executeCommand(app, ip, port, SET_PARAM_RULE_PATH, params, true).thenCompose(e -> {
if (CommandConstants.MSG_SUCCESS.equals(e)) {
return CompletableFuture.completedFuture(null);
}
else {
logger.warn("Push parameter flow rules to client failed: " + e);
return AsyncUtils.newFailedFuture(new RuntimeException(e));
}
});
}
catch (Exception ex) {
logger.warn("Error when setting parameter flow rule", ex);
return AsyncUtils.newFailedFuture(ex);
}
}
// Cluster related
public CompletableFuture<ClusterStateSimpleEntity> fetchClusterMode(String ip, int port) {
if (StringUtil.isBlank(ip) || port <= 0) {
return AsyncUtils.newFailedFuture(new IllegalArgumentException("Invalid parameter"));
}
try {
return executeCommand(ip, port, FETCH_CLUSTER_MODE_PATH, false)
.thenApply(r -> JSON.parseObject(r, ClusterStateSimpleEntity.class));
}
catch (Exception ex) {
logger.warn("Error when fetching cluster mode", ex);
return AsyncUtils.newFailedFuture(ex);
}
}
public CompletableFuture<Void> modifyClusterMode(String ip, int port, int mode) {
if (StringUtil.isBlank(ip) || port <= 0) {
return AsyncUtils.newFailedFuture(new IllegalArgumentException("Invalid parameter"));
}
try {
Map<String, String> params = new HashMap<>(1);
params.put("mode", String.valueOf(mode));
return executeCommand(ip, port, MODIFY_CLUSTER_MODE_PATH, params, false).thenCompose(e -> {
if (CommandConstants.MSG_SUCCESS.equals(e)) {
return CompletableFuture.completedFuture(null);
}
else {
logger.warn("Error when modifying cluster mode: " + e);
return AsyncUtils.newFailedFuture(new RuntimeException(e));
}
});
}
catch (Exception ex) {
logger.warn("Error when modifying cluster mode", ex);
return AsyncUtils.newFailedFuture(ex);
}
}
public CompletableFuture<ClusterClientInfoVO> fetchClusterClientInfoAndConfig(String ip, int port) {
if (StringUtil.isBlank(ip) || port <= 0) {
return AsyncUtils.newFailedFuture(new IllegalArgumentException("Invalid parameter"));
}
try {
return executeCommand(ip, port, FETCH_CLUSTER_CLIENT_CONFIG_PATH, false)
.thenApply(r -> JSON.parseObject(r, ClusterClientInfoVO.class));
}
catch (Exception ex) {
logger.warn("Error when fetching cluster client config", ex);
return AsyncUtils.newFailedFuture(ex);
}
}
public CompletableFuture<Void> modifyClusterClientConfig(String app, String ip, int port,
ClusterClientConfig config) {
if (StringUtil.isBlank(ip) || port <= 0) {
return AsyncUtils.newFailedFuture(new IllegalArgumentException("Invalid parameter"));
}
try {
Map<String, String> params = new HashMap<>(1);
params.put("data", JSON.toJSONString(config));
return executeCommand(app, ip, port, MODIFY_CLUSTER_CLIENT_CONFIG_PATH, params, true).thenCompose(e -> {
if (CommandConstants.MSG_SUCCESS.equals(e)) {
return CompletableFuture.completedFuture(null);
}
else {
logger.warn("Error when modifying cluster client config: " + e);
return AsyncUtils.newFailedFuture(new RuntimeException(e));
}
});
}
catch (Exception ex) {
logger.warn("Error when modifying cluster client config", ex);
return AsyncUtils.newFailedFuture(ex);
}
}
public CompletableFuture<Void> modifyClusterServerFlowConfig(String app, String ip, int port,
ServerFlowConfig config) {
if (StringUtil.isBlank(ip) || port <= 0) {
return AsyncUtils.newFailedFuture(new IllegalArgumentException("Invalid parameter"));
}
try {
Map<String, String> params = new HashMap<>(1);
params.put("data", JSON.toJSONString(config));
return executeCommand(app, ip, port, MODIFY_CLUSTER_SERVER_FLOW_CONFIG_PATH, params, true)
.thenCompose(e -> {
if (CommandConstants.MSG_SUCCESS.equals(e)) {
return CompletableFuture.completedFuture(null);
}
else {
logger.warn("Error when modifying cluster server flow config: " + e);
return AsyncUtils.newFailedFuture(new RuntimeException(e));
}
});
}
catch (Exception ex) {
logger.warn("Error when modifying cluster server flow config", ex);
return AsyncUtils.newFailedFuture(ex);
}
}
public CompletableFuture<Void> modifyClusterServerTransportConfig(String app, String ip, int port,
ServerTransportConfig config) {
if (StringUtil.isBlank(ip) || port <= 0) {
return AsyncUtils.newFailedFuture(new IllegalArgumentException("Invalid parameter"));
}
try {
Map<String, String> params = new HashMap<>(2);
params.put("port", config.getPort().toString());
params.put("idleSeconds", config.getIdleSeconds().toString());
return executeCommand(app, ip, port, MODIFY_CLUSTER_SERVER_TRANSPORT_CONFIG_PATH, params, false)
.thenCompose(e -> {
if (CommandConstants.MSG_SUCCESS.equals(e)) {
return CompletableFuture.completedFuture(null);
}
else {
logger.warn("Error when modifying cluster server transport config: " + e);
return AsyncUtils.newFailedFuture(new RuntimeException(e));
}
});
}
catch (Exception ex) {
logger.warn("Error when modifying cluster server transport config", ex);
return AsyncUtils.newFailedFuture(ex);
}
}
public CompletableFuture<Void> modifyClusterServerNamespaceSet(String app, String ip, int port, Set<String> set) {
if (StringUtil.isBlank(ip) || port <= 0) {
return AsyncUtils.newFailedFuture(new IllegalArgumentException("Invalid parameter"));
}
try {
Map<String, String> params = new HashMap<>(1);
params.put("data", JSON.toJSONString(set));
return executeCommand(app, ip, port, MODIFY_CLUSTER_SERVER_NAMESPACE_SET_PATH, params, true)
.thenCompose(e -> {
if (CommandConstants.MSG_SUCCESS.equals(e)) {
return CompletableFuture.completedFuture(null);
}
else {
logger.warn("Error when modifying cluster server NamespaceSet", e);
return AsyncUtils.newFailedFuture(new RuntimeException(e));
}
});
}
catch (Exception ex) {
logger.warn("Error when modifying cluster server NamespaceSet", ex);
return AsyncUtils.newFailedFuture(ex);
}
}
public CompletableFuture<ClusterServerStateVO> fetchClusterServerBasicInfo(String ip, int port) {
if (StringUtil.isBlank(ip) || port <= 0) {
return AsyncUtils.newFailedFuture(new IllegalArgumentException("Invalid parameter"));
}
try {
return executeCommand(ip, port, FETCH_CLUSTER_SERVER_BASIC_INFO_PATH, false)
.thenApply(r -> JSON.parseObject(r, ClusterServerStateVO.class));
}
catch (Exception ex) {
logger.warn("Error when fetching cluster sever all config and basic info", ex);
return AsyncUtils.newFailedFuture(ex);
}
}
public CompletableFuture<List<ApiDefinitionEntity>> fetchApis(String app, String ip, int port) {
if (StringUtil.isBlank(ip) || port <= 0) {
return AsyncUtils.newFailedFuture(new IllegalArgumentException("Invalid parameter"));
}
try {
return executeCommand(ip, port, FETCH_GATEWAY_API_PATH, false).thenApply(r -> {
List<ApiDefinitionEntity> entities = JSON.parseArray(r, ApiDefinitionEntity.class);
if (entities != null) {
for (ApiDefinitionEntity entity : entities) {
entity.setApp(app);
entity.setIp(ip);
entity.setPort(port);
}
}
return entities;
});
}
catch (Exception ex) {
logger.warn("Error when fetching gateway apis", ex);
return AsyncUtils.newFailedFuture(ex);
}
}
public boolean modifyApis(String app, String ip, int port, List<ApiDefinitionEntity> apis) {
if (apis == null) {
return true;
}
try {
AssertUtil.notEmpty(app, "Bad app name");
AssertUtil.notEmpty(ip, "Bad machine IP");
AssertUtil.isTrue(port > 0, "Bad machine port");
String data = JSON.toJSONString(apis.stream().map(r -> r.toApiDefinition()).collect(Collectors.toList()));
Map<String, String> params = new HashMap<>(2);
params.put("data", data);
String result = executeCommand(app, ip, port, MODIFY_GATEWAY_API_PATH, params, true).get();
logger.info("Modify gateway apis: {}", result);
return true;
}
catch (Exception e) {
logger.warn("Error when modifying gateway apis", e);
return false;
}
}
public CompletableFuture<List<GatewayFlowRuleEntity>> fetchGatewayFlowRules(String app, String ip, int port) {
if (StringUtil.isBlank(ip) || port <= 0) {
return AsyncUtils.newFailedFuture(new IllegalArgumentException("Invalid parameter"));
}
try {
return executeCommand(ip, port, FETCH_GATEWAY_FLOW_RULE_PATH, false).thenApply(r -> {
List<GatewayFlowRule> gatewayFlowRules = JSON.parseArray(r, GatewayFlowRule.class);
List<GatewayFlowRuleEntity> entities = gatewayFlowRules.stream()
.map(rule -> GatewayFlowRuleEntity.fromGatewayFlowRule(app, ip, port, rule))
.collect(Collectors.toList());
return entities;
});
}
catch (Exception ex) {
logger.warn("Error when fetching gateway flow rules", ex);
return AsyncUtils.newFailedFuture(ex);
}
}
public boolean modifyGatewayFlowRules(String app, String ip, int port, List<GatewayFlowRuleEntity> rules) {
if (rules == null) {
return true;
}
try {
AssertUtil.notEmpty(app, "Bad app name");
AssertUtil.notEmpty(ip, "Bad machine IP");
AssertUtil.isTrue(port > 0, "Bad machine port");
String data = JSON
.toJSONString(rules.stream().map(r -> r.toGatewayFlowRule()).collect(Collectors.toList()));
Map<String, String> params = new HashMap<>(2);
params.put("data", data);
String result = executeCommand(app, ip, port, MODIFY_GATEWAY_FLOW_RULE_PATH, params, true).get();
logger.info("Modify gateway flow rules: {}", result);
return true;
}
catch (Exception e) {
logger.warn("Error when modifying gateway apis", e);
return false;
}
}
}

View File

@ -1,59 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 com.alibaba.csp.sentinel.dashboard.config;
import com.alibaba.csp.sentinel.dashboard.auth.*;
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 javax.servlet.http.HttpServletRequest;
@Configuration
@EnableConfigurationProperties(AuthProperties.class)
public class AuthConfiguration {
private final AuthProperties authProperties;
public AuthConfiguration(AuthProperties authProperties) {
this.authProperties = authProperties;
}
@Bean
@ConditionalOnMissingBean
public AuthService<HttpServletRequest> httpServletRequestAuthService() {
if (this.authProperties.isEnabled()) {
return new SimpleWebAuthServiceImpl();
}
return new FakeAuthServiceImpl();
}
@Bean
@ConditionalOnMissingBean
public LoginAuthenticationFilter loginAuthenticationFilter(
AuthService<HttpServletRequest> httpServletRequestAuthService) {
return new DefaultLoginAuthenticationFilter(httpServletRequestAuthService);
}
@Bean
@ConditionalOnMissingBean
public AuthorizationInterceptor authorizationInterceptor(
AuthService<HttpServletRequest> httpServletRequestAuthService) {
return new DefaultAuthorizationInterceptor(httpServletRequestAuthService);
}
}

View File

@ -1,33 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 com.alibaba.csp.sentinel.dashboard.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "auth")
public class AuthProperties {
private boolean enabled = true;
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}

View File

@ -1,149 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 com.alibaba.csp.sentinel.dashboard.config;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.springframework.lang.NonNull;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* <p>
* Dashboard local config support.
* </p>
* <p>
* Dashboard supports configuration loading by several ways by order:<br>
* 1. System.properties<br>
* 2. Env
* </p>
*
* @author jason
* @since 1.5.0
*/
public class DashboardConfig {
public static final int DEFAULT_MACHINE_HEALTHY_TIMEOUT_MS = 60_000;
/**
* Login username
*/
public static final String CONFIG_AUTH_USERNAME = "sentinel.dashboard.auth.username";
/**
* Login password
*/
public static final String CONFIG_AUTH_PASSWORD = "sentinel.dashboard.auth.password";
/**
* Hide application name in sidebar when it has no healthy machines after specific
* period in millisecond.
*/
public static final String CONFIG_HIDE_APP_NO_MACHINE_MILLIS = "sentinel.dashboard.app.hideAppNoMachineMillis";
/**
* Remove application when it has no healthy machines after specific period in
* millisecond.
*/
public static final String CONFIG_REMOVE_APP_NO_MACHINE_MILLIS = "sentinel.dashboard.removeAppNoMachineMillis";
/**
* Timeout
*/
public static final String CONFIG_UNHEALTHY_MACHINE_MILLIS = "sentinel.dashboard.unhealthyMachineMillis";
/**
* Auto remove unhealthy machine after specific period in millisecond.
*/
public static final String CONFIG_AUTO_REMOVE_MACHINE_MILLIS = "sentinel.dashboard.autoRemoveMachineMillis";
private static final ConcurrentMap<String, Object> cacheMap = new ConcurrentHashMap<>();
@NonNull
private static String getConfig(String name) {
// env
String val = System.getenv(name);
if (StringUtils.isNotEmpty(val)) {
return val;
}
// properties
val = System.getProperty(name);
if (StringUtils.isNotEmpty(val)) {
return val;
}
return "";
}
protected static String getConfigStr(String name) {
if (cacheMap.containsKey(name)) {
return (String) cacheMap.get(name);
}
String val = getConfig(name);
if (StringUtils.isBlank(val)) {
return null;
}
cacheMap.put(name, val);
return val;
}
protected static int getConfigInt(String name, int defaultVal, int minVal) {
if (cacheMap.containsKey(name)) {
return (int) cacheMap.get(name);
}
int val = NumberUtils.toInt(getConfig(name));
if (val == 0) {
val = defaultVal;
}
else if (val < minVal) {
val = minVal;
}
cacheMap.put(name, val);
return val;
}
public static String getAuthUsername() {
return getConfigStr(CONFIG_AUTH_USERNAME);
}
public static String getAuthPassword() {
return getConfigStr(CONFIG_AUTH_PASSWORD);
}
public static int getHideAppNoMachineMillis() {
return getConfigInt(CONFIG_HIDE_APP_NO_MACHINE_MILLIS, 0, 60000);
}
public static int getRemoveAppNoMachineMillis() {
return getConfigInt(CONFIG_REMOVE_APP_NO_MACHINE_MILLIS, 0, 120000);
}
public static int getAutoRemoveMachineMillis() {
return getConfigInt(CONFIG_AUTO_REMOVE_MACHINE_MILLIS, 0, 300000);
}
public static int getUnhealthyMachineMillis() {
return getConfigInt(CONFIG_UNHEALTHY_MACHINE_MILLIS, DEFAULT_MACHINE_HEALTHY_TIMEOUT_MS, 30000);
}
public static void clearCache() {
cacheMap.clear();
}
}

View File

@ -1,115 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 com.alibaba.csp.sentinel.dashboard.config;
import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager;
import com.alibaba.csp.sentinel.dashboard.auth.AuthorizationInterceptor;
import com.alibaba.csp.sentinel.dashboard.auth.LoginAuthenticationFilter;
import com.alibaba.csp.sentinel.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.PostConstruct;
import javax.servlet.Filter;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* @author leyou
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
private final Logger logger = LoggerFactory.getLogger(WebConfig.class);
@Autowired
private LoginAuthenticationFilter loginAuthenticationFilter;
@Autowired
private AuthorizationInterceptor authorizationInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authorizationInterceptor).addPathPatterns("/**");
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("classpath:/resources/");
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("forward:/index.htm");
}
/**
* Add {@link CommonFilter} to the server, this is the simplest way to use Sentinel
* for Web application.
*/
@Bean
public FilterRegistrationBean sentinelFilterRegistration() {
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
registration.setFilter(new CommonFilter());
registration.addUrlPatterns("/*");
registration.setName("sentinelFilter");
registration.setOrder(1);
// If this is enabled, the entrance of all Web URL resources will be unified as a
// single context name.
// In most scenarios that's enough, and it could reduce the memory footprint.
registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "true");
logger.info("Sentinel servlet CommonFilter registered");
return registration;
}
@PostConstruct
public void doInit() {
Set<String> suffixSet = new HashSet<>(Arrays.asList(".js", ".css", ".html", ".ico", ".txt", ".woff", ".woff2"));
// Example: register a UrlCleaner to exclude URLs of common static resources.
WebCallbackManager.setUrlCleaner(url -> {
if (StringUtil.isEmpty(url)) {
return url;
}
if (suffixSet.stream().anyMatch(url::endsWith)) {
return null;
}
return url;
});
}
@Bean
public FilterRegistrationBean authenticationFilterRegistration() {
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
registration.setFilter(loginAuthenticationFilter);
registration.addUrlPatterns("/*");
registration.setName("authenticationFilter");
registration.setOrder(0);
return registration;
}
}

View File

@ -1,81 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 com.alibaba.csp.sentinel.dashboard.controller;
import com.alibaba.csp.sentinel.dashboard.discovery.AppInfo;
import com.alibaba.csp.sentinel.dashboard.discovery.AppManagement;
import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo;
import com.alibaba.csp.sentinel.dashboard.domain.Result;
import com.alibaba.csp.sentinel.dashboard.domain.vo.MachineInfoVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* @author Carpenter Lee
*/
@RestController
@RequestMapping(value = "/app")
public class AppController {
@Autowired
private AppManagement appManagement;
@GetMapping("/names.json")
public Result<List<String>> queryApps(HttpServletRequest request) {
return Result.ofSuccess(appManagement.getAppNames());
}
@GetMapping("/briefinfos.json")
public Result<List<AppInfo>> queryAppInfos(HttpServletRequest request) {
List<AppInfo> list = new ArrayList<>(appManagement.getBriefApps());
Collections.sort(list, Comparator.comparing(AppInfo::getApp));
return Result.ofSuccess(list);
}
@GetMapping(value = "/{app}/machines.json")
public Result<List<MachineInfoVo>> getMachinesByApp(@PathVariable("app") String app) {
AppInfo appInfo = appManagement.getDetailApp(app);
if (appInfo == null) {
return Result.ofSuccess(null);
}
List<MachineInfo> list = new ArrayList<>(appInfo.getMachines());
Collections.sort(list, Comparator.comparing(MachineInfo::getApp).thenComparing(MachineInfo::getIp)
.thenComparingInt(MachineInfo::getPort));
return Result.ofSuccess(MachineInfoVo.fromMachineInfoList(list));
}
@RequestMapping(value = "/{app}/machine/remove.json")
public Result<String> removeMachineById(@PathVariable("app") String app, @RequestParam(name = "ip") String ip,
@RequestParam(name = "port") int port) {
AppInfo appInfo = appManagement.getDetailApp(app);
if (appInfo == null) {
return Result.ofSuccess(null);
}
if (appManagement.removeMachine(app, ip, port)) {
return Result.ofSuccessMsg("success");
}
else {
return Result.ofFail(1, "remove failed");
}
}
}

View File

@ -1,94 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 com.alibaba.csp.sentinel.dashboard.controller;
import com.alibaba.csp.sentinel.dashboard.auth.AuthService;
import com.alibaba.csp.sentinel.dashboard.auth.SimpleWebAuthServiceImpl;
import com.alibaba.csp.sentinel.dashboard.config.DashboardConfig;
import com.alibaba.csp.sentinel.dashboard.domain.Result;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
/**
* @author cdfive
* @since 1.6.0
*/
@RestController
@RequestMapping("/auth")
public class AuthController {
private static final Logger LOGGER = LoggerFactory.getLogger(AuthController.class);
@Value("${auth.username:sentinel}")
private String authUsername;
@Value("${auth.password:sentinel}")
private String authPassword;
@Autowired
private AuthService<HttpServletRequest> authService;
@PostMapping("/login")
public Result<AuthService.AuthUser> login(HttpServletRequest request, String username, String password) {
if (StringUtils.isNotBlank(DashboardConfig.getAuthUsername())) {
authUsername = DashboardConfig.getAuthUsername();
}
if (StringUtils.isNotBlank(DashboardConfig.getAuthPassword())) {
authPassword = DashboardConfig.getAuthPassword();
}
/*
* If auth.username or auth.password is blank(set in application.properties or VM
* arguments), auth will pass, as the front side validate the input which can't be
* blank, so user can input any username or password(both are not blank) to login
* in that case.
*/
if (StringUtils.isNotBlank(authUsername) && !authUsername.equals(username)
|| StringUtils.isNotBlank(authPassword) && !authPassword.equals(password)) {
LOGGER.error("Login failed: Invalid username or password, username=" + username);
return Result.ofFail(-1, "Invalid username or password");
}
AuthService.AuthUser authUser = new SimpleWebAuthServiceImpl.SimpleWebAuthUserImpl(username);
request.getSession().setAttribute(SimpleWebAuthServiceImpl.WEB_SESSION_KEY, authUser);
return Result.ofSuccess(authUser);
}
@PostMapping(value = "/logout")
public Result<?> logout(HttpServletRequest request) {
request.getSession().invalidate();
return Result.ofSuccess(null);
}
@PostMapping(value = "/check")
public Result<?> check(HttpServletRequest request) {
AuthService.AuthUser authUser = authService.getAuthUser(request);
if (authUser == null) {
return Result.ofFail(-1, "Not logged in");
}
return Result.ofSuccess(authUser);
}
}

View File

@ -1,186 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 com.alibaba.csp.sentinel.dashboard.controller;
import com.alibaba.csp.sentinel.dashboard.auth.AuthAction;
import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegeType;
import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.AuthorityRuleEntity;
import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo;
import com.alibaba.csp.sentinel.dashboard.domain.Result;
import com.alibaba.csp.sentinel.dashboard.repository.rule.RuleRepository;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.List;
/**
* @author Eric Zhao
* @since 0.2.1
*/
@RestController
@RequestMapping(value = "/authority")
public class AuthorityRuleController {
private final Logger logger = LoggerFactory.getLogger(AuthorityRuleController.class);
@Autowired
private SentinelApiClient sentinelApiClient;
@Autowired
private RuleRepository<AuthorityRuleEntity, Long> repository;
@GetMapping("/rules")
@AuthAction(PrivilegeType.READ_RULE)
public Result<List<AuthorityRuleEntity>> apiQueryAllRulesForMachine(@RequestParam String app,
@RequestParam String ip, @RequestParam Integer port) {
if (StringUtil.isEmpty(app)) {
return Result.ofFail(-1, "app cannot be null or empty");
}
if (StringUtil.isEmpty(ip)) {
return Result.ofFail(-1, "ip cannot be null or empty");
}
if (port == null || port <= 0) {
return Result.ofFail(-1, "Invalid parameter: port");
}
try {
List<AuthorityRuleEntity> rules = sentinelApiClient.fetchAuthorityRulesOfMachine(app, ip, port);
rules = repository.saveAll(rules);
return Result.ofSuccess(rules);
}
catch (Throwable throwable) {
logger.error("Error when querying authority rules", throwable);
return Result.ofFail(-1, throwable.getMessage());
}
}
private <R> Result<R> checkEntityInternal(AuthorityRuleEntity entity) {
if (entity == null) {
return Result.ofFail(-1, "bad rule body");
}
if (StringUtil.isBlank(entity.getApp())) {
return Result.ofFail(-1, "app can't be null or empty");
}
if (StringUtil.isBlank(entity.getIp())) {
return Result.ofFail(-1, "ip can't be null or empty");
}
if (entity.getPort() == null || entity.getPort() <= 0) {
return Result.ofFail(-1, "port can't be null");
}
if (entity.getRule() == null) {
return Result.ofFail(-1, "rule can't be null");
}
if (StringUtil.isBlank(entity.getResource())) {
return Result.ofFail(-1, "resource name cannot be null or empty");
}
if (StringUtil.isBlank(entity.getLimitApp())) {
return Result.ofFail(-1, "limitApp should be valid");
}
if (entity.getStrategy() != RuleConstant.AUTHORITY_WHITE
&& entity.getStrategy() != RuleConstant.AUTHORITY_BLACK) {
return Result.ofFail(-1, "Unknown strategy (must be blacklist or whitelist)");
}
return null;
}
@PostMapping("/rule")
@AuthAction(PrivilegeType.WRITE_RULE)
public Result<AuthorityRuleEntity> apiAddAuthorityRule(@RequestBody AuthorityRuleEntity entity) {
Result<AuthorityRuleEntity> checkResult = checkEntityInternal(entity);
if (checkResult != null) {
return checkResult;
}
entity.setId(null);
Date date = new Date();
entity.setGmtCreate(date);
entity.setGmtModified(date);
try {
entity = repository.save(entity);
}
catch (Throwable throwable) {
logger.error("Failed to add authority rule", throwable);
return Result.ofThrowable(-1, throwable);
}
if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) {
logger.info("Publish authority rules failed after rule add");
}
return Result.ofSuccess(entity);
}
@PutMapping("/rule/{id}")
@AuthAction(PrivilegeType.WRITE_RULE)
public Result<AuthorityRuleEntity> apiUpdateParamFlowRule(@PathVariable("id") Long id,
@RequestBody AuthorityRuleEntity entity) {
if (id == null || id <= 0) {
return Result.ofFail(-1, "Invalid id");
}
Result<AuthorityRuleEntity> checkResult = checkEntityInternal(entity);
if (checkResult != null) {
return checkResult;
}
entity.setId(id);
Date date = new Date();
entity.setGmtCreate(null);
entity.setGmtModified(date);
try {
entity = repository.save(entity);
if (entity == null) {
return Result.ofFail(-1, "Failed to save authority rule");
}
}
catch (Throwable throwable) {
logger.error("Failed to save authority rule", throwable);
return Result.ofThrowable(-1, throwable);
}
if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) {
logger.info("Publish authority rules failed after rule update");
}
return Result.ofSuccess(entity);
}
@DeleteMapping("/rule/{id}")
@AuthAction(PrivilegeType.DELETE_RULE)
public Result<Long> apiDeleteRule(@PathVariable("id") Long id) {
if (id == null) {
return Result.ofFail(-1, "id cannot be null");
}
AuthorityRuleEntity oldEntity = repository.findById(id);
if (oldEntity == null) {
return Result.ofSuccess(null);
}
try {
repository.delete(id);
}
catch (Exception e) {
return Result.ofFail(-1, e.getMessage());
}
if (!publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort())) {
logger.error("Publish authority rules failed after rule delete");
}
return Result.ofSuccess(id);
}
private boolean publishRules(String app, String ip, Integer port) {
List<AuthorityRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
return sentinelApiClient.setAuthorityRuleOfMachine(app, ip, port, rules);
}
}

Some files were not shown because too many files have changed in this diff Show More