小熊家务帮day5 客户管理模块1 (小程序认证,手机验证码认证等)

news2024/12/27 19:38:18

客户管理模块

  • 1.认证模块
    • 1.1 认证方式介绍
      • 1.1.1 小程序认证
      • 1.1.2 手机验证码登录
      • 1.1.3 账号密码认证
    • 1.2 小程序认证
      • 1.2.1 小程序申请
      • 1.2.2 创建客户后端工程jzo2o-customer
      • 1.2.3 开发部署前端
      • 1.2.4 小程序认证流程
        • 1.2.4.1 customer小程序认证接口设计
          • Controller层
          • Service层
          • 调用Publics模块获取openid
          • 查询数据库构建token
          • 保存token到微服务的ThreadLocal中
      • 1.2.5 手机验证码认证
        • 1.2.5.1 开发与部署app前端
        • 1.2.5.2 customer短信认证接口设计

1.认证模块

一般情况有用户交互的项目都有认证授权功能,首先要搞清楚两个概念:认证和授权。
认证: 就是校验用户的身份是否合法,常见的认证方式有账号密码登录、手机验证码登录等。
授权:则是该用户登录系统成功后当用户去点击菜单或操作数据时系统判断该用户是否有权限,有权限则允许继续操作,没有权限则拒绝访问。

本项目包括四个端:用户端(小程序)、服务端(app)、机构端(PC)、运营管理端(PC).
分别对应四类用户角色:家政需求方即c端用户,家政服务人员、家政服务公司(机构)、平台运营人员。

1.1 认证方式介绍

1.1.1 小程序认证

用户端通过小程序使用平台,初次使用小程序会进行认证,具体流程如下:
在这里插入图片描述

1.1.2 手机验证码登录

服务人员通过app登录采用手机验证码认证方式,输入手机号、发送验证码,验证码校验通过则认证通过,初次认证通过将自动注册服务人员信息。
在这里插入图片描述

1.1.3 账号密码认证

机构端认证方式是账号密码认证方式,通过pc浏览器进入登录界面输入账号和密码登录系统
机构端提供单独的注册页面,输入手机号,接收验证码进行注册

1.2 小程序认证

下边测试用户端小程序的认证流程,先参考微信官方提供的小程序登录流程先大概知道小程序认证流程需要几部分,如下图:
从图上可以看出小程序认证流程需要三部分:
小程序:即前端程序
开发者服务器:后端微服务程序。
微信接口服务:即微信服务器。
在这里插入图片描述
1.前端调用wx.login()获取登录凭证code
2.前端请求后端进行认证,发送code
3.后端请求微信获取openid,发送appid、app密钥、code参数,微信返回openid
4.后端生成认证成功凭证返回给前端。
5.前端存储用户认证成功凭证

1.2.1 小程序申请

开发小程序首先要申请小程序账号,参考官方文档:https://developers.weixin.qq.com/miniprogram/dev/framework/quickstart/getstart.html#%E7%94%B3%E8%AF%B7%E8%B4%A6%E5%8F%B7
通过阅读上述文档并且完成操作,本人已经完成小程序注册并保存好了密匙

1.2.2 创建客户后端工程jzo2o-customer

此处不展开了
具体就是新建工程,同步Gitee,修改nacos配置文件的小程序认证部分等等

1.2.3 开发部署前端

这部分也不再展开
在这里插入图片描述

1.2.4 小程序认证流程

整个过程包括三部分:
小程序:即前端程序
开发者服务器:后端微服务程序。
微信接口服务:即微信服务器。

具体的流程如下:
1.前端调用wx.login()获取登录凭证code
2.前端请求后端进行认证,发送code
3.后端请求微信获取openid
4.后端生成认证成功凭证返回给前端。
在这里插入图片描述
根据官方的认证流程我们定义本项目小程序认证的交互流程:
customer工程提供认证接口,publics工程作为一个公共服务提供与微信通信的接口。(抽取通用服务)
前端与cutomer交互不与publics交互。
在这里插入图片描述

