diff --git a/sql/wfc_config_db/wfc_config_db.sql b/sql/wfc_config_db/wfc_config_db.sql index 77c3a63..e5e703c 100644 --- a/sql/wfc_config_db/wfc_config_db.sql +++ b/sql/wfc_config_db/wfc_config_db.sql @@ -86,8 +86,8 @@ INSERT INTO `config_info` VALUES (49, 'wfc-user-test.yml', 'DEFAULT_GROUP', '# s INSERT INTO `config_info` VALUES (50, 'wfc-payment-test.yml', 'DEFAULT_GROUP', '# spring配置\nspring:\n main:\n allow-bean-definition-overriding: true\n \n redis:\n host: wfc-redis\n port: 6379\n password:\n datasource:\n druid:\n stat-view-servlet:\n enabled: true\n loginUsername: admin\n loginPassword: 123456\n dynamic:\n druid:\n initial-size: 5\n min-idle: 5\n maxActive: 20\n maxWait: 60000\n connectTimeout: 30000\n socketTimeout: 60000\n timeBetweenEvictionRunsMillis: 60000\n minEvictableIdleTimeMillis: 300000\n validationQuery: SELECT 1 FROM DUAL\n testWhileIdle: true\n testOnBorrow: false\n testOnReturn: false\n poolPreparedStatements: true\n maxPoolPreparedStatementPerConnectionSize: 20\n filters: stat,slf4j\n connectionProperties: druid.stat.mergeSql\\=true;druid.stat.slowSqlMillis\\=5000\n datasource:\n # 主库数据源\n master:\n driver-class-name: com.mysql.cj.jdbc.Driver\n url: jdbc:mysql://wfc-mysql:3306/wfc_user_db?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8\n username: root\n password: 123456\n # 从库数据源\n # slave:\n # username:\n # password:\n # url:\n # driver-class-name:\n\n# mybatis-plus配置\nmybatis-plus:\n # 搜索指定包别名\n type-aliases-package: org.wfc.system\n # 配置mapper的扫描,找到所有的mapper.xml映射文件\n mapper-locations: classpath:mapper/**/*.xml\n global-config:\n db-config:\n logic-delete-field: del_flag\n logic-delete-value: 1\n logic-not-delete-value: 0\n\n# swagger配置\nswagger:\n title: 系统模块接口文档\n license: Powered By wfc\n licenseUrl: https://wfc.vip\n\nlogging:\n level:\n root: debug\n org:\n springframework:\n web: debug\n mybatis:\n mapper: debug\n wfc:\n system: debug\n com:\n github:\n binarywang: debug\n file:\n name: /var/log/wfc/wfc-modules-payment.log\n\nwxpay:\n appId: 121412414112\n mchId: 1131412414\n mchKey: 1525342aa\n subAppId: #服务商模式下的子商户公众账号ID\n subMchId: #服务商模式下的子商户号 \n keyPath: /home/wfc/config/payment/wxpay_key.pem\n useSandboxEnv: false\n ', '782c7fb3b169abae667b19cd08b96df8', '2024-12-28 19:22:50', '2024-12-28 19:22:50', NULL, '172.19.0.1', '', 'wfc-test', 'wfc-modules-payment production yaml', NULL, NULL, 'yaml', NULL, ''); INSERT INTO `config_info` VALUES (51, 'sentinel-wfc-gateway-test', 'DEFAULT_GROUP', '[\r\n {\r\n \"resource\": \"wfc-auth\",\r\n \"count\": 500,\r\n \"grade\": 1,\r\n \"limitApp\": \"default\",\r\n \"strategy\": 0,\r\n \"controlBehavior\": 0\r\n },\r\n {\r\n \"resource\": \"wfc-system\",\r\n \"count\": 1000,\r\n \"grade\": 1,\r\n \"limitApp\": \"default\",\r\n \"strategy\": 0,\r\n \"controlBehavior\": 0\r\n },\r\n {\r\n \"resource\": \"wfc-gen\",\r\n \"count\": 200,\r\n \"grade\": 1,\r\n \"limitApp\": \"default\",\r\n \"strategy\": 0,\r\n \"controlBehavior\": 0\r\n },\r\n {\r\n \"resource\": \"wfc-job\",\r\n \"count\": 300,\r\n \"grade\": 1,\r\n \"limitApp\": \"default\",\r\n \"strategy\": 0,\r\n \"controlBehavior\": 0\r\n }\r\n]', 'a8b3ec396dd09d5f2ba494cc80a7afa0', '2024-12-28 19:28:44', '2024-12-28 19:28:44', NULL, '172.19.0.1', '', 'wfc-test', '限流策略', NULL, NULL, 'json', NULL, ''); -INSERT INTO `config_info` VALUES (61, 'application-prod.yml', 'DEFAULT_GROUP', 'spring:\n autoconfigure:\n exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure\n mvc:\n pathmatch:\n matching-strategy: ant_path_matcher\n # 资源信息\n #messages:\n # 国际化资源文件路径\n #basename: i18n/messages\n \n# feign 配置\nfeign:\n sentinel:\n enabled: true\n okhttp:\n enabled: false\n httpclient:\n enabled: true\n disable-ssl-validation: true\n client:\n config:\n default:\n connectTimeout: 60000\n readTimeout: 60000\n compression:\n request:\n enabled: true\n min-request-size: 8192\n response:\n enabled: true\n\n# 暴露监控端点\nmanagement:\n endpoints:\n web:\n exposure:\n include: \'*\'\n \n', '82d8c057ca3afdbaf5ad6f607914d27a', '2024-12-13 11:52:34', '2025-01-20 12:56:36', NULL, '172.19.0.1', '', 'wfc-prod', '通用配置', '', '', 'yaml', '', ''); -INSERT INTO `config_info` VALUES (62, 'wfc-gateway-prod.yml', 'DEFAULT_GROUP', 'spring:\n redis:\n host: wfc-redis\n port: 6379\n password:\n cloud:\n gateway:\n discovery:\n locator:\n lowerCaseServiceId: true\n enabled: true\n routes:\n # 认证中心\n - id: wfc-auth\n uri: lb://wfc-auth\n predicates:\n - Path=/auth/**\n filters:\n # 验证码处理\n - CacheRequestFilter\n - ValidateCodeFilter\n - StripPrefix=1\n # 代码生成\n - id: wfc-gen\n uri: lb://wfc-gen\n predicates:\n - Path=/code/**\n filters:\n - StripPrefix=1\n # 定时任务\n - id: wfc-job\n uri: lb://wfc-job\n predicates:\n - Path=/schedule/**\n filters:\n - StripPrefix=1\n # 系统模块\n - id: wfc-system\n uri: lb://wfc-system\n predicates:\n - Path=/system/**\n filters:\n - StripPrefix=1\n # 用户模块\n - id: wfc-user\n uri: lb://wfc-user\n predicates:\n - Path=/u/**\n filters:\n - StripPrefix=1 \n # 文件服务\n - id: wfc-file\n uri: lb://wfc-file\n predicates:\n - Path=/file/**\n filters:\n - StripPrefix=1\n # payment\n - id: wfc-payment\n uri: lb://wfc-payment\n predicates:\n - Path=/payment/**\n filters:\n - StripPrefix=1 \n\n# 安全配置\nsecurity:\n # 验证码\n captcha:\n enabled: true\n type: math\n # 防止XSS攻击\n xss:\n enabled: true\n excludeUrls:\n - /system/notice\n # 不校验白名单\n ignore:\n whites:\n - /auth/logout\n - /auth/login\n - /auth/register\n - /auth/checkRepeat\n - /*/v2/api-docs\n - /csrf\n - /payment/aliPay/callback\n - /payment/wxPay/callback\n', 'ff556284699feb397ab1c73e98e1a3c3', '2024-12-13 11:52:34', '2025-01-24 04:14:22', NULL, '172.19.0.1', '', 'wfc-prod', 'wfc-gateway production', '', '', 'yaml', '', ''); +INSERT INTO `config_info` VALUES (61, 'application-prod.yml', 'DEFAULT_GROUP', 'spring:\n autoconfigure:\n exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure\n mvc:\n pathmatch:\n matching-strategy: ant_path_matcher\n # 资源信息\n #messages:\n # 国际化资源文件路径\n #basename: i18n/messages\n \n# feign 配置\nfeign:\n sentinel:\n enabled: true\n okhttp:\n enabled: false\n httpclient:\n enabled: true\n disable-ssl-validation: true\n client:\n config:\n default:\n connectTimeout: 60000\n readTimeout: 60000\n compression:\n request:\n enabled: true\n min-request-size: 8192\n response:\n enabled: true\n\n# 暴露监控端点\nmanagement:\n endpoints:\n web:\n exposure:\n include: \'*\'\n \n# 邮箱\nmail:\n enabled: true\n host: smtp.qq.com\n port: 465\n # 是否需要用户名密码验证\n auth: true\n # 发送方,遵循RFC-822标准\n from: 707821112@qq.com\n # 用户名(注意:如果使用foxmail邮箱,此处user为qq号)\n user: 707821112@qq.com\n # 密码(注意,某些邮箱需要为SMTP服务单独设置密码,详情查看相关帮助)\n pass: zcbontiutwvebedb2\n # 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。\n starttlsEnable: true\n # 使用SSL安全连接\n sslEnable: true\n # SMTP超时时长,单位毫秒,缺省值不超时\n timeout: 0\n # Socket连接超时值,单位毫秒,缺省值不超时\n connectionTimeout: 0\n \n', 'c37793d4d5aa1070a15ae4d8ad346a3e', '2024-12-13 11:52:34', '2025-02-07 11:09:55', NULL, '192.168.88.14', '', 'wfc-prod', '通用配置', '', '', 'yaml', '', ''); +INSERT INTO `config_info` VALUES (62, 'wfc-gateway-prod.yml', 'DEFAULT_GROUP', 'spring:\n redis:\n host: wfc-redis\n port: 6379\n password:\n cloud:\n gateway:\n discovery:\n locator:\n lowerCaseServiceId: true\n enabled: true\n routes:\n # 认证中心\n - id: wfc-auth\n uri: lb://wfc-auth\n predicates:\n - Path=/auth/**\n filters:\n # 验证码处理\n - CacheRequestFilter\n - ValidateCodeFilter\n - StripPrefix=1\n # 代码生成\n - id: wfc-gen\n uri: lb://wfc-gen\n predicates:\n - Path=/code/**\n filters:\n - StripPrefix=1\n # 定时任务\n - id: wfc-job\n uri: lb://wfc-job\n predicates:\n - Path=/schedule/**\n filters:\n - StripPrefix=1\n # 系统模块\n - id: wfc-system\n uri: lb://wfc-system\n predicates:\n - Path=/system/**\n filters:\n - StripPrefix=1\n # 用户模块\n - id: wfc-user\n uri: lb://wfc-user\n predicates:\n - Path=/u/**\n filters:\n - StripPrefix=1 \n # 文件服务\n - id: wfc-file\n uri: lb://wfc-file\n predicates:\n - Path=/file/**\n filters:\n - StripPrefix=1\n # payment\n - id: wfc-payment\n uri: lb://wfc-payment\n predicates:\n - Path=/payment/**\n filters:\n - StripPrefix=1 \n\n# 安全配置\nsecurity:\n # 验证码\n captcha:\n enabled: true\n mailEnabled: true\n type: math\n # 防止XSS攻击\n xss:\n enabled: true\n excludeUrls:\n - /system/notice\n # 不校验白名单\n ignore:\n whites:\n - /auth/logout\n - /auth/login\n - /auth/register\n - /auth/checkRepeat\n - /*/v2/api-docs\n - /csrf\n - /u/email/code\n - /payment/aliPay/callback\n - /payment/wxPay/callback\n', '097c37e699095201baa494d9576fb0b2', '2024-12-13 11:52:34', '2025-02-07 11:26:31', NULL, '192.168.88.14', '', 'wfc-prod', 'wfc-gateway production', '', '', 'yaml', '', ''); INSERT INTO `config_info` VALUES (63, 'wfc-auth-prod.yml', 'DEFAULT_GROUP', 'spring:\n redis:\n host: wfc-redis\n port: 6379\n password:\n', 'c3f5481240e7581cc397f5c7918fd785', '2024-12-13 11:52:34', '2024-12-13 11:53:35', NULL, '192.168.2.116', '', 'wfc-prod', '认证中心', '', '', 'yaml', '', ''); INSERT INTO `config_info` VALUES (64, 'wfc-monitor-prod.yml', 'DEFAULT_GROUP', '# spring\nspring:\n security:\n user:\n name: wfc\n password: 123456\n boot:\n admin:\n ui:\n title: visual monitor\n', 'c8f896d284d5328aab16baeb81a3685c', '2024-12-13 11:52:34', '2024-12-13 11:54:04', NULL, '192.168.2.116', '', 'wfc-prod', '监控中心', '', '', 'yaml', '', ''); INSERT INTO `config_info` VALUES (65, 'wfc-system-prod.yml', 'DEFAULT_GROUP', '# spring配置\nspring:\n redis:\n host: wfc-redis\n port: 6379\n password:\n datasource:\n druid:\n stat-view-servlet:\n enabled: true\n loginUsername: admin\n loginPassword: 123456\n dynamic:\n druid:\n initial-size: 5\n min-idle: 5\n maxActive: 20\n maxWait: 60000\n connectTimeout: 30000\n socketTimeout: 60000\n timeBetweenEvictionRunsMillis: 60000\n minEvictableIdleTimeMillis: 300000\n validationQuery: SELECT 1 FROM DUAL\n testWhileIdle: true\n testOnBorrow: false\n testOnReturn: false\n poolPreparedStatements: true\n maxPoolPreparedStatementPerConnectionSize: 20\n filters: stat,slf4j\n connectionProperties: druid.stat.mergeSql\\=true;druid.stat.slowSqlMillis\\=5000\n datasource:\n # 主库数据源\n master:\n driver-class-name: com.mysql.cj.jdbc.Driver\n url: jdbc:mysql://wfc-mysql:3306/wfc_system_db?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8\n username: root\n password: 123456\n # 从库数据源\n # slave:\n # username: \n # password: \n # url: \n # driver-class-name: \n\n# mybatis配置\nmybatis:\n # 搜索指定包别名\n typeAliasesPackage: org.wfc.system\n # 配置mapper的扫描,找到所有的mapper.xml映射文件\n mapperLocations: classpath:mapper/**/*.xml\n\n# swagger配置\nswagger:\n title: 系统模块接口文档\n license: Powered By wfc\n licenseUrl: https://wfc.vip', 'a355587121f711511c9010a4a8c0d797', '2024-12-13 11:52:34', '2024-12-13 11:54:49', NULL, '192.168.2.116', '', 'wfc-prod', '系统模块', '', '', 'yaml', '', ''); diff --git a/wfc-auth/src/main/java/org/wfc/auth/WfcAuthApplication.java b/wfc-auth/src/main/java/org/wfc/auth/WfcAuthApplication.java index 5f48322..e8f9899 100644 --- a/wfc-auth/src/main/java/org/wfc/auth/WfcAuthApplication.java +++ b/wfc-auth/src/main/java/org/wfc/auth/WfcAuthApplication.java @@ -3,6 +3,7 @@ package org.wfc.auth; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.wfc.common.security.annotation.EnableCustomConfig; import org.wfc.common.security.annotation.EnableRyFeignClients; /** @@ -10,6 +11,7 @@ import org.wfc.common.security.annotation.EnableRyFeignClients; * * @author wfc */ +@EnableCustomConfig @EnableRyFeignClients @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class }) public class WfcAuthApplication diff --git a/wfc-common/wfc-common-core/src/main/java/org/wfc/common/core/constant/Constants.java b/wfc-common/wfc-common-core/src/main/java/org/wfc/common/core/constant/Constants.java index 7a94ed0..db59697 100644 --- a/wfc-common/wfc-common-core/src/main/java/org/wfc/common/core/constant/Constants.java +++ b/wfc-common/wfc-common-core/src/main/java/org/wfc/common/core/constant/Constants.java @@ -115,7 +115,7 @@ public class Constants /** * 邮箱验证码有效期(分钟) */ - public static final long MAIL_CAPTCHA_EXPIRATION = 30; + public static final long MAIL_CAPTCHA_EXPIRATION = 10; /** * 资源映射路径 前缀 diff --git a/wfc-common/wfc-common-core/src/main/java/org/wfc/common/core/constant/SecurityConstants.java b/wfc-common/wfc-common-core/src/main/java/org/wfc/common/core/constant/SecurityConstants.java index 907da08..2be0de2 100644 --- a/wfc-common/wfc-common-core/src/main/java/org/wfc/common/core/constant/SecurityConstants.java +++ b/wfc-common/wfc-common-core/src/main/java/org/wfc/common/core/constant/SecurityConstants.java @@ -51,4 +51,9 @@ public class SecurityConstants * 角色权限 */ public static final String ROLE_PERMISSION = "role_permission"; + + /** + * 多语言 + */ + public static final String CONTENT_LANGUAGE = "content-language"; } diff --git a/wfc-common/wfc-common-core/src/main/java/org/wfc/common/core/exception/VerificationCodeException.java b/wfc-common/wfc-common-core/src/main/java/org/wfc/common/core/exception/VerificationCodeException.java new file mode 100644 index 0000000..5749a5e --- /dev/null +++ b/wfc-common/wfc-common-core/src/main/java/org/wfc/common/core/exception/VerificationCodeException.java @@ -0,0 +1,22 @@ +package org.wfc.common.core.exception; + +import org.wfc.common.core.exception.user.UserException; + +/** + * 验证码错误异常类 + * + * @author wfc + */ +public class VerificationCodeException extends UserException +{ + private static final long serialVersionUID = 1L; + + public VerificationCodeException() { + super("email.code.error"); + } + + public VerificationCodeException(String msg) + { + super(msg); + } +} diff --git a/wfc-common/wfc-common-core/src/main/resources/i18n/messages_en_US.properties b/wfc-common/wfc-common-core/src/main/resources/i18n/messages_en_US.properties index f5ec7c2..7b38880 100644 --- a/wfc-common/wfc-common-core/src/main/resources/i18n/messages_en_US.properties +++ b/wfc-common/wfc-common-core/src/main/resources/i18n/messages_en_US.properties @@ -51,6 +51,7 @@ rate.limiter.message=Visit too frequently, please try again later sms.code.not.blank=Sms code cannot be blank sms.code.retry.limit.count=Sms code input error {0} times sms.code.retry.limit.exceed=Sms code input error {0} times, account locked for {1} minutes +email.code.error=Verification code error email.code.not.blank=Email code cannot be blank email.code.retry.limit.count=Email code input error {0} times email.code.retry.limit.exceed=Email code input error {0} times, account locked for {1} minutes diff --git a/wfc-common/wfc-common-core/src/main/resources/i18n/messages_zh_CN.properties b/wfc-common/wfc-common-core/src/main/resources/i18n/messages_zh_CN.properties index 344d721..667cf35 100644 --- a/wfc-common/wfc-common-core/src/main/resources/i18n/messages_zh_CN.properties +++ b/wfc-common/wfc-common-core/src/main/resources/i18n/messages_zh_CN.properties @@ -51,6 +51,7 @@ rate.limiter.message=访问过于频繁,请稍候再试 sms.code.not.blank=短信验证码不能为空 sms.code.retry.limit.count=短信验证码输入错误{0}次 sms.code.retry.limit.exceed=短信验证码输入错误{0}次,帐户锁定{1}分钟 +email.code.error=邮箱验证码错误 email.code.not.blank=邮箱验证码不能为空 email.code.retry.limit.count=邮箱验证码输入错误{0}次 email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,帐户锁定{1}分钟 diff --git a/wfc-common/wfc-common-security/src/main/java/org/wfc/common/security/feign/FeignRequestInterceptor.java b/wfc-common/wfc-common-security/src/main/java/org/wfc/common/security/feign/FeignRequestInterceptor.java index 9fc7f52..f13bcef 100644 --- a/wfc-common/wfc-common-security/src/main/java/org/wfc/common/security/feign/FeignRequestInterceptor.java +++ b/wfc-common/wfc-common-security/src/main/java/org/wfc/common/security/feign/FeignRequestInterceptor.java @@ -1,14 +1,15 @@ package org.wfc.common.security.feign; -import java.util.Map; -import javax.servlet.http.HttpServletRequest; +import feign.RequestInterceptor; +import feign.RequestTemplate; import org.springframework.stereotype.Component; import org.wfc.common.core.constant.SecurityConstants; import org.wfc.common.core.utils.ServletUtils; import org.wfc.common.core.utils.StringUtils; import org.wfc.common.core.utils.ip.IpUtils; -import feign.RequestInterceptor; -import feign.RequestTemplate; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; /** * feign 请求拦截器 @@ -46,6 +47,11 @@ public class FeignRequestInterceptor implements RequestInterceptor { requestTemplate.header(SecurityConstants.AUTHORIZATION_HEADER, authentication); } + String language = headers.get(SecurityConstants.CONTENT_LANGUAGE); + if (StringUtils.isNotEmpty(language)) + { + requestTemplate.header(SecurityConstants.CONTENT_LANGUAGE, language); + } String platform = headers.get(SecurityConstants.DETAILS_PLATFORM); if (StringUtils.isNotEmpty(platform)) { requestTemplate.header(SecurityConstants.DETAILS_PLATFORM, platform); diff --git a/wfc-gateway/src/main/java/org/wfc/gateway/config/properties/CaptchaProperties.java b/wfc-gateway/src/main/java/org/wfc/gateway/config/properties/CaptchaProperties.java index f6f9aba..6ed1255 100644 --- a/wfc-gateway/src/main/java/org/wfc/gateway/config/properties/CaptchaProperties.java +++ b/wfc-gateway/src/main/java/org/wfc/gateway/config/properties/CaptchaProperties.java @@ -15,10 +15,15 @@ import org.springframework.context.annotation.Configuration; public class CaptchaProperties { /** - * 验证码开关 + * 图片验证码开关 */ private Boolean enabled; + /** + * 邮箱验证码开关 + */ + private Boolean mailEnabled; + /** * 验证码类型(math 数组计算 char 字符) */ @@ -43,4 +48,12 @@ public class CaptchaProperties { this.type = type; } + + public Boolean getMailEnabled() { + return mailEnabled; + } + + public void setMailEnabled(Boolean mailEnabled) { + this.mailEnabled = mailEnabled; + } } diff --git a/wfc-gateway/src/main/java/org/wfc/gateway/filter/ValidateCodeFilter.java b/wfc-gateway/src/main/java/org/wfc/gateway/filter/ValidateCodeFilter.java index 5decc69..bf10d47 100644 --- a/wfc-gateway/src/main/java/org/wfc/gateway/filter/ValidateCodeFilter.java +++ b/wfc-gateway/src/main/java/org/wfc/gateway/filter/ValidateCodeFilter.java @@ -1,8 +1,7 @@ package org.wfc.gateway.filter; -import java.nio.CharBuffer; -import java.nio.charset.StandardCharsets; -import java.util.concurrent.atomic.AtomicReference; +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; @@ -10,14 +9,16 @@ import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBufferUtils; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.stereotype.Component; -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.JSONObject; import org.wfc.common.core.utils.ServletUtils; import org.wfc.common.core.utils.StringUtils; import org.wfc.gateway.config.properties.CaptchaProperties; import org.wfc.gateway.service.ValidateCodeService; import reactor.core.publisher.Flux; +import java.nio.CharBuffer; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.atomic.AtomicReference; + /** * 验证码过滤器 * @@ -26,7 +27,8 @@ import reactor.core.publisher.Flux; @Component public class ValidateCodeFilter extends AbstractGatewayFilterFactory { - private final static String[] VALIDATE_URL = new String[] { "/auth/login", "/auth/register" }; + private final static String[] VALIDATE_URL = new String[] { "/auth/login" }; + private final static String[] MAIL_VALIDATE_URL = new String[] { "/auth/register" }; @Autowired private ValidateCodeService validateCodeService; @@ -38,14 +40,18 @@ public class ValidateCodeFilter extends AbstractGatewayFilterFactory private static final String UUID = "uuid"; + private static final String EMAIL = "email"; + @Override public GatewayFilter apply(Object config) { return (exchange, chain) -> { ServerHttpRequest request = exchange.getRequest(); - // 非登录/注册请求或验证码关闭,不处理 - if (!StringUtils.equalsAnyIgnoreCase(request.getURI().getPath(), VALIDATE_URL) || !captchaProperties.getEnabled()) + // 非登录请求且验证码启用,非注册请求且邮箱验证码启用, 不处理 + boolean enabledLoginCaptcha = StringUtils.equalsAnyIgnoreCase(request.getURI().getPath(), VALIDATE_URL) && captchaProperties.getEnabled(); + boolean enabledRegisterCaptcha = StringUtils.equalsAnyIgnoreCase(request.getURI().getPath(), MAIL_VALIDATE_URL) && captchaProperties.getMailEnabled(); + if (!enabledLoginCaptcha && !enabledRegisterCaptcha) { return chain.filter(exchange); } @@ -54,7 +60,14 @@ public class ValidateCodeFilter extends AbstractGatewayFilterFactory { String rspStr = resolveBodyFromRequest(request); JSONObject obj = JSON.parseObject(rspStr); - validateCodeService.checkCaptcha(obj.getString(CODE), obj.getString(UUID)); + // 图片验证码启用 + if (enabledLoginCaptcha) { + validateCodeService.checkCaptcha(obj.getString(CODE), obj.getString(UUID)); + } + // 邮箱验证码启用 + if (enabledRegisterCaptcha) { + validateCodeService.checkCaptchaEmail(obj.getString(CODE), obj.getString(EMAIL)); + } } catch (Exception e) { diff --git a/wfc-gateway/src/main/java/org/wfc/gateway/service/ValidateCodeService.java b/wfc-gateway/src/main/java/org/wfc/gateway/service/ValidateCodeService.java index 2861e6e..97a1de1 100644 --- a/wfc-gateway/src/main/java/org/wfc/gateway/service/ValidateCodeService.java +++ b/wfc-gateway/src/main/java/org/wfc/gateway/service/ValidateCodeService.java @@ -1,9 +1,10 @@ package org.wfc.gateway.service; -import java.io.IOException; import org.wfc.common.core.exception.CaptchaException; import org.wfc.common.core.web.domain.AjaxResult; +import java.io.IOException; + /** * 验证码处理 * @@ -25,4 +26,9 @@ public interface ValidateCodeService * 校验验证码 */ public void checkCaptcha(String key, String value) throws CaptchaException; + + /** + * 校验邮箱验证码 + */ + public void checkCaptchaEmail(String key, String value) throws CaptchaException; } diff --git a/wfc-gateway/src/main/java/org/wfc/gateway/service/impl/ValidateCodeServiceImpl.java b/wfc-gateway/src/main/java/org/wfc/gateway/service/impl/ValidateCodeServiceImpl.java index c914847..1135822 100644 --- a/wfc-gateway/src/main/java/org/wfc/gateway/service/impl/ValidateCodeServiceImpl.java +++ b/wfc-gateway/src/main/java/org/wfc/gateway/service/impl/ValidateCodeServiceImpl.java @@ -8,13 +8,13 @@ import org.springframework.stereotype.Service; import org.springframework.util.FastByteArrayOutputStream; import org.wfc.common.core.constant.CacheConstants; import org.wfc.common.core.constant.Constants; -import org.wfc.common.core.domain.R; +import org.wfc.common.core.constant.GlobalConstants; import org.wfc.common.core.exception.CaptchaException; +import org.wfc.common.core.exception.VerificationCodeException; import org.wfc.common.core.utils.StringUtils; import org.wfc.common.core.utils.sign.Base64; import org.wfc.common.core.utils.uuid.IdUtils; import org.wfc.common.core.web.domain.AjaxResult; -import org.wfc.common.mail.utils.MailUtils; import org.wfc.common.redis.service.RedisService; import org.wfc.gateway.config.properties.CaptchaProperties; import org.wfc.gateway.service.ValidateCodeService; @@ -66,7 +66,7 @@ public class ValidateCodeServiceImpl implements ValidateCodeService // 保存验证码信息 String uuid = IdUtils.simpleUUID(); - String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid; + String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + uuid; String capStr = null, code = null; BufferedImage image = null; @@ -154,9 +154,9 @@ public class ValidateCodeServiceImpl implements ValidateCodeService { if (StringUtils.isEmpty(code)) { - throw new CaptchaException("user.captcha.not.blank"); + throw new CaptchaException("user.jcaptcha.not.blank"); } - String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, ""); + String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, ""); String captcha = redisService.getCacheObject(verifyKey); if (captcha == null) { @@ -168,4 +168,26 @@ public class ValidateCodeServiceImpl implements ValidateCodeService throw new CaptchaException(); } } + + /** + * 校验验证码 + */ + @Override + public void checkCaptchaEmail(String code, String uuid) throws CaptchaException + { + if (StringUtils.isEmpty(code)) + { + throw new VerificationCodeException("email.code.not.blankk"); + } + String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, ""); + String captcha = redisService.getCacheObject(verifyKey); + if (captcha == null) + { + throw new VerificationCodeException(); + } + if (!code.equalsIgnoreCase(captcha)) + { + throw new VerificationCodeException(); + } + } } diff --git a/wfc-modules/wfc-user/src/main/java/org/wfc/user/controller/UEmailController.java b/wfc-modules/wfc-user/src/main/java/org/wfc/user/controller/UEmailController.java index 0abff67..6001707 100644 --- a/wfc-modules/wfc-user/src/main/java/org/wfc/user/controller/UEmailController.java +++ b/wfc-modules/wfc-user/src/main/java/org/wfc/user/controller/UEmailController.java @@ -49,7 +49,7 @@ public class UEmailController extends BaseController { String code = RandomUtil.randomNumbers(4); redisService.setCacheObject(key, code, Constants.MAIL_CAPTCHA_EXPIRATION, TimeUnit.MINUTES); try { - MailUtils.sendText(email, "Registration verification code", "Your verification code is: " + code + ", The validity period is " + Constants.MAIL_CAPTCHA_EXPIRATION + " minutes, please fill in as soon as possible."); + MailUtils.sendText(email, "Your WANFI verification code", "Hi\nYour verification code is:\n" + code + "\nThis code will expire in " + Constants.MAIL_CAPTCHA_EXPIRATION + " minutes.\nFor your security, don't share it with anyone."); } catch (Exception e) { log.error("验证码短信发送异常 => {}", e.getMessage()); return R.fail(e.getMessage());