【业务功能篇93】微服务-springcloud-springboot-认证服务-注册功能-第三方短信验证API

news2024/10/7 6:50:30

商城认证服务

一、搭建认证服务环境

  结合我们前面介绍的商城的架构我们需要单独的搭建一个认证服务。

image.png

1.创建项目

  首先创建一个SpringBoot项目,然后添加对应的依赖

<?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.注册中心配置

  我们需要把认证服务注册到Nacos中,添加对应的依赖,然后完成对应的配置

# 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

放开Nacos注册中心

image.png

然后启动测试

image.png

3.登录和注册页面

  然后我们整理登录和注册的相关资源,首先把登录和注册的模板文件拷贝进项目

image.png

然后把对应的静态文件拷贝到Nginx中。

image.png

然后我们需要在host文件中添加对应的配置

image.png

修改Nginx的反向代理的配置

image.png

然后重启Nginx的服务image.png

然后修改网关服务

image.png

最后调整登录和注册页面的静态资源文件的路径.

注册服务的名称:msb-auth,启动对应的服务,测试

登录页面

image.png

注册页面

image.png

4.注册功能

4.1 手机验证码

  先处理验证码的页面,使其能够倒数操作

image.png

image.png

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 短信验证接口

  通过阿里云的短信服务来实现。我们直接购买0元15次就可以了。https://www.aliyun.com/

image.png

image.png

进入到对应的管理控制台,查看对应的信息

image.png

通过短信供应商提供的相关的编程语言的开发模板开发即可

image.png

供应商提供了对应的HttpUtils工具类,我们需要下载保存到我们自己的项目中。

image.png

然后封装对应的发送验证码的接口

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();
        }
    }
}

添加对应的属性信息

image.png

image.png

4.3 短信功能

  然后我们将短信功能串联起来

image.png

4.3.1 third服务

  我们需要在第三方服务中提供对外的接口服务

@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();
    }
}

image.png

4.3.2 认证服务

  我们需要在认证服务中通过feign来调用third中提供的短信服务,同时给客户端提供访问的接口

        <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>

放开注解

image.png

然后声明Feign的接口

image.png

定义对应的Controller

@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 客户端

  然后我们需要在页面中通过jQuery的异步提交来发送短信

image.png

4.3.4 验证码存储

  当我们把验证码通过短信的形式发送给你客户手机,然后我们需要把手机号和对应的验证码存储起来,后面可能会集群部署,这时我们把这个信息存在在Redis中。

image.png

添加配置

image.png

存储数据

image.png

image.png

搞定

4.3.5 60秒间隔

  针对验证码发送的间隔必须是60秒以上,这时我们可以在保存到Redis中的数据的值我们加上发送的时间来处理

image.png

模板页面也需要做出对应的处理

image.png

4.4 注册数据验证

  表单提交的注册数据我们通过JSR303来验证。

首先定义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;  // 验证码
}

然后就是控制器的逻辑代码

    @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";
    }

然后就是页面代码处理

image.png

image.png

验证码的校验

image.png

4.5 完整的注册功能

image.png

会员服务处理

