Explorar el Código

feat:初步完成邮件、短信验证

wanwenbi hace 3 años
padre
commit
c0c81e2382

+ 59 - 0
smsb-customer-manager-adapter/src/main/java/com/inspur/customer/web/controller/authcode/AuthCodeController.java

@@ -0,0 +1,59 @@
+package com.inspur.customer.web.controller.authcode;
+
+import com.alibaba.cola.dto.Response;
+import com.alibaba.cola.dto.SingleResponse;
+import com.inspur.customer.service.client.authcode.AuthCodeService;
+import com.inspur.customer.service.dto.AuthCodeCheckDTO;
+import com.inspur.customer.service.dto.AuthCodeDTO;
+import com.inspur.customer.service.dto.AuthCodeCheckResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+
+/**@Description: 验证码相关接口
+ * @version v1.0
+ * @author joe wan
+ * @date 2022/6/29 14:14
+ */
+@Slf4j
+@RestController
+@RequestMapping("/authcode")
+public class AuthCodeController {
+
+    @DubboReference
+    private AuthCodeService authCodeService;
+
+    /**@Description: 电话、邮件发送验证码
+     * @param[com.inspur.customer.service.dto.AuthCodeDTO]
+     * @return com.alibaba.cola.dto.Response
+     * @version v1.0
+     * @author joe wan
+     * @date 2022/6/29 17:19
+     */
+    @PostMapping("/send")
+    public Response sendAuthCode(@Validated @RequestBody AuthCodeDTO authCodeDTO){
+        if(StringUtils.isBlank(authCodeDTO.getEmail()) && StringUtils.isBlank(authCodeDTO.getPhoneNum())){
+            return Response.buildFailure("999","参数为空!");
+        }
+        return authCodeService.sendAuthCode(authCodeDTO);
+    }
+
+    /**@Description: 电话、邮件验证码check
+     * @param[com.inspur.customer.service.dto.AuthCodeDTO]
+     * @return com.alibaba.cola.dto.SingleResponse<com.inspur.customer.service.dto.AuthCodeResponseDTO>
+     * @version v1.0
+     * @author joe wan
+     * @date 2022/6/29 17:19
+     */
+    @PostMapping("/check")
+    public SingleResponse<AuthCodeCheckResponse> checkAuthCode(@Validated @RequestBody AuthCodeCheckDTO authCodeCheckDTO){
+        AuthCodeCheckResponse authCodeCheckResponse = authCodeService.checkAuthCode(authCodeCheckDTO);
+        return SingleResponse.of(authCodeCheckResponse);
+    }
+}

+ 23 - 0
smsb-customer-manager-adapter/src/main/java/com/inspur/customer/web/handler/BaseExceptionHandler.java

@@ -0,0 +1,23 @@
+package com.inspur.customer.web.handler;
+
+import com.alibaba.cola.dto.Response;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+
+/**@Description: 处理异常
+ * @version v1.0
+ * @author joe wan
+ * @date 2022/6/29 15:50
+ */
+@Slf4j
+@RestControllerAdvice
+public class BaseExceptionHandler {
+    @ExceptionHandler(MethodArgumentNotValidException.class)
+    public Response handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
+        log.error(e.getMessage(), e);
+        return Response.buildFailure("400", "参数出错: " + e.getBindingResult().getFieldErrors().get(0).getDefaultMessage());
+    }
+}

+ 27 - 0
smsb-customer-manager-app/pom.xml

@@ -55,6 +55,33 @@
             <groupId>org.springframework</groupId>
             <artifactId>spring-web</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.inspur</groupId>
+            <artifactId>smsb-event-logging-client</artifactId>
+            <version>0.0.1-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-annotations</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.mybatis</groupId>
+            <artifactId>mybatis-typehandlers-jsr310</artifactId>
+            <version>1.0.1</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.datatype</groupId>
+            <artifactId>jackson-datatype-jsr310</artifactId>
+            <version>2.9.2</version>
+        </dependency>
     </dependencies>
 
 </project>

+ 74 - 0
smsb-customer-manager-app/src/main/java/com/inspur/customer/config/JsonObjectMapper.java