1.2.4.1 customer小程序认证接口设计

首先认证的前端请求如下:
在这里插入图片描述

Controller层
@RestController("openLoginController")
@RequestMapping("/open/login")
@Api(tags = "白名单接口 - 客户登录相关接口")
public class LoginController {

    @Resource
    private ILoginService loginService;

    @PostMapping("/worker")
    @ApiOperation("服务人员/机构人员登录接口")
    public LoginResDTO loginForWorker(@RequestBody LoginForWorkReqDTO loginForWorkReqDTO) {

        if(UserType.INSTITUTION == loginForWorkReqDTO.getUserType()){
            return loginService.loginForPassword(loginForWorkReqDTO);
        }else{
            return loginService.loginForVerify(loginForWorkReqDTO);
        }

    }

    /**
     * c端用户登录接口
     */
    @PostMapping("/common/user")
    @ApiOperation("c端用户登录接口")
    public LoginResDTO loginForCommonUser(@RequestBody LoginForCustomerReqDTO loginForCustomerReqDTO) {
        return loginService.loginForCommonUser(loginForCustomerReqDTO);
    }

}
Service层
    @Override
    public LoginResDTO loginForCommonUser(LoginForCustomerReqDTO loginForCustomerReqDTO) {
        // code换openId
        OpenIdResDTO openIdResDTO = wechatApi.getOpenId(loginForCustomerReqDTO.getCode());
        if(ObjectUtil.isEmpty(openIdResDTO) || ObjectUtil.isEmpty(openIdResDTO.getOpenId())){
            // openid申请失败
            throw new CommonException(ErrorInfo.Code.LOGIN_TIMEOUT, ErrorInfo.Msg.REQUEST_FAILD);
        }
        CommonUser commonUser = commonUserService.findByOpenId(openIdResDTO.getOpenId());
        //如果未从数据库查到,需要新增数据
        if (ObjectUtil.isEmpty(commonUser)) {
            commonUser = BeanUtil.toBean(loginForCustomerReqDTO, CommonUser.class);
            long snowflakeNextId = IdUtil.getSnowflakeNextId();
            commonUser.setId(snowflakeNextId);
            commonUser.setOpenId(openIdResDTO.getOpenId());
            commonUser.setNickname("普通用户"+ RandomUtil.randomInt(10000,99999));
            commonUserService.save(commonUser);
        }else if(CoCummonStatusConstants.USER_STATUS_FREEZE == commonUser.getStatus()) {
            // 被冻结
            throw new CommonException(ErrorInfo.Code.ACCOUNT_FREEZED, commonUser.getAccountLockReason());
        }

        //构建token
        String token = jwtTool.createToken(commonUser.getId(), commonUser.getNickname(), commonUser.getAvatar(), UserType.C_USER);
        return new LoginResDTO(token);
    }
调用Publics模块获取openid

其中customer模块的OpenIdResDTO openIdResDTO = wechatApi.getOpenId(loginForCustomerReqDTO.getCode());代码就是调用publics模块的接口从而获取openid:

    @Resource
    private WechatService wechatService;

    @Override
    @GetMapping("/getOpenId")
    @ApiOperation("获取openId")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "code", value = "登录凭证", required = true, dataTypeClass = String.class)
    })
    public OpenIdResDTO getOpenId(@RequestParam("code") String code) {
        String openId = wechatService.getOpenid(code);
        return new OpenIdResDTO(openId);
    }

而在其中调用了第三方模块的wechatService.getOpenid接口,其中内容如下:

    public String getOpenid(String code) {
        Map<String, Object> requestUrlParam = this.getAppConfig();
        requestUrlParam.put("js_code", code);
        String result = HttpUtil.get("https://api.weixin.qq.com/sns/jscode2session?grant_type=authorization_code", requestUrlParam);
        log.info("getOpenid result:{}", result);
        JSONObject jsonObject = JSONUtil.parseObj(result);
        if (ObjectUtil.isNotEmpty(jsonObject.getInt("errcode"))) {
            throw new ServerErrorException(jsonObject.getStr("errmsg"));
        } else {
            return jsonObject.getStr("openid");
        }
    }