控制器

   /**
     * 会员注册
     * @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();
    }

然后对应的Service

   /**
     * 完成会员的注册功能
     * @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);
    }

auth服务通过Fegin远程调用

image.png

远程调用

    @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";
    }

完成对应的服务注册

image.png

校验提示

image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/963419.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

勃艮第葡萄酒是如何分级的?

勃艮第葡萄酒来自一个同名的地区:勃艮第&#xff0c;它位于法国中东部&#xff0c;在西部的卢瓦尔河和东部的索恩河之间。该地区最大的城市是欧塞尔、第戎、马孔和内韦尔。由于地处国家中心&#xff0c;勃艮第属于大陆性气候&#xff0c;夏季炎热&#xff0c;冬季寒冷。这种气候…

Mac不想用iTerm2了怎么办

这东西真是让人又爱又恨&#xff0c;爱的是它的UI还真不错&#xff0c;恨的是它把我的环境给破坏啦&#xff01;让我每次启动终端之后都要重新source激活我的python环境&#xff0c;而且虚拟环境前面没有括号啦&#xff01;这怎么能忍&#xff01;在UI和实用性面前我断然选择实…

3D点云处理:提取指定圆环内的点(附源码)

文章目录 0. 测试效果1. 基本内容2. 代码实现文章目录:3D视觉个人学习目录微信:dhlddxB站: Non-Stop_目标:提取指定范围的点云0. 测试效果 红色为根据指定条件提取的点 1. 基本内容 要提取指定圆环内和指定高度范围内的点云,可以按照以下步骤进行操作: 定义圆环和高度参数…

区块链实验室(19) - 在新建的无标度网络中配置控制台

在前文区块链实验室(18) - 用FISCO BCOS架设1个无标度网络中架设了1个网络&#xff0c;这个网络还没有配置控制台。FISCO-BCOS技术文档给出了一个创建4节点的网络以及控制台&#xff0c;那个控制台不能直接用于该文的无标度网络&#xff0c;主要是因为控制台证书不匹配。 本文…

FPGA时序分析与约束(3)——时钟不确定性

一、前言 在之前的文章中&#xff0c;我们介绍了组合电路的时序和时序电路的时序问题&#xff0c;在阅读本文章之前&#xff0c;强烈推荐先阅读完本系列之前的文章&#xff0c;因为这是我们继续学习的理论的理论基础&#xff0c;前文链接&#xff1a; FPGA时序分析与约束&…

富士施乐S2110复印机先后提示代码045-313、092-910、092-668故障解决

故障描述 : 用户一台富士施乐S2110复印机使用过程中报错045-313,电话沟通分析可能是硒鼓出现了问题,本着负责的态度上门检查并确认故障;到用户处后先重新插拔一下硒鼓然后再重新开机进行测试,开机后能复印及打印几张然后后报错092-910 ,以为硒鼓没有安装好再次重插…

在CAD中批量测量线段的长度

我们经常会有批量测量线段长度的需求&#xff0c;但是线段太多了&#xff0c;一个个加属实浪费时间。网上对这方面也只是个别晦涩的解决方法&#xff0c;大部分无法实用&#xff0c;本文介绍了笔者认为一种最轻松的测量办法。 下图即我们需要测量的线段组&#xff0c;正常测肯定…

【JS】—闭包—双例对比法学习总结

一、选定知识点&#xff1a;闭包 二、指令学习 1. 闭包MDN的定义 闭包&#xff08;closure&#xff09;是一个函数以及其捆绑的周边环境状态&#xff08;lexical environment&#xff0c;词法环境&#xff09;的引用的组合。换而言之&#xff0c;闭包让开发者可以从内部函数…

Cordova Android 生成的 APK 中添加代码混淆

要在 Cordova Android 生成的 APK 中添加代码混淆&#xff0c;你可以按照以下步骤进行操作&#xff1a; 1. 在项目根目录下&#xff0c;找到 platforms/android/ 目录&#xff0c;进入该目录。 2. 打开 build.gradle 文件&#xff0c;并在 android { ... } 部分添加以下代码&…

在Windows10上编译grpc工程,得到protoc.exe和grpc_cpp_plugin.exe

grpc是google于2015年发布的一款跨进程、跨语言、开源的RPC(远程过程调用)技术。使用C/S模式&#xff0c;在客户端、服务端共享一个protobuf二进制数据。在点对点通信、微服务、跨语言通信等领域应用很广&#xff0c;下面介绍grpc在windows10上编译&#xff0c;这里以编译grpc …

肖sir__xftp安装使用__004

xftp 一、定义&#xff1a;Xftp是一款功能强大的FTP传输软件&#xff0c;主要用于文件的上传和下载&#xff0c;支持SFTP和FTP协议。Xftp在Windows系统上设计&#xff0c;但也可在Linux系统上使用。本文将详细介绍Xftp的功能和使用方法 二、Xftp的功能 1.文件传输与管理&#…

递归算法学习——电话号码的字母组成,括号生成,组合

目录 一&#xff0c;电话号码的字母组合 1.题意 2.例子 3.题目接口 4.解题代码和思路 代码&#xff1a; 思路&#xff1a; 二&#xff0c;括号的生成 1.题意 2.例子 3.题目接口 四&#xff0c;解题代码和思路 1.先写代码&#xff1a; 2.思路 三&#xff0c;组合 …

udig下载、安装及汉化,生成geoserver图层样式sld文件

uDig是一款开源免费的桌面地理信息系统框架软件。uDig汉化版主要采用RCP技术构建&#xff0c;内置的多专业的水文工具&#xff0c;拥有复杂专业的分析能力&#xff0c;既可以作为独立程序运行&#xff0c;还可以作为插件使用。 uDig是一个 open source (EPL and BSD) 桌面应用程…

volatile 关键字 与 CPU cache line 的效率问题

分析&回答 Cache Line可以简单的理解为CPU Cache中的最小缓存单位。目前主流的CPU Cache的Cache Line大小都是64Bytes。假设我们有一个512字节的一级缓存&#xff0c;那么按照64B的缓存单位大小来算&#xff0c;这个一级缓存所能存放的缓存个数就是512/64 8个。具体参见下…

微信小程序地图应用总结版

1.应用场景&#xff1a;展示公司位置&#xff0c;并打开第三方app&#xff08;高德&#xff0c;腾讯&#xff09;导航到目标位置。 &#xff08;1&#xff09;展示位置地图 uniapp官网提供了相关组件&#xff0c;uniapp-map组件 具体用法&#xff1a; html结构 <map sty…

文件夹如何隐藏加密?文件夹加密隐藏软件有哪些?

文件夹加密和文件夹隐藏都是保护文件夹数据安全的方法&#xff0c;我们可以将这两者结合&#xff0c;以实现更好的保护。那么&#xff0c;文件夹如何隐藏加密呢&#xff1f; 如何隐藏加密文件夹&#xff1f; 想要隐藏加密文件夹&#xff0c;我们可以通过以下两种方式来实现&am…

【算法竞赛宝典】读文章

【算法竞赛宝典】读文章 题目描述代码展示 题目描述 代码展示 //读文章 #include <iostream> #include <string.h>using namespace std;int main() {int i, j, upp, low, dig, spa, oth;char text[3][80];upp low dig spa oth 0;for (i 0; i < 3; i) {g…

Pyecharts数据可视化(一)

目录 1.Pyecharts简介 2.Pyecharts的常用方法 3.Pyecharts绘制柱状图 3.1 绘制并列柱状图 3.2 绘制水平直方图 1.Pyecharts简介 Pyecharts是一个用于创建交互式图表的Python库。它基于Echarts&#xff0c;一个强大的JavaScript图表库&#xff0c;Pyecharts允许Python开发者…

分享几个靠谱的网络项目,空闲时间就能月收益几千!

近几年来最大的感受就是赚钱越来越难了&#xff0c;对于上班族来说固定的那份工资比较有限&#xff0c;相信很多朋友们都想开拓一些副业&#xff0c;给自己增加一些收入&#xff0c;小编今天给大家推荐几个靠谱的最新项目分享给大家。 第一个&#xff1a;文案编辑 文案编辑是…

详解vue3中ref和reactive用法和区别

vue3中ref和reactive区别 1、前言2、基本用法2.1 ref2.2 reactive 3、ref和reactive定义数组对比3.1 ref定义数组3.1 reactive定义数组 4、ref 和reactive的区别 1、前言 ref和reactive是Vue3中用来实现数据响应式的API&#xff0c;一般情况下&#xff0c;ref定义基本数据类型…