@@ -0,0 +1,74 @@
+package com.inspur.customer.config;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
+import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
+import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
+import java.io.Serializable;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+
+/**
+ * 单例模式枚举实现 JsonObjectMapper
+ *
+ * @author liangke
+ */
+public enum JsonObjectMapper implements Serializable {
+    /**
+     * 实例
+     */
+    INSTANCE;
+
+    /**
+     * Jackson 的 ObjectMapper 对象
+     */
+    private final ObjectMapper objectMapper;
+
+    /**
+     * 枚举的构造函数
+     */
+    JsonObjectMapper() {
+        this.objectMapper = new ObjectMapper();
+
+        // 对于 Java 8+ 的 time 库的序列化与反序列化处理
+        JavaTimeModule javaTimeModule = new JavaTimeModule();
+
+        DateTimeFormatter localDateTimePattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(localDateTimePattern));
+        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(localDateTimePattern));
+
+        DateTimeFormatter localDatePattern = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(localDatePattern));
+        javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(localDatePattern));
+
+        DateTimeFormatter localTimePattern = DateTimeFormatter.ofPattern("HH:mm:ss");
+        javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(localTimePattern));
+        javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(localTimePattern));
+
+        objectMapper.registerModule(javaTimeModule);
+
+        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
+        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+    }
+
+    /**
+     * 获取单例对象
+     *
+     * @return ObjectMapper
+     */
+    public ObjectMapper getInstance() {
+        return objectMapper;
+    }
+}

+ 128 - 0
smsb-customer-manager-app/src/main/java/com/inspur/customer/config/RedisConfig.java

@@ -0,0 +1,128 @@
+package com.inspur.customer.config;
+
+import com.google.common.base.Joiner;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
+import org.springframework.cache.Cache;
+import org.springframework.cache.CacheManager;
+import org.springframework.cache.annotation.CachingConfigurerSupport;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.cache.interceptor.CacheErrorHandler;
+import org.springframework.cache.interceptor.KeyGenerator;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.cache.RedisCacheConfiguration;
+import org.springframework.data.redis.cache.RedisCacheManager;
+import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.RedisSerializationContext;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+import org.springframework.lang.Nullable;
+
+import java.time.Duration;
+
+/**
+ * Redis 配置
+ *
+ * @author liangke
+ */
+@Slf4j
+@Configuration
+@EnableCaching
+@AutoConfigureAfter(RedisAutoConfiguration.class)
+public class RedisConfig extends CachingConfigurerSupport {
+
+    /**
+     * 自定义缓存 key 的生成策略。默认的生成策略是不可读。
+     * 通过 Spring 的依赖注入特性进行自定义的配置注入并且此类是一个配置类可以更多程度的自定义配置
+     *
+     * @return KeyGenerator
+     */
+    @Bean
+    @Override
+    public KeyGenerator keyGenerator() {
+        return (target, method, params) -> Joiner.on(':').skipNulls().join(target.getClass().getName(), method.getName(), params);
+    }
+
+    /**
+     * 重写 errorHandler 方法,使 redis 异常后,不直接抛出异常,而是能继续执行函数,并且记录这次异常
+     *
+     * @return CacheErrorHandler
+     */
+    @Bean
+    @Override
+    public CacheErrorHandler errorHandler() {
+        return new CacheErrorHandler() {
+            @Override
+            public void handleCacheGetError(@Nullable RuntimeException exception, @Nullable Cache cache, @Nullable Object key) {
+                log.error("Get {} from redis Error", key, exception);
+            }
+
+            @Override
+            public void handleCachePutError(@Nullable RuntimeException exception, @Nullable Cache cache, @Nullable Object key, @Nullable Object value) {
+                log.error("Put {} from redis Error", key, exception);
+            }
+
+            @Override
+            public void handleCacheEvictError(@Nullable RuntimeException exception, @Nullable Cache cache, @Nullable Object key) {
+                log.error("Evict {} from redis Error", key, exception);
+            }
+
+            @Override
+            public void handleCacheClearError(@Nullable RuntimeException exception, @Nullable Cache cache) {
+                log.error("Clear from redis Error", exception);
+            }
+        };
+    }
+
+    /**
+     * 缓存配置管理器
+     *
+     * @return CacheManager
+     */
+    @Bean
+    public CacheManager cacheManager(LettuceConnectionFactory factory) {
+        log.info("redisCacheManager");
+        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
+        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
+        jackson2JsonRedisSerializer.setObjectMapper(JsonObjectMapper.INSTANCE.getInstance());
+        // 创建默认缓存配置对象
+        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
+            .entryTtl(Duration.ofHours(3L))
+            .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
+            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
+            .disableCachingNullValues();
+        return RedisCacheManager.builder(factory)
+            .cacheDefaults(config)
+            .transactionAware()
+            .build();
+    }
+
+    /**
+     * 获取缓存操作对象
+     *
+     * @return RedisTemplate
+     */
+    @Bean
+    public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory factory) {
+        //创建 Redis 缓存模板操作 RedisTemplate 对象
+        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
+        redisTemplate.setConnectionFactory(factory);
+        // 使用 Jackson2JsonRedisSerialize 替换默认序列化(默认采用的是 JDK 序列化)
+        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
+        jackson2JsonRedisSerializer.setObjectMapper(JsonObjectMapper.INSTANCE.getInstance());
+        // 设置键(key)的序列化采用 redisSerializer。
+        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
+        redisTemplate.setKeySerializer(redisSerializer);
+        redisTemplate.setHashKeySerializer(redisSerializer);
+        // 设置值(value)的序列化采用 jackson2JsonRedisSerializer。
+        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
+        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
+
+        redisTemplate.afterPropertiesSet();
+        return redisTemplate;
+    }
+}