功能很简单,通过调用微信官方api获取到数据,从数据中解析出openid返回publics模块,最后返回到customer模块

查询数据库构建token

customer模块拿到openid后开始查询数据库:

CommonUser commonUser = commonUserService.findByOpenId(openIdResDTO.getOpenId());

在这里插入图片描述
假如数据库没查到,说明第一次使用,那么就会自动注册:

        if (ObjectUtil.isEmpty(commonUser)) {
            commonUser = BeanUtil.toBean(loginForCustomerReqDTO, CommonUser.class);
            long snowflakeNextId = IdUtil.getSnowflakeNextId();
            commonUser.setId(snowflakeNextId);
            commonUser.setOpenId(openIdResDTO.getOpenId());
            commonUser.setNickname("普通用户"+ RandomUtil.randomInt(10000,99999));
            commonUserService.save(commonUser);
        }

那么如果查到了,说明注册过了,就会生成token:

        //构建token
        String token = jwtTool.createToken(commonUser.getId(), commonUser.getNickname(), commonUser.getAvatar(), UserType.C_USER);
        return new LoginResDTO(token);
保存token到微服务的ThreadLocal中

通过上述流程,前端就获得了token:
在这里插入图片描述
当拿到了token后,就会携带token去访问网关:

        // 2.获取token解析工具JwtTool工具
        // 2.1.获取token
        String token = GatewayWebUtils.getRequestHeader(exchange, HEADER_TOKEN);
        if (StringUtils.isEmpty(token)) {
            return GatewayWebUtils.toResponse(exchange,
                    HttpStatus.FORBIDDEN.value(),
                    ErrorInfo.Msg.REQUEST_FORBIDDEN);
        }
        // 2.2.获取tokenKey
        String tokenKey = applicationProperties.getTokenKey().get(JwtTool.getUserType(token) + "");
        if (StringUtils.isEmpty(token)) {
            return GatewayWebUtils.toResponse(exchange,
                    HttpStatus.FORBIDDEN.value(),
                    ErrorInfo.Msg.REQUEST_FORBIDDEN);
        }

如果网关校验token通过,就会放行到微服务,微服务就会将token放入ThreadLocal中,由于所有的微服务都需要走这个流程(将token放入ThreadLocal中),因此抽取这部分到MVC模块的拦截器:

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 1.尝试获取头信息中的用户信息
        String userInfo = request.getHeader(HeaderConstants.USER_INFO);
        // 2.判断是否为空
        if (userInfo == null) {
            return true;
        }
        try {
            // 3.base64解码用户信息
            String decodeUserInfo = Base64Utils.decodeStr(userInfo);
            CurrentUserInfo currentUserInfo = JsonUtils.toBean(decodeUserInfo, CurrentUserInfo.class);

            // 4.转为用户id并保存
            UserContext.set(currentUserInfo);
            return true;
        } catch (NumberFormatException e) {
            log.error("用户身份信息格式不正确,{}, 原因:{}", userInfo, e.getMessage());
            return true;
        }
    }

其中ThreadLocal定义如下:

public class UserContext {
    private static final ThreadLocal<CurrentUserInfo> THREAD_LOCAL_USER = new ThreadLocal<>();

    /**
     * 获取当前用户id
     *
     * @return 用户id
     */
    public static Long currentUserId() {
        return THREAD_LOCAL_USER.get().getId();
    }

    public static CurrentUserInfo currentUser() {
        return THREAD_LOCAL_USER.get();
    }

    /**
     * 设置当前用户id
     *
     * @param currentUserInfo 当前用户信息
     */
    public static void set(CurrentUserInfo currentUserInfo) {
        THREAD_LOCAL_USER.set(currentUserInfo);
    }

    /**
     * 清理当前线程中的用户信息
     */
    public static void clear(){
        THREAD_LOCAL_USER.remove();
    }
}

