[Capítulo 94 de la función empresarial] Microservicio-springcloud-springboot-Servicio de autenticación-Función de registro-API de verificación de SMS de terceros

Servicio de certificación de centros comerciales.

1. Construir un entorno de servicios de certificación

  En combinación con la arquitectura del centro comercial que presentamos anteriormente, necesitamos crear un servicio de autenticación independiente.

imagen.png

1.Crear proyecto

  Primero cree un proyecto SpringBoot y luego agregue las dependencias correspondientes

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.12</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.msb.mall</groupId>
    <artifactId>mall-auth-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>mall-auth_server</name>
    <description>认证服务</description>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.1</spring-cloud.version>
    </properties>
    <dependencies>
        <!-- 公共依赖 -->
        <dependency>
            <groupId>com.msb.mall</groupId>
            <artifactId>mall-commons</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <exclusions>
                <exclusion>
                    <groupId>com.baomidou</groupId>
                    <artifactId>mybatis-plus-boot-starter</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

2. Configuración del centro de registro

  Necesitamos registrar el servicio de autenticación en Nacos, agregar las dependencias correspondientes y luego completar la configuración correspondiente.

# Nacos服务注册
spring:
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.56.100:8848
  application:
    name: mall-auth_server
  # 统一的全局的--设置服务器响应给客户端的日期时间格式
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
  thymeleaf:
    cache: false # 关闭Thymeleaf的缓存
server:
  port: 30000

Liberar el centro de registro de Nacos

imagen.png

Luego comienza la prueba.

imagen.png

3. Página de inicio de sesión y registro

  Luego organizamos los recursos relacionados para el inicio de sesión y el registro. Primero, copiamos los archivos de plantilla de inicio de sesión y registro en el proyecto.

imagen.png

Luego copie los archivos estáticos correspondientes a Nginx.

imagen.png

Luego necesitamos agregar la configuración correspondiente al archivo host.

imagen.png

Modificar la configuración del proxy inverso de Nginx

imagen.png

Luego reinicie el servicio Nginximagen.png

Luego modifique el servicio de puerta de enlace.

imagen.png

Finalmente, ajuste las rutas a los archivos de recursos estáticos de las páginas de inicio de sesión y registro.

Registre el nombre del servicio: msb-auth, inicie el servicio correspondiente y pruebe

página de inicio de sesión

imagen.png

pagina de registro

imagen.png

4.Función de registro

4.1 Código de verificación del teléfono móvil

  Procese primero la página del código de verificación para habilitar la operación de cuenta regresiva

imagen.png

imagen.png

código JS

$(function(){
    
    
				$("#sendCode").click(function(){
    
    
					if($(this).hasClass("d1")){
    
    
						// 说明正在倒计时
					}else{
    
    
						// 给指定的手机号发送验证码
						timeoutChangeStyle()
					}

				});
			})
			var num = 10
			function timeoutChangeStyle(){
    
    
				$("#sendCode").attr("class","d1")
				if(num == 0){
    
    
					// 说明1分钟到了,可以再次发送验证码了
					$("#sendCode").text("发送验证码")
					num= 10;
					$("#sendCode").attr("class","")
				}else{
    
    
					setTimeout('timeoutChangeStyle()',1000)
					$("#sendCode").text(num+"s后再次发送")
				}

				num --;
			}

4.2 Interfaz de verificación por SMS

  Se realiza a través del servicio de SMS de Alibaba Cloud. Podemos comprar 0 yuanes 15 veces directamente. https://www.aliyun.com/

imagen.png

imagen.png

Ingrese a la consola de administración correspondiente y visualice la información correspondiente.

imagen.png

Se puede desarrollar a través de la plantilla de desarrollo del lenguaje de programación correspondiente proporcionada por el proveedor de SMS.

imagen.png

El proveedor proporciona la clase de herramienta HttpUtils correspondiente, que debemos descargar y guardar en nuestro propio proyecto.

imagen.png

Luego encapsule la interfaz correspondiente para enviar códigos de verificación.

package com.msb.mall.third.utils;

import lombok.Data;
import org.apache.http.HttpResponse;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * 短信组件
 */
@ConfigurationProperties(prefix = "spring.cloud.alicloud.sms")
@Data
@Component
public class SmsComponent {
    
    

    private String host;
    private String path;
    private String method = "POST";
    private String appCode;