+ 90 - 0
smsb-customer-manager-app/src/main/java/com/inspur/customer/service/authcode/AuthCodeServiceImpl.java

@@ -0,0 +1,90 @@
+package com.inspur.customer.service.authcode;
+
+import com.alibaba.cola.dto.Response;
+import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
+import com.google.common.collect.Lists;
+import com.inspur.customer.service.client.authcode.AuthCodeService;
+import com.inspur.customer.service.dto.AuthCodeCheckDTO;
+import com.inspur.customer.service.dto.AuthCodeDTO;
+import com.inspur.customer.service.dto.AuthCodeCheckResponse;
+import com.inspur.inform.client.email.SmsbEmailService;
+import com.inspur.inform.client.sms.SmsbSmsService;
+import com.inspur.inform.object.message.EmailMessage;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.springframework.data.redis.core.RedisTemplate;
+import javax.annotation.Resource;
+import java.util.concurrent.TimeUnit;
+
+
+/**@Description: 验证码相关功能实现类
+ * @version v1.0
+ * @author joe wan
+ * @date 2022/6/29 17:22
+ */
+@Slf4j
+@DubboService
+public class AuthCodeServiceImpl implements AuthCodeService {
+
+    @DubboReference
+    SmsbSmsService smsbSmsService;
+
+    @DubboReference
+    SmsbEmailService smsbEmailService;
+
+    @Resource
+    private RedisTemplate<String, String> redisTemplate;
+
+    /**@Description: 电话、邮件发送验证码
+     * @param[com.inspur.customer.service.dto.AuthCodeDTO]
+     * @return com.alibaba.cola.dto.Response
+     * @version v1.0
+     * @author joe wan
+     * @date 2022/6/29 17:20
+     */
+    public Response sendAuthCode(AuthCodeDTO authCodeDTO){
+        try{
+            //生成一个6位验证码
+            int authcode = (int)((Math.random() * 9 + 1) * 100000);
+            //发送邮件
+            EmailMessage emailMessage = new EmailMessage();
+            emailMessage.setSubject("浪潮安播云");
+            emailMessage.setEmailContent("【浪潮安播云】验证码:"+ authcode +"(有效期为5分钟),请勿泄露给他人,如非本人操作,请忽略此信息。 ");
+            emailMessage.setAddressees(Lists.newArrayList(authCodeDTO.getEmail()));
+            Boolean aBoolean = smsbEmailService.sendEmail(emailMessage);
+            if(aBoolean)redisTemplate.opsForValue().set("smsb:authcode:email:" + authCodeDTO.getEmail(), authcode + "", 5, TimeUnit.MINUTES);
+            //发送手机短信
+            SendSmsResponse sendPhoneNum = smsbSmsService.send("待定 SMS_154950909", authCodeDTO.getPhoneNum(), "浪潮安播云", "{\"MSRcode\":\"" + authCodeDTO + "\"}");
+            if ("OK".equals(sendPhoneNum.body.code)) {
+                redisTemplate.opsForValue().set("smsb:authcode:phoneNum:" + authCodeDTO.getPhoneNum(), authcode + "", 5, TimeUnit.MINUTES);
+            }
+        }catch (Exception e){
+            log.error("发送验证码报错 --》 {}", authCodeDTO);
+            return Response.buildFailure("999","发送失败!");
+        }
+        return Response.buildSuccess();
+    }
+
+    /**@Description: 电话、邮件验证码check
+     * @param[com.inspur.customer.service.dto.AuthCodeCheckDTO]
+     * @return com.inspur.customer.service.dto.AuthCodeCheckResponse
+     * @version v1.0
+     * @author joe wan
+     * @date 2022/6/30 17:56
+     */
+    public AuthCodeCheckResponse checkAuthCode(AuthCodeCheckDTO authCodeCheckDTO){
+
+        AuthCodeCheckResponse result = new AuthCodeCheckResponse();
+        if(StringUtils.isNotBlank(authCodeCheckDTO.getPhoneNumAuthCode())){
+            String authcodePhone = redisTemplate.opsForValue().get("smsb:authcode:phoneNum:" + authCodeCheckDTO.getPhoneNum());
+            if(authCodeCheckDTO.getPhoneNumAuthCode().equals(authcodePhone))result.setCheckPhoneNum(true);
+        }
+        if(StringUtils.isNotBlank(authCodeCheckDTO.getEmailAuthCode())){
+            String authcodeEmail = redisTemplate.opsForValue().get("smsb:authcode:email:" + authCodeCheckDTO.getEmail());
+            if(authCodeCheckDTO.getEmailAuthCode().equals(authcodeEmail))result.setCheckEmail(true);
+        }
+       return result;
+    }
+}