那么微服务之后获取token只需要从ThreadLocal获取即可
之后相信大家对于本项目的认证流程很熟悉了:
在这里插入图片描述

1.2.5 手机验证码认证

1.2.5.1 开发与部署app前端

开发和部署细节省略
在这里插入图片描述

1.2.5.2 customer短信认证接口设计

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

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

相关文章

The 2022 ICPC Asia Nanjing Regional Contest - External G

题目链接:Problem - D - Codeforces 写在前面&#xff1a;今天的训练赛打的稀碎&#xff0c;一道稍微难一点的签到题就把我难住了&#xff0c;看完题解确实感觉不难&#xff0c;看来题目还是刷太少了。 回归正题 题意&#xff1a; 思路&#xff1a;尽量让分子大&#xff0c;分…

操作系统实验三 可变分区内存分配首次适应算法模拟

实验三 可变分区内存分配首次适应算法模拟 实验内容 模拟内存分配&#xff0c;了解并掌握动态分区分配中所用的数据结构、分区分配算法&#xff0c;深刻理解首次适应内存分配算法。 模拟实现可变分区内存分配首次适应算法&#xff1b;空闲分区表要求有空闲块的起始地址、大小…

LLama学习记录

学习前&#xff1a; 五大问题&#xff1a; 为什么SwiGLU激活函数能够提升模型性能&#xff1f;RoPE位置编码是什么&#xff1f;怎么用的&#xff1f;还有哪些位置编码方式&#xff1f;GQA&#xff08;Grouped-Query Attention, GQA&#xff09;分组查询注意力机制是什么&…

使用Python发送电子邮件

大家好&#xff0c;当我们需要迅速、方便地与他人沟通时&#xff0c;电子邮件是无疑是一种不可或缺的通信工具。无论是在个人生活中还是工作场合&#xff0c;电子邮件都是我们日常生活中的重要组成部分。它不仅能够传递文字信息&#xff0c;还可以发送附件、链接和嵌入式多媒体…

AJAX基础知识

定义 Ajax 异步 JavaScript 和 XML &#xff08; async javascript and xml &#xff09;&#xff0c;使用 Ajax 技术网页应用能够快速地将数据更新呈现在用户界面上&#xff0c;而不需要重载&#xff08;刷新&#xff09;整个页面&#xff0c;这使得程序能够更快地回应用户的操…

6、xss-labs之level8

1、测试分析 传入123查看页面源码&#xff0c;发现传入的值传给了value和a标签的href&#xff0c;并且对特殊字符<>" 都进行了HTML实体化&#xff0c;对于大小写进行了转化&#xff0c;过滤掉了src、data、onfocus、href、script、"&#xff08;双引号&#…

JAVA学习路线图

计算机网课资料分享群&#xff1a;710895979

每天写两道(二)LRU缓存、

146.LRU 缓存 . - 力扣&#xff08;LeetCode&#xff09; 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类&#xff1a; LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 key 存在于缓存…

蓝桥杯第1022题 玩具蛇 基础DFS C++ Java

题目 思路和解题方法 问题理解&#xff1a;此题要求找出将一条由16节正方形构成的玩具蛇放入4x4的方格中的不同方式数。每节蛇可以是直线或直角转弯&#xff0c;且蛇的形状需要完全覆盖盒子里的16个格子&#xff0c;每个格子仅被蛇的一个部分占据。 状态表示&#xff1a;使用一…

Mesa软件框架以及重要数据结构分析

Mesa软件框架以及重要数据结构分析 引言 Mesa的实现比较复杂&#xff0c;其中还有许多的数据结构之间的关系逻辑还不是很清楚。感觉分析了又没有分析一样&#xff0c;这里我们再理一理&#xff01; 1.1 Mesa下EGL/GL核心数据结构和层级关系 MESA的核心数据结构很多很复杂&#…

猜猜我是谁游戏