    /**
     * 发送短信验证码
     * @param phone 发送的手机号
     * @param code 发送的短信验证码
     */
    public void sendSmsCode(String phone,String code){
    
    
        Map<String, String> headers = new HashMap<String, String>();
        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
        headers.put("Authorization", "APPCODE " + appCode);
        //根据API的要求,定义相对应的Content-Type
        headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        Map<String, String> querys = new HashMap<String, String>();
        Map<String, String> bodys = new HashMap<String, String>();
        bodys.put("content", "code:"+code);
        bodys.put("phone_number", phone);
        bodys.put("template_id", "TPL_0000");


        try {
    
    
            HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
            System.out.println(response.toString());
            //获取response的body
            //System.out.println(EntityUtils.toString(response.getEntity()));
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }
}

Agregar información de atributo correspondiente

imagen.png

imagen.png

4.3 Función SMS

  Luego concatenamos la función SMS.

imagen.png

4.3.1 terceros servicios

  Necesitamos proporcionar servicios de interfaz externa en servicios de terceros.

@RestController
public class SMSController {
    
    

    @Autowired
    private SmsComponent smsComponent;

    /**
     * 调用短信服务商提供的短信API发送短信
     * @param phone
     * @param code
     * @return
     */
    @GetMapping("/sms/sendcode")
    public R sendSmsCode(@RequestParam("phone") String phone,@RequestParam("code") String code){
    
    
        smsComponent.sendSmsCode(phone,code);
        return R.ok();
    }
}

imagen.png

4.3.2 Servicio de autenticación

  Necesitamos llamar al servicio de SMS proporcionado por terceros mediante fingir en el servicio de autenticación y, al mismo tiempo, proporcionar una interfaz de acceso para el cliente.

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>

Publicar anotaciones

imagen.png

Luego declara la interfaz de Feign

imagen.png

Definir el controlador correspondiente

@Controller
public class LoginController {
    
    


    @Autowired
    private ThirdPartFeginService thirdPartFeginService;

    @ResponseBody
    @GetMapping("/sms/sendCode")
    public R sendSmsCode(@RequestParam("phone") String phone){
    
    
        // 生成随机的验证码
        String code = UUID.randomUUID().toString().substring(0, 5);
        thirdPartFeginService.sendSmsCode(phone,code);
        return R.ok();
    }
}

4.3.3 Cliente

  Luego necesitamos enviar mensajes de texto a través del envío asincrónico de jQuery en la página.

imagen.png

4.3.4 Almacenamiento del código de verificación

  Cuando enviamos el código de verificación al teléfono móvil de su cliente en forma de SMS, necesitamos almacenar el número de teléfono móvil y el código de verificación correspondiente, que puede implementarse en un grupo más adelante. En este momento, almacenamos esta información en Redis.

imagen.png

Agregar configuración

imagen.png

Almacenamiento de datos

imagen.png

imagen.png

Hecho

4.3.5 Intervalo de 60 segundos

  El intervalo de envío de códigos de verificación debe ser superior a 60 segundos, en este momento podemos sumar el tiempo de envío al valor de los datos guardados en Redis.

imagen.png

Las páginas de plantilla también deben procesarse en consecuencia.

imagen.png

4.4 Verificación de datos de registro

  Verificamos los datos de registro enviados a través del formulario a través de JSR303.

Primero defina el objeto VO

package com.msb.mall.vo;

import lombok.Data;
import org.hibernate.validator.constraints.Length;

import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;

/**
 * 注册用户的VO对象
 */
@Data
public class UserRegisterVo {
    
    

    @NotEmpty(message = "账号不能为空")
    @Length(min = 3,max = 15,message = "账号必须是3~15位")
    private String userName; // 账号

    @NotEmpty(message = "密码不能为空")
    @Length(min = 3,max = 15,message = "密码必须是3~15位")
    private String password; // 密码

    @NotEmpty(message = "手机号不能为空")
    @Pattern(regexp = "^[1][3-9][0-9]{9}$",message = "手机号不合法")
    private String phone;  // 手机号

    @NotEmpty(message = "验证码不能为空")
    private String code;  // 验证码
}

Luego está el código lógico del controlador.