+ 10 - 0
smsb-customer-manager-client/pom.xml

@@ -35,6 +35,16 @@
             <groupId>org.springframework</groupId>
             <artifactId>spring-context</artifactId>
         </dependency>
+        <!--validation-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-validator</artifactId>
+            <version>6.1.5.Final</version>
+        </dependency>
     </dependencies>
 
 </project>

+ 32 - 0
smsb-customer-manager-client/src/main/java/com/inspur/customer/service/client/authcode/AuthCodeService.java

@@ -0,0 +1,32 @@
+package com.inspur.customer.service.client.authcode;
+
+import com.alibaba.cola.dto.Response;
+import com.inspur.customer.service.dto.AuthCodeCheckDTO;
+import com.inspur.customer.service.dto.AuthCodeDTO;
+import com.inspur.customer.service.dto.AuthCodeCheckResponse;
+
+/**@Description: 验证码相关
+ * @version v1.0
+ * @author joe wan
+ * @date 2022/6/29 14:13
+ */
+public interface AuthCodeService {
+
+    /**@Description: 电话、邮件发送验证码
+     * @param[com.inspur.customer.service.dto.AuthCodeDTO]
+     * @return com.alibaba.cola.dto.Response
+     * @version v1.0
+     * @author joe wan
+     * @date 2022/6/29 17:20
+     */
+    Response sendAuthCode(AuthCodeDTO authCodeDTO);
+
+    /**@Description: 电话、邮件验证码check
+     * @param[com.inspur.customer.service.dto.AuthCodeCheckDTO]
+     * @return com.inspur.customer.service.dto.AuthCodeCheckResponse
+     * @version v1.0
+     * @author joe wan
+     * @date 2022/6/30 17:56
+     */
+    AuthCodeCheckResponse checkAuthCode(AuthCodeCheckDTO authCodeCheckDTO);
+}

+ 23 - 0
smsb-customer-manager-client/src/main/java/com/inspur/customer/service/dto/AuthCodeCheckDTO.java

@@ -0,0 +1,23 @@
+package com.inspur.customer.service.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.Email;
+import javax.validation.constraints.Pattern;
+import java.io.Serializable;
+
+@Data
+public class AuthCodeCheckDTO implements Serializable {
+
+    @Email(message = "邮件格式错误")
+    private String email;
+
+    @Pattern(regexp = "1[3-9]\\d{9}", message = "手机号码格式错误")
+    private String phoneNum;
+
+    @Pattern(regexp = "\\\\d{6}", message = "请输入6位数字验证码!")
+    private String emailAuthCode;
+
+    @Pattern(regexp = "\\\\d{6}", message = "请输入6位数字验证码!")
+    private String phoneNumAuthCode;
+}

+ 19 - 0
smsb-customer-manager-client/src/main/java/com/inspur/customer/service/dto/AuthCodeCheckResponse.java

@@ -0,0 +1,19 @@
+package com.inspur.customer.service.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class AuthCodeCheckResponse implements Serializable {
+
+    /*
+        邮箱验证码,ture为验证正确,flase为验证错误
+     */
+    private boolean checkEmail;
+
+    /*
+        手机验证码,ture为验证正确,flase为验证错误
+     */
+    private boolean checkPhoneNum;
+}

+ 21 - 0
smsb-customer-manager-client/src/main/java/com/inspur/customer/service/dto/AuthCodeDTO.java

@@ -0,0 +1,21 @@
+package com.inspur.customer.service.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.Email;
+import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Size;
+import java.io.Serializable;
+
+@Data
+public class AuthCodeDTO implements Serializable {
+
+    @Email(message = "邮件格式错误")
+    private String email;
+
+    @Pattern(regexp = "1[3-9]\\d{9}", message = "手机号码格式错误")
+    private String phoneNum;
+
+    @Pattern(regexp = "\\\\d{6}", message = "请输入6位数字验证码!")
+    private String authCode;
+}

+ 9 - 2
smsb-customer-manager-start-web/src/main/resources/bootstrap.yml

@@ -1,9 +1,11 @@
 spring:
+  application:
+    name: smsb-customer-manager-web
   main:
     allow-bean-definition-overriding: true
     allow-circular-references: true
-  application:
-    name: smsb-customer-manager-web
+  profiles:
+    active: dev
   cloud:
     nacos:
       server-addr: 10.180.88.84:8060
@@ -12,3 +14,8 @@ spring:
       config:
         file-extension: yml
         refresh-enabled: true
+        group: smsb-customer-manager-web
+        namespace: 1f794295-ee51-492b-a001-04cda84b8fed
+      discovery:
+        enabled: true
+        namespace: 1f794295-ee51-492b-a001-04cda84b8fed