猜谜过程 在TabControl控件中&#xff0c;第一个tab中放了一个PictureBox&#xff0c;里面有一张黑色的图片。 玩家点击显示答案按钮&#xff0c;切换图片。 设计器 private void button1_Click(object sender, EventArgs e){this.pictureBox1.Image Image.FromFile(&qu…

多模态大模型:系统、趋势与问题

引言 多模态大模型是当今人工智能领域的热门方向之一。它不仅能处理文本&#xff0c;还能理解和生成图像、视频、语音等多种模态的数据。这种能力使得多模态大模型在自然语言处理、计算机视觉等多个领域展示出巨大的潜力和应用价值。那么&#xff0c;多模态大模型是如何训练出…

【LeetCode刷题】滑动窗口解决问题:串联所有单词的子串(困难)、最小覆盖子串(困难)

【LeetCode刷题】Day 10 题目1&#xff1a;30. 串联所有单词的子串&#xff08;困难&#xff09;思路分析&#xff1a;思路1&#xff1a;滑动窗口哈希map 题目2&#xff1a;LCR 017.最小覆盖子串思路分析思路1&#xff1a;滑动窗口哈希表 题目1&#xff1a;30. 串联所有单词的子…

MyBatis学习笔记(周五前学完)

MyBatis-Plus是一个MyBatis的增强工具。在MyBatis的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。 通过MyBatis-Plus来进行数据插入时&#xff0c;它默认会 使用雪花算法来生成id&#xff0c;长度比较长 增删改的返回值都是统一的&#xff0c;影响的只有行数。…

Matplotlib绘图指南:从基础绘图到多子图展示

目录 前言 导入模块 第一点&#xff1a;绘制图像 第二点&#xff1a;保存图像 第三点&#xff1a;多图形的绘制 第四点&#xff1a;绘制多子图 总结 前言 在数据可视化中&#xff0c;Matplotlib是一款强大的Python库&#xff0c;提供了丰富的功能来绘制各种类型的图表。…

Notepad++不显示CRLF的方法

View -> Show Symbol -> 去掉勾选 Show All Characters

[机缘参悟-191] - 《道家-水木然人间清醒1》读书笔记 -14- 关系界限 - 经济和人格上的独立,走向成熟的必经之路,才能更好的谈其他情感(IT)

目录 前言&#xff1a; 1、“友善的孤独者” 2、“外向的孤独者” 3、道不同不相为谋 4、警惕依赖 5、完整独立的个体 6、不必纠正他人的错误&#xff0c;除非他影响了你 7、不再期待别人能理解自己&#xff0c;只有高维向下兼容你的人才能理解你 8、只有高维和同频的…

有限元之有限元法的实现

目录 一、单元刚度矩阵及单元荷载 二、总刚度矩阵及总荷载的合成 三、边界条件处理 四、算例实现 4.1 C代码 4.2 计算结果 五、结论 前三节我们介绍了有限元的基本概念、变分理论及有限元空间的构造&#xff0c;本节我们探讨如何实现有限元法。我们继续以二维椭圆型方程…

5W 1.5KVDC、3KVDC 宽电压输入 DC/DC 电源模块——TP05DA 系列,广泛应用于通信、铁路等设备中

TP05DA系列电源模块额定输出功率为5W&#xff0c;外形尺寸为31.75*20.32*10.65&#xff0c;应用于2:1及4:1电压输入范围 9V-18V、18V-36V、36V-72V、9V-36V和18V-72VDC的输入电压环境&#xff0c;输出电压精度可达1%&#xff0c;具有输出短路保护等功能&#xff0c;可广泛应用于…

Apache、Nginx、IIS文件解析漏洞

目录 1、文件解析漏洞介绍 2、Apache相关的解析漏洞 &#xff08;1&#xff09;多后缀解析漏洞 &#xff08;2&#xff09;Apache配置问题 &#xff08;3&#xff09;换行符解析漏洞 &#xff08;4&#xff09;罕见后缀解析 3、Nginx相关的解析漏洞 &#xff08;1&…