    @PostMapping("/sms/register")
    public String register(@Valid UserRegisterVo vo, BindingResult result, Model model){
    
    
        if(result.hasErrors()){
    
    
            // 表示提交的数据不合法
            List<FieldError> fieldErrors = result.getFieldErrors();
            Map<String,String> map = new HashMap<>();
            for (FieldError fieldError : fieldErrors) {
    
    
                String field = fieldError.getField();
                String defaultMessage = fieldError.getDefaultMessage();
                map.put(field,defaultMessage);
            }
            model.addAttribute("error",map);
            return "/reg";
        }
        // 表单提交的注册的数据是合法的

        return "redirect:/login.html";
    }

Luego está el procesamiento del código de la página.

imagen.png

imagen.png

Verificación del código de verificación.

imagen.png

4.5 Función de registro completa

imagen.png

Procesamiento de servicios para miembros

controlador

   /**
     * 会员注册
     * @return
     */
    @PostMapping("/register")
    public R register(@RequestBody MemberReigerVO vo){
    
    
        try {
    
    
            memberService.register(vo);
        }catch (UsernameExsitException exception){
    
    
            return R.error(BizCodeEnume.USERNAME_EXSIT_EXCEPTION.getCode(),
                    BizCodeEnume.USERNAME_EXSIT_EXCEPTION.getMsg());
        }catch (PhoneExsitExecption exsitExecption) {
    
    
            return R.error(BizCodeEnume.PHONE_EXSIT_EXCEPTION.getCode(),
                    BizCodeEnume.PHONE_EXSIT_EXCEPTION.getMsg());
        }catch (Exception e){
    
    
            return R.error(BizCodeEnume.UNKNOW_EXCEPTION.getCode(),
                    BizCodeEnume.UNKNOW_EXCEPTION.getMsg());
        }

        return R.ok();
    }

Luego el Servicio correspondiente

   /**
     * 完成会员的注册功能
     * @param vo
     */
    @Override
    public void register(MemberReigerVO vo) throws PhoneExsitExecption,UsernameExsitException{
    
    
        MemberEntity entity = new MemberEntity();
        // 设置会员等级 默认值
        MemberLevelEntity memberLevelEntity = memberLevelService.queryMemberLevelDefault();
        entity.setLevelId(memberLevelEntity.getId()); // 设置默认的会员等级

        // 添加对应的账号和手机号是不能重复的
        checkUsernameUnique(vo.getUserName());
        checkPhoneUnique(vo.getPhone());

        entity.setUsername(vo.getUserName());
        entity.setMobile(vo.getPhone());

        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String encode = encoder.encode(vo.getPassword());
        // 需要对密码做加密处理
        entity.setPassword(encode);
         // 设置其他的默认值
        this.save(entity);
    }

El servicio de autenticación se llama de forma remota a través de Fegin.

imagen.png

llamada remota

    @PostMapping("/sms/register")
    public String register(@Valid UserRegisterVo vo, BindingResult result, Model model){
    
    
        Map<String,String> map = new HashMap<>();
        if(result.hasErrors()){
    
    
            // 表示提交的数据不合法
            List<FieldError> fieldErrors = result.getFieldErrors();

            for (FieldError fieldError : fieldErrors) {
    
    
                String field = fieldError.getField();
                String defaultMessage = fieldError.getDefaultMessage();
                map.put(field,defaultMessage);
            }
            model.addAttribute("error",map);
            return "/reg";
        }else{
    
    
            // 验证码是否正确
             String code = (String)redisTemplate.opsForValue().get(SMSConstant.SMS_CODE_PERFIX + vo.getPhone());
            code = code.split("_")[0];
            if(!code.equals(vo.getCode())){
    
    
                // 说明验证码不正确
                map.put("code","验证码错误");
                model.addAttribute("error",map);
                return "/reg";
            }else{
    
    
                // 验证码正确  删除验证码
                redisTemplate.delete(SMSConstant.SMS_CODE_PERFIX + vo.getPhone());
                // 远程调用对应的服务 完成注册功能
                R r = memberFeginService.register(vo);
                if(r.getCode() == 0){
    
    
                    // 注册成功
                    return "redirect:http://msb.auth.com/login.html";
                }else{
    
    
                    // 注册失败
                    map.put("msg",r.getCode()+":"+r.get("msg"));
                    model.addAttribute("error",map);
                    return "/reg";
                }
            }
        }



        //return "redirect:/login.html";
    }

Completar el registro de servicio correspondiente

imagen.png

Mensaje de verificación

imagen.png

Supongo que te gusta

Origin blog.csdn.net/studyday1/article/details/132637223
Recomendado
Clasificación