.*), /$\\{path}/$\\{path}/v3/api-docs', '6ef9265e4a4298c5f4fdb9fbbf846818', '2022-05-08 12:10:37', '2024-04-07 12:22:09', 'nacos', '0:0:0:0:0:0:0:1', '', '', '', '', '', 'yaml', '', '');
+INSERT INTO `config_info` (`id`, `data_id`, `group_id`, `content`, `md5`, `gmt_create`, `gmt_modified`, `src_user`, `src_ip`, `app_name`, `tenant_id`, `c_desc`, `c_use`, `effect`, `type`, `c_schema`, `encrypted_data_key`) VALUES (5, 'pig-monitor-dev.yml', 'DEFAULT_GROUP', 'spring:\n autoconfigure:\n exclude: com.pig4cloud.pig.common.core.config.JacksonConfiguration\n # 安全配置\n security:\n user:\n name: ENC(8Hk2ILNJM8UTOuW/Xi75qg==) # pig\n password: ENC(o6cuPFfUevmTbkmBnE67Ow====) # pig\n', '650bdfa15f60f3faa84dfe6e6878b8cf', '2022-05-08 12:10:37', '2022-05-08 12:10:37', NULL, '127.0.0.1', '', '', NULL, NULL, NULL, 'yaml', NULL, '');
+INSERT INTO `config_info` (`id`, `data_id`, `group_id`, `content`, `md5`, `gmt_create`, `gmt_modified`, `src_user`, `src_ip`, `app_name`, `tenant_id`, `c_desc`, `c_use`, `effect`, `type`, `c_schema`, `encrypted_data_key`) VALUES (6, 'pig-upms-biz-dev.yml', 'DEFAULT_GROUP', '# 数据源\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?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true\n\n# 文件上传相关 支持阿里云、华为云、腾讯、minio\nfile:\n bucketName: s3demo \n local:\n enable: true\n base-path: /Users/lengleng/Downloads/img', '48f8db128aeb5debb331bae49ff37908', '2022-05-08 12:10:37', '2023-07-07 14:44:09', 'nacos', '0:0:0:0:0:0:0:1', '', '', '', '', '', 'yaml', '', '');
+INSERT INTO `config_info` (`id`, `data_id`, `group_id`, `content`, `md5`, `gmt_create`, `gmt_modified`, `src_user`, `src_ip`, `app_name`, `tenant_id`, `c_desc`, `c_use`, `effect`, `type`, `c_schema`, `encrypted_data_key`) VALUES (7, 'pig-quartz-dev.yml', 'DEFAULT_GROUP', 'spring:\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?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true\n', '8d9725a73216310178d2835de13c4ebf', '2023-07-02 12:24:33', '2024-04-18 22:36:12', 'nacos', '0:0:0:0:0:0:0:1', '', '', '', '', '', 'yaml', '', '');
COMMIT;
-- ----------------------------
diff --git a/db/pig_job.sql b/db/pig_job.sql
deleted file mode 100644
index 585c6e8bf1b3554de2f4d752bc3a7f20b1a93e32..0000000000000000000000000000000000000000
--- a/db/pig_job.sql
+++ /dev/null
@@ -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;
diff --git a/docker-compose.yml b/docker-compose.yml
index be4193263a711c9f496c142fc9e4faa3f257b1e8..1e774a0d8b3cbce7ed55c787ff7054d3a4a519ce 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -11,14 +11,18 @@ services:
image: pig-mysql
ports:
- 3306:3306
+ networks:
+ - spring_cloud_default
pig-redis:
- image: redis:7.0.0
+ image: registry.cn-hangzhou.aliyuncs.com/dockerhub_mirror/redis
ports:
- 6379:6379
restart: always
container_name: pig-redis
hostname: pig-redis
+ networks:
+ - spring_cloud_default
pig-register:
build:
@@ -29,6 +33,8 @@ services:
container_name: pig-register
hostname: pig-register
image: pig-register
+ networks:
+ - spring_cloud_default
pig-gateway:
build:
@@ -39,6 +45,8 @@ services:
container_name: pig-gateway
hostname: pig-gateway
image: pig-gateway
+ networks:
+ - spring_cloud_default
pig-auth:
build:
@@ -47,6 +55,8 @@ services:
container_name: pig-auth
hostname: pig-auth
image: pig-auth
+ networks:
+ - spring_cloud_default
pig-upms:
build:
@@ -55,6 +65,8 @@ services:
container_name: pig-upms
hostname: pig-upms
image: pig-upms
+ networks:
+ - spring_cloud_default
pig-monitor:
build:
@@ -65,15 +77,8 @@ services:
container_name: pig-monitor
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
+ networks:
+ - spring_cloud_default
pig-codegen:
build:
@@ -82,13 +87,19 @@ services:
container_name: pig-codegen
hostname: pig-codegen
image: pig-codegen
+ networks:
+ - spring_cloud_default
- pig-job:
+ pig-quartz:
build:
- context: ./pig-visual/pig-xxl-job-admin
+ context: ./pig-visual/pig-quartz
restart: always
- container_name: pig-job
- hostname: pig-job
- image: pig-job
- ports:
- - 5004:5004
+ image: pig-quartz
+ container_name: pig-quartz
+ networks:
+ - spring_cloud_default
+
+networks:
+ spring_cloud_default:
+ name: spring_cloud_default
+ driver: bridge
diff --git a/pig-auth/Dockerfile b/pig-auth/Dockerfile
index 0d630f03b2a27455ee9e5725bb793036e644444b..80098bcb9f006f9c7faf76f398796767fded3d15 100755
--- a/pig-auth/Dockerfile
+++ b/pig-auth/Dockerfile
@@ -1,6 +1,4 @@
-FROM moxm/java:1.8-full
-
-RUN mkdir -p /pig-auth
+FROM registry.cn-hangzhou.aliyuncs.com/dockerhub_mirror/java:1.8-full
WORKDIR /pig-auth
diff --git a/pig-auth/pom.xml b/pig-auth/pom.xml
index 1e5e2da47c9c7087d584f1b5064692ad4e8d1e1c..19eca575c3f8a45f081ca4453ed054fb39989025 100755
--- a/pig-auth/pom.xml
+++ b/pig-auth/pom.xml
@@ -21,7 +21,7 @@
com.pig4cloud
pig
- 3.6.4
+ ${revision}
pig-auth
@@ -73,19 +73,38 @@
com.pig4cloud
pig-common-log
+
+
+ io.springboot.plugin
+ captcha-core
+ ${captcha.version}
+
+
+
+ cn.hutool
+ hutool-crypto
+
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
- io.fabric8
- docker-maven-plugin
-
-
-
+
+
+ boot
+
+
+ cloud
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ io.fabric8
+ docker-maven-plugin
+
+
+
+
+
diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/PigAuthApplication.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/PigAuthApplication.java
index 1e36a8b9ca6300f5676eb6936b28e94f13996e38..3591081cc11781443e977bedaee26a531c5fefea 100755
--- a/pig-auth/src/main/java/com/pig4cloud/pig/auth/PigAuthApplication.java
+++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/PigAuthApplication.java
@@ -16,7 +16,6 @@
package com.pig4cloud.pig.auth;
-import com.pig4cloud.pig.common.feign.annotation.EnablePigFeignClients;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@@ -25,7 +24,6 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
* @author lengleng
* @date 2018年06月21日 认证授权中心
*/
-@EnablePigFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class PigAuthApplication {
diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/AuthorizationServerConfiguration.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/AuthorizationServerConfiguration.java
index a6e9105d567dcad462d5fdef34d94a1c30677a24..6220418c117f3a0d92234f490ee818b3040d1c99 100755
--- a/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/AuthorizationServerConfiguration.java
+++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/AuthorizationServerConfiguration.java
@@ -20,6 +20,8 @@ import com.pig4cloud.pig.auth.support.CustomeOAuth2AccessTokenGenerator;
import com.pig4cloud.pig.auth.support.core.CustomeOAuth2TokenCustomizer;
import com.pig4cloud.pig.auth.support.core.FormIdentityLoginConfigurer;
import com.pig4cloud.pig.auth.support.core.PigDaoAuthenticationProvider;
+import com.pig4cloud.pig.auth.support.filter.PasswordDecoderFilter;
+import com.pig4cloud.pig.auth.support.filter.ValidateCodeFilter;
import com.pig4cloud.pig.auth.support.handler.PigAuthenticationFailureEventHandler;
import com.pig4cloud.pig.auth.support.handler.PigAuthenticationSuccessEventHandler;
import com.pig4cloud.pig.auth.support.password.OAuth2ResourceOwnerPasswordAuthenticationConverter;
@@ -28,6 +30,7 @@ import com.pig4cloud.pig.auth.support.sms.OAuth2ResourceOwnerSmsAuthenticationCo
import com.pig4cloud.pig.auth.support.sms.OAuth2ResourceOwnerSmsAuthenticationProvider;
import com.pig4cloud.pig.common.core.constant.SecurityConstants;
import lombok.RequiredArgsConstructor;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
@@ -35,6 +38,7 @@ import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
+import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.oauth2.server.authorization.token.DelegatingOAuth2TokenGenerator;
@@ -44,14 +48,14 @@ import org.springframework.security.oauth2.server.authorization.web.authenticati
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationConverter;
-import org.springframework.security.web.util.matcher.RequestMatcher;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import java.util.Arrays;
/**
* @author lengleng
* @date 2022/5/27
- *
+ *
* 认证服务器配置
*/
@Configuration
@@ -60,28 +64,47 @@ public class AuthorizationServerConfiguration {
private final OAuth2AuthorizationService authorizationService;
+ private final PasswordDecoderFilter passwordDecoderFilter;
+
+ private final ValidateCodeFilter validateCodeFilter;
+
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
+ @ConditionalOnProperty(value = "security.micro", matchIfMissing = true)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
- OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = new OAuth2AuthorizationServerConfigurer();
- http.apply(authorizationServerConfigurer.tokenEndpoint((tokenEndpoint) -> {// 个性化认证授权端点
+ // OAuth 2.1 默认配置
+ // 缺省配置:authorizeRequests.anyRequest().authenticated()、
+ // csrf.ignoringRequestMatchers(endpointsMatcher) 等等
+ OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
+
+ // 使用 HttpSecurity 获取 OAuth 2.1 配置中的 OAuth2AuthorizationServerConfigurer 对象
+ OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = http
+ .getConfigurer(OAuth2AuthorizationServerConfigurer.class);
+
+ // 增加验证码过滤器
+ http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class);
+ // 增加密码解密过滤器
+ http.addFilterBefore(passwordDecoderFilter, UsernamePasswordAuthenticationFilter.class);
+
+ 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)));
-
- RequestMatcher endpointsMatcher = authorizationServerConfigurer.getEndpointsMatcher();
- DefaultSecurityFilterChain securityFilterChain = http.requestMatcher(endpointsMatcher)
- .authorizeRequests(authorizeRequests -> authorizeRequests.anyRequest().authenticated())
- .apply(authorizationServerConfigurer.authorizationService(authorizationService)// redis存储token的实现
- .authorizationServerSettings(AuthorizationServerSettings.builder()
- .issuer(SecurityConstants.PROJECT_LICENSE).build()))
- // 授权码登录的登录页个性化
- .and().apply(new FormIdentityLoginConfigurer()).and().build();
+ .authorizationEndpoint(authorizationEndpoint -> authorizationEndpoint// 授权码端点个性化confirm页面
+ .consentPage(SecurityConstants.CUSTOM_CONSENT_PAGE_URI));
+
+ DefaultSecurityFilterChain securityFilterChain = authorizationServerConfigurer
+ .authorizationService(authorizationService)// redis存储token的实现
+ .authorizationServerSettings(
+ AuthorizationServerSettings.builder().issuer(SecurityConstants.PROJECT_LICENSE).build())
+ // 授权码登录的登录页个性化
+ .and()
+ .apply(new FormIdentityLoginConfigurer())
+ .and()
+ .build();
// 注入自定义授权模式实现
addCustomOAuth2GrantAuthenticationProvider(http);
@@ -105,7 +128,8 @@ public class AuthorizationServerConfiguration {
* request -> xToken 注入请求转换器
* @return DelegatingAuthenticationConverter
*/
- private AuthenticationConverter accessTokenRequestConverter() {
+ @Bean
+ public AuthenticationConverter accessTokenRequestConverter() {
return new DelegatingAuthenticationConverter(Arrays.asList(
new OAuth2ResourceOwnerPasswordAuthenticationConverter(),
new OAuth2ResourceOwnerSmsAuthenticationConverter(), new OAuth2RefreshTokenAuthenticationConverter(),
@@ -116,10 +140,9 @@ public class AuthorizationServerConfiguration {
/**
* 注入授权模式实现提供方
- *
+ *
* 1. 密码模式
* 2. 短信登录
- *
*/
@SuppressWarnings("unchecked")
private void addCustomOAuth2GrantAuthenticationProvider(HttpSecurity http) {
diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/WebSecurityConfiguration.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/WebSecurityConfiguration.java
index 0ebc699d9a1821d14d1b01016b6e18c8ce9d481d..be513a647e9d6e5e5042a94e8864098f8d39ab89 100755
--- a/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/WebSecurityConfiguration.java
+++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/WebSecurityConfiguration.java
@@ -41,9 +41,15 @@ public class WebSecurityConfiguration {
*/
@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
- http.authorizeRequests(authorizeRequests -> authorizeRequests.antMatchers("/token/*").permitAll()// 开放自定义的部分端点
- .anyRequest().authenticated()).headers().frameOptions().sameOrigin()// 避免iframe同源无法登录
- .and().apply(new FormIdentityLoginConfigurer()); // 表单登录个性化
+ http.authorizeRequests(authorizeRequests -> authorizeRequests.antMatchers("/token/*")
+ .permitAll()// 开放自定义的部分端点
+ .anyRequest()
+ .authenticated())
+ .headers()
+ .frameOptions()
+ .sameOrigin()// 避免iframe同源无法登录
+ .and()
+ .apply(new FormIdentityLoginConfigurer()); // 表单登录个性化
// 处理 UsernamePasswordAuthenticationToken
http.authenticationProvider(new PigDaoAuthenticationProvider());
return http.build();
@@ -51,7 +57,7 @@ public class WebSecurityConfiguration {
/**
* 暴露静态资源
- *
+ *
* https://github.com/spring-projects/spring-security/issues/10938
* @param http
* @return
@@ -60,9 +66,14 @@ public class WebSecurityConfiguration {
@Bean
@Order(0)
SecurityFilterChain resources(HttpSecurity http) throws Exception {
- http.requestMatchers((matchers) -> matchers.antMatchers("/actuator/**", "/css/**", "/error"))
- .authorizeHttpRequests((authorize) -> authorize.anyRequest().permitAll()).requestCache().disable()
- .securityContext().disable().sessionManagement().disable();
+ http.requestMatchers((matchers) -> matchers.antMatchers("/actuator/**", "/code/image", "/css/**", "/error"))
+ .authorizeHttpRequests((authorize) -> authorize.anyRequest().permitAll())
+ .requestCache()
+ .disable()
+ .securityContext()
+ .disable()
+ .sessionManagement()
+ .disable();
return http.build();
}
diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/endpoint/ImageCodeEndpoint.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/endpoint/ImageCodeEndpoint.java
new file mode 100644
index 0000000000000000000000000000000000000000..6197f134ce8ce67c123a4e0071cbe0e026543b39
--- /dev/null
+++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/endpoint/ImageCodeEndpoint.java
@@ -0,0 +1,53 @@
+package com.pig4cloud.pig.auth.endpoint;
+
+import cn.hutool.core.lang.Validator;
+import com.pig4cloud.pig.common.core.constant.CacheConstants;
+import com.pig4cloud.pig.common.core.constant.SecurityConstants;
+import io.springboot.captcha.ArithmeticCaptcha;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 验证码相关的接口
+ *
+ * @author lengleng
+ * @date 2022/6/27
+ */
+@RestController
+@RequestMapping("/code")
+@RequiredArgsConstructor
+public class ImageCodeEndpoint {
+
+ private static final Integer DEFAULT_IMAGE_WIDTH = 100;
+
+ private static final Integer DEFAULT_IMAGE_HEIGHT = 40;
+
+ private final StringRedisTemplate redisTemplate;
+
+ /**
+ * 创建图形验证码
+ */
+ @SneakyThrows
+ @GetMapping("/image")
+ public void image(String randomStr, HttpServletResponse response) {
+ ArithmeticCaptcha captcha = new ArithmeticCaptcha(DEFAULT_IMAGE_WIDTH, DEFAULT_IMAGE_HEIGHT);
+
+ if (Validator.isMobile(randomStr)) {
+ return;
+ }
+
+ String result = captcha.text();
+ redisTemplate.opsForValue()
+ .set(CacheConstants.DEFAULT_CODE_KEY + randomStr, result, SecurityConstants.CODE_TIME, TimeUnit.SECONDS);
+ // 转换流信息写出
+ captcha.out(response.getOutputStream());
+ }
+
+}
diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/endpoint/PigTokenEndpoint.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/endpoint/PigTokenEndpoint.java
index 99b64714535553384f0c626854da741e39a46268..f9ae29cf8f9746b9e795896739455a7d32d5e42b 100644
--- a/pig-auth/src/main/java/com/pig4cloud/pig/auth/endpoint/PigTokenEndpoint.java
+++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/endpoint/PigTokenEndpoint.java
@@ -107,8 +107,10 @@ 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 authorizedScopes = StringUtils.commaDelimitedListToSet(clientDetails.getScope());
modelAndView.addObject("clientId", clientId);
@@ -168,7 +170,7 @@ public class PigTokenEndpoint {
* @param token token
*/
@Inner
- @DeleteMapping("/{token}")
+ @DeleteMapping("/remove/{token}")
public R removeToken(@PathVariable("token") String token) {
OAuth2Authorization authorization = authorizationService.findByToken(token, OAuth2TokenType.ACCESS_TOKEN);
if (authorization == null) {
@@ -179,8 +181,8 @@ public class PigTokenEndpoint {
if (accessToken == null || StrUtil.isBlank(accessToken.getToken().getTokenValue())) {
return R.ok();
}
- // 清空用户信息
- cacheManager.getCache(CacheConstants.USER_DETAILS).evict(authorization.getPrincipalName());
+ // 清空用户信息(立即删除)
+ cacheManager.getCache(CacheConstants.USER_DETAILS).evictIfPresent(authorization.getPrincipalName());
// 清空access token
authorizationService.remove(authorization);
// 处理自定义退出事件,保存相关日志
diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/CustomeOAuth2AccessTokenGenerator.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/CustomeOAuth2AccessTokenGenerator.java
index 7865f68d376b6fb1a8d21c239dcbd1f5f69b6679..667f6da5ada7b3382a871bc1233a4c93f85942e4 100644
--- a/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/CustomeOAuth2AccessTokenGenerator.java
+++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/CustomeOAuth2AccessTokenGenerator.java
@@ -30,7 +30,7 @@ public class CustomeOAuth2AccessTokenGenerator implements OAuth2TokenGenerator 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 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);
diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/base/OAuth2ResourceOwnerBaseAuthenticationProvider.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/base/OAuth2ResourceOwnerBaseAuthenticationProvider.java
index f551f77b98f4e0074866e22825cb199ea5b1bd80..5f1aa4680ad9f48856c64b75a5f52c6669d4690d 100644
--- a/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/base/OAuth2ResourceOwnerBaseAuthenticationProvider.java
+++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/base/OAuth2ResourceOwnerBaseAuthenticationProvider.java
@@ -128,7 +128,7 @@ public abstract class OAuth2ResourceOwnerBaseAuthenticationProvider(resouceOwnerBaseAuthentication.getScopes());
}
else {
- throw new ScopeException(OAuth2ErrorCodesExpand.SCOPE_IS_EMPTY);
+ authorizedScopes = new LinkedHashSet<>();
}
Map reqParameters = resouceOwnerBaseAuthentication.getAdditionalParameters();
@@ -139,7 +139,7 @@ public abstract class OAuth2ResourceOwnerBaseAuthenticationProvider logout.logoutSuccessHandler(new SsoLogoutSuccessHandler())
+ .deleteCookies("JSESSIONID")
+ .invalidateHttpSession(true)) // SSO登出成功处理
+
+ .csrf(AbstractHttpConfigurer::disable);
}
}
diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/core/PigDaoAuthenticationProvider.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/core/PigDaoAuthenticationProvider.java
index 36949419c77b7b2f071aa7f25bcf1f8af56353be..b587d68bfa80416005cee41bdbca6f6f4a63db1a 100644
--- a/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/core/PigDaoAuthenticationProvider.java
+++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/core/PigDaoAuthenticationProvider.java
@@ -1,11 +1,11 @@
package com.pig4cloud.pig.auth.support.core;
import cn.hutool.core.util.StrUtil;
-import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.pig4cloud.pig.common.core.constant.SecurityConstants;
import com.pig4cloud.pig.common.core.util.WebUtils;
import com.pig4cloud.pig.common.security.service.PigUserDetailsService;
+import javax.servlet.http.HttpServletRequest;
import lombok.SneakyThrows;
import org.springframework.core.Ordered;
import org.springframework.security.authentication.BadCredentialsException;
@@ -20,11 +20,11 @@ import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.web.authentication.www.BasicAuthenticationConverter;
import org.springframework.util.Assert;
-import javax.servlet.http.HttpServletRequest;
import java.util.Comparator;
import java.util.Map;
import java.util.Optional;
@@ -68,22 +68,22 @@ public class PigDaoAuthenticationProvider extends AbstractUserDetailsAuthenticat
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
- // app 模式不用校验密码
+ // 只有密码模式需要校验密码
String grantType = WebUtils.getRequest().get().getParameter(OAuth2ParameterNames.GRANT_TYPE);
- if (StrUtil.equals(SecurityConstants.APP, grantType)) {
+ if (!StrUtil.equals(AuthorizationGrantType.PASSWORD.getValue(), grantType)) {
return;
}
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,24 +92,25 @@ public class PigDaoAuthenticationProvider extends AbstractUserDetailsAuthenticat
protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) {
prepareTimingAttackProtection();
- HttpServletRequest request = WebUtils.getRequest().orElseThrow(
- (Supplier) () -> new InternalAuthenticationServiceException("web request is empty"));
+ HttpServletRequest request = WebUtils.getRequest()
+ .orElseThrow(
+ (Supplier) () -> new InternalAuthenticationServiceException("web request is empty"));
- Map paramMap = ServletUtil.getParamMap(request);
- String grantType = paramMap.get(OAuth2ParameterNames.GRANT_TYPE);
- String clientId = paramMap.get(OAuth2ParameterNames.CLIENT_ID);
+ String grantType = WebUtils.getRequest().get().getParameter(OAuth2ParameterNames.GRANT_TYPE);
+ String clientId = WebUtils.getRequest().get().getParameter(OAuth2ParameterNames.CLIENT_ID);
if (StrUtil.isBlank(clientId)) {
clientId = basicConvert.convert(request).getName();
}
Map userDetailsServiceMap = SpringUtil
- .getBeansOfType(PigUserDetailsService.class);
+ .getBeansOfType(PigUserDetailsService.class);
String finalClientId = clientId;
- Optional optional = userDetailsServiceMap.values().stream()
- .filter(service -> service.support(finalClientId, grantType))
- .max(Comparator.comparingInt(Ordered::getOrder));
+ Optional 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");
diff --git a/pig-gateway/src/main/java/com/pig4cloud/pig/gateway/config/GatewayConfigProperties.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/filter/AuthSecurityConfigProperties.java
similarity index 52%
rename from pig-gateway/src/main/java/com/pig4cloud/pig/gateway/config/GatewayConfigProperties.java
rename to pig-auth/src/main/java/com/pig4cloud/pig/auth/support/filter/AuthSecurityConfigProperties.java
index 4ca748de073d12e3398364002179d0364d487ae3..2633caf6788eae5f57c24283663060a7ff0acae7 100644
--- a/pig-gateway/src/main/java/com/pig4cloud/pig/gateway/config/GatewayConfigProperties.java
+++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/filter/AuthSecurityConfigProperties.java
@@ -1,8 +1,9 @@
-package com.pig4cloud.pig.gateway.config;
+package com.pig4cloud.pig.auth.support.filter;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.stereotype.Component;
import java.util.List;
@@ -13,17 +14,23 @@ import java.util.List;
* 网关配置文件
*/
@Data
+@Component
@RefreshScope
-@ConfigurationProperties("gateway")
-public class GatewayConfigProperties {
+@ConfigurationProperties("security")
+public class AuthSecurityConfigProperties {
/**
- * 网关解密登录前端密码 秘钥 {@link com.pig4cloud.pig.gateway.filter.PasswordDecoderFilter}
+ * 是否是微服务架构
+ */
+ private boolean isMicro;
+
+ /**
+ * 网关解密登录前端密码 秘钥
*/
private String encodeKey;
/**
- * 网关不需要校验验证码的客户端 {@link com.pig4cloud.pig.gateway.filter.ValidateCodeGatewayFilter}
+ * 网关不需要校验验证码的客户端
*/
private List ignoreClients;
diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/filter/PasswordDecoderFilter.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/filter/PasswordDecoderFilter.java
new file mode 100755
index 0000000000000000000000000000000000000000..c756e752397132a8f81a6ea40786dba64fec2d17
--- /dev/null
+++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/filter/PasswordDecoderFilter.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2020 pig4cloud Authors. All Rights Reserved.
+ *
+ * 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.pig4cloud.pig.auth.support.filter;
+
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.crypto.Mode;
+import cn.hutool.crypto.Padding;
+import cn.hutool.crypto.SecureUtil;
+import cn.hutool.crypto.symmetric.AES;
+import com.pig4cloud.pig.common.core.constant.SecurityConstants;
+import com.pig4cloud.pig.common.core.servlet.RepeatBodyRequestWrapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * @author lengleng
+ * @date 2019 /2/1 密码解密工具类
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class PasswordDecoderFilter extends OncePerRequestFilter {
+
+ private final AuthSecurityConfigProperties authSecurityConfigProperties;
+
+ private static final String PASSWORD = "password";
+
+ private static final String KEY_ALGORITHM = "AES";
+
+ static {
+ // 关闭hutool 强制关闭Bouncy Castle库的依赖
+ SecureUtil.disableBouncyCastle();
+ }
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
+ throws ServletException, IOException {
+ // 不是登录请求,直接向下执行
+ if (!StrUtil.containsAnyIgnoreCase(request.getRequestURI(), SecurityConstants.OAUTH_TOKEN_URL)) {
+ chain.doFilter(request, response);
+ return;
+ }
+
+ // 将请求流转换为可多次读取的请求流
+ RepeatBodyRequestWrapper requestWrapper = new RepeatBodyRequestWrapper(request);
+ Map parameterMap = requestWrapper.getParameterMap();
+
+ // 构建前端对应解密AES 因子
+ AES aes = new AES(Mode.CFB, Padding.NoPadding,
+ new SecretKeySpec(authSecurityConfigProperties.getEncodeKey().getBytes(), KEY_ALGORITHM),
+ new IvParameterSpec(authSecurityConfigProperties.getEncodeKey().getBytes()));
+
+ parameterMap.forEach((k, v) -> {
+ String[] values = parameterMap.get(k);
+ if (!PASSWORD.equals(k) || ArrayUtil.isEmpty(values)) {
+ return;
+ }
+
+ // 解密密码
+ String decryptPassword = aes.decryptStr(values[0]);
+ parameterMap.put(k, new String[] { decryptPassword });
+ });
+ chain.doFilter(requestWrapper, response);
+ }
+
+}
diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/filter/ValidateCodeFilter.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/filter/ValidateCodeFilter.java
new file mode 100644
index 0000000000000000000000000000000000000000..3863251d675a100014e44aa3f968690572ccccce
--- /dev/null
+++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/filter/ValidateCodeFilter.java
@@ -0,0 +1,126 @@
+package com.pig4cloud.pig.auth.support.filter;
+
+/**
+ * 登录前处理器
+ *
+ * @author lengleng
+ * @date 2024/4/3
+ */
+
+import cn.hutool.core.util.StrUtil;
+import com.pig4cloud.pig.common.core.constant.CacheConstants;
+import com.pig4cloud.pig.common.core.constant.SecurityConstants;
+import com.pig4cloud.pig.common.core.exception.ValidateCodeException;
+import com.pig4cloud.pig.common.core.util.SpringContextHolder;
+import com.pig4cloud.pig.common.core.util.WebUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
+import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Optional;
+
+/**
+ * @author lbw
+ * @date 2024-01-06
+ *
+ * 登录前置处理器: 前端密码传输密文解密,验证码处理
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class ValidateCodeFilter extends OncePerRequestFilter {
+
+ private final AuthSecurityConfigProperties authSecurityConfigProperties;
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
+ throws ServletException, IOException {
+
+ String requestUrl = request.getServletPath();
+
+ // 不是登录URL 请求直接跳过
+ if (!SecurityConstants.OAUTH_TOKEN_URL.equals(requestUrl)) {
+ filterChain.doFilter(request, response);
+ return;
+ }
+
+ // 如果登录URL 但是刷新token的请求,直接向下执行
+ String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE);
+ if (StrUtil.equals(SecurityConstants.REFRESH_TOKEN, grantType)) {
+ filterChain.doFilter(request, response);
+ return;
+ }
+
+ // 客户端配置跳过验证码
+ boolean isIgnoreClient = authSecurityConfigProperties.getIgnoreClients().contains(WebUtils.getClientId());
+ if (isIgnoreClient) {
+ filterChain.doFilter(request, response);
+ return;
+ }
+
+ // 校验验证码 1. 客户端开启验证码 2. 短信模式
+ try {
+ checkCode();
+ filterChain.doFilter(request, response);
+ }
+ catch (ValidateCodeException validateCodeException) {
+ throw new OAuth2AuthenticationException(validateCodeException.getMessage());
+ }
+ }
+
+ /**
+ * 校验验证码
+ */
+ private void checkCode() throws ValidateCodeException {
+ Optional request = WebUtils.getRequest();
+ String code = request.get().getParameter("code");
+
+ if (StrUtil.isBlank(code)) {
+ throw new ValidateCodeException("验证码不能为空");
+ }
+
+ String randomStr = request.get().getParameter("randomStr");
+
+ // https://gitee.com/log4j/pig/issues/IWA0D
+ String mobile = request.get().getParameter("mobile");
+ if (StrUtil.isNotBlank(mobile)) {
+ randomStr = mobile;
+ }
+
+ String key = CacheConstants.DEFAULT_CODE_KEY + randomStr;
+ RedisTemplate redisTemplate = SpringContextHolder.getBean(StringRedisTemplate.class);
+ if (Boolean.FALSE.equals(redisTemplate.hasKey(key))) {
+ throw new ValidateCodeException("验证码不合法");
+ }
+
+ Object codeObj = redisTemplate.opsForValue().get(key);
+
+ if (codeObj == null) {
+ throw new ValidateCodeException("验证码不合法");
+ }
+
+ String saveCode = codeObj.toString();
+ if (StrUtil.isBlank(saveCode)) {
+ redisTemplate.delete(key);
+ throw new ValidateCodeException("验证码不合法");
+ }
+
+ if (!StrUtil.equals(saveCode, code)) {
+ redisTemplate.delete(key);
+ throw new ValidateCodeException("验证码不合法");
+ }
+
+ redisTemplate.delete(key);
+ }
+
+}
diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/handler/FormAuthenticationFailureHandler.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/handler/FormAuthenticationFailureHandler.java
index f4c0ad5f29d6725560cc741d182b82055733f2ab..636af33e6830a52911d37ee267351e2f81107df9 100644
--- a/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/handler/FormAuthenticationFailureHandler.java
+++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/handler/FormAuthenticationFailureHandler.java
@@ -19,14 +19,13 @@ package com.pig4cloud.pig.auth.support.handler;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.http.HttpUtil;
import com.pig4cloud.pig.common.core.util.WebUtils;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
/**
* @author lengleng
* @date 2022-06-02
diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/handler/PigAuthenticationFailureEventHandler.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/handler/PigAuthenticationFailureEventHandler.java
index a12b2a99df77d857c9396d9783b2300b4576a225..101871829e28bca4b6f765ba621d84f9350d10b0 100644
--- a/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/handler/PigAuthenticationFailureEventHandler.java
+++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/handler/PigAuthenticationFailureEventHandler.java
@@ -19,8 +19,6 @@ package com.pig4cloud.pig.auth.support.handler;
import cn.hutool.core.util.StrUtil;
import com.pig4cloud.pig.admin.api.entity.SysLog;
import com.pig4cloud.pig.common.core.constant.CommonConstants;
-import com.pig4cloud.pig.common.core.constant.SecurityConstants;
-import com.pig4cloud.pig.common.core.util.MsgUtils;
import com.pig4cloud.pig.common.core.util.R;
import com.pig4cloud.pig.common.core.util.SpringContextHolder;
import com.pig4cloud.pig.common.log.event.SysLogEvent;
@@ -66,7 +64,7 @@ public class PigAuthenticationFailureEventHandler implements AuthenticationFailu
log.info("用户:{} 登录失败,异常:{}", username, exception.getLocalizedMessage());
SysLog logVo = SysLogUtils.getSysLog();
logVo.setTitle("登录失败");
- logVo.setType(LogTypeEnum.ERROR.getType());
+ logVo.setLogType(LogTypeEnum.ERROR.getType());
logVo.setException(exception.getLocalizedMessage());
// 发送异步日志事件
String startTimeStr = request.getHeader(CommonConstants.REQUEST_START_TIME);
@@ -76,7 +74,6 @@ public class PigAuthenticationFailureEventHandler implements AuthenticationFailu
logVo.setTime(endTime - startTime);
}
logVo.setCreateBy(username);
- logVo.setUpdateBy(username);
SpringContextHolder.publishEvent(new SysLogEvent(logVo));
// 写出错误信息
sendErrorResponse(request, response, exception);
@@ -98,12 +95,6 @@ public class PigAuthenticationFailureEventHandler implements AuthenticationFailu
errorMessage = exception.getLocalizedMessage();
}
- // 手机号登录
- String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE);
- if (SecurityConstants.APP.equals(grantType)) {
- errorMessage = MsgUtils.getSecurityMessage("AbstractUserDetailsAuthenticationProvider.smsBadCredentials");
- }
-
this.errorHttpResponseConverter.write(R.failed(errorMessage), MediaType.APPLICATION_JSON, httpResponse);
}
diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/handler/PigAuthenticationSuccessEventHandler.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/handler/PigAuthenticationSuccessEventHandler.java
index 162babd2133ea5fbf0800244d2efd67f9830ff80..40dff7d5f6f2dabfacea510aec641d0f9963fa83 100644
--- a/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/handler/PigAuthenticationSuccessEventHandler.java
+++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/handler/PigAuthenticationSuccessEventHandler.java
@@ -24,7 +24,10 @@ import com.pig4cloud.pig.common.core.constant.SecurityConstants;
import com.pig4cloud.pig.common.core.util.SpringContextHolder;
import com.pig4cloud.pig.common.log.event.SysLogEvent;
import com.pig4cloud.pig.common.log.util.SysLogUtils;
+import com.pig4cloud.pig.common.security.component.PigCustomOAuth2AccessTokenResponseHttpMessageConverter;
import com.pig4cloud.pig.common.security.service.PigUser;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageConverter;
@@ -34,13 +37,10 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
-import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.util.CollectionUtils;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.temporal.ChronoUnit;
import java.util.Map;
@@ -52,7 +52,7 @@ import java.util.Map;
@Slf4j
public class PigAuthenticationSuccessEventHandler implements AuthenticationSuccessHandler {
- private final HttpMessageConverter accessTokenHttpResponseConverter = new OAuth2AccessTokenResponseHttpMessageConverter();
+ private final HttpMessageConverter accessTokenHttpResponseConverter = new PigCustomOAuth2AccessTokenResponseHttpMessageConverter();
/**
* Called when a user has been successfully authenticated.
@@ -81,7 +81,6 @@ public class PigAuthenticationSuccessEventHandler implements AuthenticationSucce
logVo.setTime(endTime - startTime);
}
logVo.setCreateBy(userInfo.getName());
- logVo.setUpdateBy(userInfo.getName());
SpringContextHolder.publishEvent(new SysLogEvent(logVo));
}
@@ -99,7 +98,8 @@ public class PigAuthenticationSuccessEventHandler implements AuthenticationSucce
Map 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()));
}
@@ -114,6 +114,7 @@ public class PigAuthenticationSuccessEventHandler implements AuthenticationSucce
// 无状态 注意删除 context 上下文的信息
SecurityContextHolder.clearContext();
+
this.accessTokenHttpResponseConverter.write(accessTokenResponse, null, httpResponse);
}
diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/handler/PigLogoutSuccessEventHandler.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/handler/PigLogoutSuccessEventHandler.java
index b929345b6dab8e98da7f6ba8b4a6d90f28acc0f7..cbd1086010d26015bef944e644a3d99fee499413 100644
--- a/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/handler/PigLogoutSuccessEventHandler.java
+++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/support/handler/PigLogoutSuccessEventHandler.java
@@ -70,7 +70,6 @@ public class PigLogoutSuccessEventHandler implements ApplicationListener
-