小熊家务帮day5-day7 客户管理模块1 (小程序认证,手机验证码认证,账号密码认证,修改密码,找回密码等)

客户管理模块

  • 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短信认证接口设计
          • 需求分析
          • Controller层
          • Service层
      • 1.2.6 账号密码验证
        • 1.2.6.1 前端设计和部署
        • 1.2.6.2 customer账号密码验证接口设计
          • Controller设计
          • Service层设计
          • 顺便复习下BCrypt加密
      • 1.2.7 注册功能实现
        • 1.2.7.1 需求
        • 1.2.7.2 Costomer注册功能接口实现
          • Controller开发
          • Service开发
          • 演示
      • 1.2.8 找回密码功能
        • 1.2.8.1 需求
        • 1.2.8.2 Costomer找回密码功能接口实现
          • Controller开发
          • Service开发
          • 演示

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短信认证接口设计
需求分析

首先散户打开app,会输入手机号,点击获取验证码
在这里插入图片描述
之后会发出这个请求:
在这里插入图片描述
散户输入验证码后,点击登录即可进入主界面
在这里插入图片描述
短信验证流程如下:
在这里插入图片描述
那么下面我去实现这个功能

Controller层

发送验证码:

@RestController
@RequestMapping("/sms-code")
@Api(tags = "验证码相关接口")
public class SmsCodeController {
    @Resource
    private ISmsCodeService smsCodeService;

    @PostMapping("/send")
    @ApiOperation("发送短信验证码")
    public void smsCodeSend(@RequestBody SmsCodeSendReqDTO smsCodeSendReqDTO) {
        smsCodeService.smsCodeSend(smsCodeSendReqDTO);
    }
}

验证验证码:

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

    }
Service层

当用户点击了发送验证码后,首先会调用Public模块的服务,生成一个随机的验证码存储在redis中为验证做准备:

    @Override
    public void smsCodeSend(SmsCodeSendReqDTO smsCodeSendReqDTO) {
        if(StringUtils.isEmpty(smsCodeSendReqDTO.getPhone()) || StringUtils.isEmpty(smsCodeSendReqDTO.getBussinessType())) {
            log.debug("不能发送短信验证码,phone:{},bussinessType:{}", smsCodeSendReqDTO.getPhone(), smsCodeSendReqDTO.getBussinessType());
            return;
        }
        String redisKey = String.format(CommonRedisConstants.RedisKey.VERIFY_CODE, smsCodeSendReqDTO.getPhone(), smsCodeSendReqDTO.getBussinessType());
        // 取6位随机数
//        String verifyCode = (int)(Math.random() * 1000000) + "";
        String verifyCode = "123456";//为方便测试固定为123456
        log.info("向手机号{}发送验证码{}",smsCodeSendReqDTO.getPhone(),verifyCode);
        //todo调用短信平台接口向指定手机发验证码...
        //短信验证码有效期5分钟
        redisTemplate.opsForValue().set(redisKey, verifyCode, 300, TimeUnit.SECONDS);
    }

当用户输入验证码后,点击登录按钮则进行校验:
这次是调用Customer模块的服务
在这里插入图片描述
发送的请求参数是手机号,验证码以及验证身份的代码,收到请求后,先判空,若不为空,则交由Public模块去验证验证码的正确性,假如验证码没错,那么检查用户是否冻结或者没有注册,若没有注册,则自动注册,存入数据库,生成并返回token:

    @Override
    public LoginResDTO loginForVerify(LoginForWorkReqDTO loginForWorkReqDTO) {

        // 数据校验
        if(StringUtils.isEmpty(loginForWorkReqDTO.getVeriryCode())){
            throw new BadRequestException("验证码错误,请重新获取");
        }
        //远程调用publics服务校验验证码是否正确
        boolean verifyResult = smsCodeApi.verify(loginForWorkReqDTO.getPhone(), SmsBussinessTypeEnum.SERVE_STAFF_LOGIN, loginForWorkReqDTO.getVeriryCode()).getIsSuccess();
        if(!verifyResult) {
            throw new BadRequestException("验证码错误,请重新获取");
        }
        // 登录校验
        // 根据手机号和用户类型获取服务人员或机构信息
        ServeProvider serveProvider = serveProviderService.findByPhoneAndType(loginForWorkReqDTO.getPhone(), loginForWorkReqDTO.getUserType());
        // 账号禁用校验
        if(serveProvider != null && CommonStatusConstants.USER_STATUS_FREEZE == serveProvider.getStatus()) {
            throw new CommonException(ErrorInfo.Code.ACCOUNT_FREEZED, serveProvider.getAccountLockReason());
        }
        // 自动注册
        if(serveProvider == null) {
            serveProvider = serveProviderService.add(loginForWorkReqDTO.getPhone(), UserType.WORKER, null);
        }

        // 生成登录token
        String token = jwtTool.createToken(serveProvider.getId(), serveProvider.getName(), serveProvider.getAvatar(), loginForWorkReqDTO.getUserType());
        return new LoginResDTO(token);
    }

Public模块校验代码如下:
首先根据手机号和人员类型拼接出key,从Redis取出相应的验证码,之后进行一个校验,由于验证码只能用一次,通过校验则立马删除Redis的该条记录

    @Override
    public boolean verify(String phone, SmsBussinessTypeEnum bussinessType, String verifyCode) {
        // 1.验证前准备
        String redisKey = String.format(CommonRedisConstants.RedisKey.VERIFY_CODE, phone, bussinessType.getType());
        String verifyCodeInRedis = redisTemplate.opsForValue().get(redisKey);

        // 2.短验验证,验证通过后删除code,code只能使用一次
        boolean verifyResult = StringUtils.isNotEmpty(verifyCode) && verifyCode.equals(verifyCodeInRedis);
        if(verifyResult) {
            redisTemplate.delete(redisKey);
        }
        return verifyResult;
    }

所以大家应该理解了下图:
在这里插入图片描述

1.2.6 账号密码验证

1.2.6.1 前端设计和部署

在这里插入图片描述

1.2.6.2 customer账号密码验证接口设计
Controller设计
    @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);
        }

    }
Service层设计

首先会进行判空,若不为空,则根据账号去查数据库,以及进行密码校验(BCrypt加密),若通过则生成并返回token

    @Override
    public LoginResDTO loginForPassword(LoginForWorkReqDTO loginForWorkReqDTO) {
        // 1.数据校验
        if(StringUtils.isEmpty(loginForWorkReqDTO.getPassword())) {
            throw new BadRequestException("请输入密码");
        }

        // 2.登录校验
        // 2.1.根据手机号和用户类型获取服务人员或机构信息
        ServeProvider serveProvider = serveProviderService.findByPhoneAndType(loginForWorkReqDTO.getPhone(), loginForWorkReqDTO.getUserType());
        // 账号禁用校验
        if(serveProvider != null && CommonStatusConstants.USER_STATUS_FREEZE == serveProvider.getStatus()) {
            throw new CommonException(ErrorInfo.Code.ACCOUNT_FREEZED, serveProvider.getAccountLockReason());
        }
        //密码校验
        if(serveProvider == null || !passwordEncoder.matches(loginForWorkReqDTO.getPassword(), serveProvider.getPassword())){
            throw new BadRequestException("账号或密码错误,请重新输入");
        }


        // 3.生成登录token
        String token = jwtTool.createToken(serveProvider.getId(), serveProvider.getName(), serveProvider.getAvatar(), loginForWorkReqDTO.getUserType());
        return new LoginResDTO(token);

    }
顺便复习下BCrypt加密

BCrypt是一种密码哈希函数,通常用于存储用户密码的安全性。它是基于 Blowfish 密码算法的一种单向哈希函数
使用很简单,如下:

public static void main(String[] args) {
    BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    /**
     $2a$10$1sp7I0OdYH3Azs/2lK8YYeuiaGZzOGshGT9j.IYArZftsGNsXqlma
     $2a$10$m983E2nmJ7ITlesbXzjbzO/M7HL2wP8EgpgX.pPACDm1wG38Lt.na
     $2a$10$rZvathrW98vVPenLhOnl0OMpUtRTdBkWJ45IkIsTebITS9AFgKqGK
     $2a$10$2gaMKWCRoKdc42E0jsq7b.munjzOSPOM4yr3GG9M6194E7dOH5LyS
     $2a$10$I/n93PIKpKL8m4O3AuT5kuZncZhfqV51bfx5sJrplnYoM7FimdboC
     */
    for (int i = 0; i < 5; i++) {
        //对密码进行哈希
        String encode = passwordEncoder.encode("11111");
        System.out.println(encode);
    }
    //校验哈希串和密码是否匹配
    boolean matches = passwordEncoder.matches("11111", "$2a$10$m983E2nmJ7ITlesbXzjbzO/M7HL2wP8EgpgX.pPACDm1wG38Lt.na");
    System.out.println(matches);
}

1.2.7 注册功能实现

1.2.7.1 需求

用户点击注册按钮:
在这里插入图片描述
输入手机号获取验证码,再输入密码进行注册,接口设计如下:
在这里插入图片描述
接口地址:POST/customer/open/serve-provider/institution/register

1.2.7.2 Costomer注册功能接口实现
Controller开发
@RestController("openServeProviderController")
@RequestMapping("/open/serve-provider")
@Api(tags = "白名单接口 - 服务人员或机构相关接口")
public class ServeProviderController {

    @Autowired
    private IServeProviderService iServeProviderService;

    @PostMapping("/register")
    public void institutionRegister(@RequestBody InstitutionRegisterReqDTO institutionRegisterReqDTO){
        iServeProviderService.registerInstitution(institutionRegisterReqDTO);
    }
}

Service开发

首先校验验证码,假如验证码没问题就进行注册:

    /**
     * 机构注册
     * @param institutionRegisterReqDTO
     */
    @Override
    public void registerInstitution(InstitutionRegisterReqDTO institutionRegisterReqDTO) {
        //1.验证验证码
        boolean verifyResult = smsCodeApi.verify(institutionRegisterReqDTO.getPhone(),SmsBussinessTypeEnum.INSTITION_REGISTER,institutionRegisterReqDTO.getVerifyCode()).getIsSuccess();
        if(verifyResult){
            throw new BadRequestException("验证码校验失败");
        }
        //2.新增机构
        owner.add(institutionRegisterReqDTO.getPhone(),UserType.INSTITUTION,institutionRegisterReqDTO.getPassword());
    }

其中注册接口如下,先验证手机号是否已经被注册,没有则写入数据库:

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServeProvider add(String phone, Integer type, String password) {
        // 校验手机号是否存在
        ServeProvider existServeProvider = lambdaQuery().eq(ServeProvider::getPhone, phone)
                .one();
        if (existServeProvider != null) {
            if(existServeProvider.getType().equals(UserType.WORKER)){
                throw new BadRequestException("该账号已被服务人员注册");
            }else {
                throw new BadRequestException("该账号已被机构注册");
            }
        }

        //新增服务人员/机构信息
        ServeProvider serveProvider = new ServeProvider();
        serveProvider.setPhone(phone);
        serveProvider.setPassword(password);
        serveProvider.setType(type);
        serveProvider.setStatus(CommonStatusConstants.USER_STATUS_NORMAL);
        serveProvider.setCode(IdUtils.getSnowflakeNextIdStr());
        baseMapper.insert(serveProvider);

        //新增服务人员/机构配置信息同步表信息,方便后期对配置项进行配置
        serveProviderSettingsService.add(serveProvider.getId(), type);

        return serveProvider;
    }
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void add(Long id, Integer serveProviderType) {
        ServeProviderSettings serveProviderSettings = new ServeProviderSettings();
        serveProviderSettings.setId(id);
        if(baseMapper.insert(serveProviderSettings) <= 0 || serveProviderSyncService.add(id, serveProviderType) <= 0){
            throw new DBException("请求失败");
        }
    }
演示

在这里插入图片描述

1.2.8 找回密码功能

1.2.8.1 需求

首先用户忘记密码,点击找回密码:
在这里插入图片描述
全部输入后发出请求,接口如下:
在这里插入图片描述
POST/customer/agency/serve-provider/institution/resetPassword
首先校验验证码是否正确。
校验手机号是否存在数据库。
通过校验最后修改密码,密码的加密方式参考机构注册接口。

1.2.8.2 Costomer找回密码功能接口实现
Controller开发
@RestController("agencyServeProviderController")
@RequestMapping("/agency/serve-provider")
@Api(tags = "机构端 - 服务人员或机构相关接口")
public class ServeProviderController {
    @Resource
    private IServeProviderService serveProviderService;

    @GetMapping("/currentUserInfo")
    @ApiOperation("获取当前用户信息")
    public ServeProviderInfoResDTO currentUserInfo() {
        return serveProviderService.currentUserInfo();
    }

    @PostMapping("/institution/resetPassword")
    @ApiOperation("机构登录密码重置接口")
    public void resetPassword(@RequestBody InstitutionResetPasswordReqDTO institutionResetPasswordReqDTO){
        serveProviderService.resetPassword(institutionResetPasswordReqDTO);
    }
}

Service开发
    /**
     * c机构重置密码
     * @param institutionResetPasswordReqDTO
     */
    @Override
    public void resetPassword(InstitutionResetPasswordReqDTO institutionResetPasswordReqDTO) {
        //1.校验验证码
        Boolean verifyResult = smsCodeApi.verify(institutionResetPasswordReqDTO.getPhone(),SmsBussinessTypeEnum.INSTITUTION_RESET_PASSWORD,institutionResetPasswordReqDTO.getVerifyCode()).getIsSuccess();
        if(!verifyResult){
            throw new BadRequestException("验证码校验错误");
        }
        //2.校验数据库是否已经存在这个手机号
        ServeProvider serveProvider = lambdaQuery().eq(ServeProvider::getPhone, institutionResetPasswordReqDTO.getPhone()).one();
        if(serveProvider == null){
            throw new BadRequestException("手机号不存在");
        }
        //3.修改密码
        lambdaUpdate().eq(ServeProvider::getPhone, institutionResetPasswordReqDTO.getPhone())
                .set(ServeProvider::getPassword,passwordEncoder.encode(institutionResetPasswordReqDTO.getPassword())).update();
    }
演示

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

TCP三次握手、四次分手

TCP三次握手、四次挥手 TCP&#xff08;Transmission Control Protocol&#xff09;是一种面向连接的、可靠的、基于字节流的传输层通信协议&#xff0c;用于在网络上建立可靠的数据传输通道。在TCP/IP协议族中&#xff0c;TCP负责在数据传输过程中提供可靠性和完整性保证。TCP…

python协程入门实战详解

本章将以通俗易懂、贴合实际的方式介绍以下内容&#xff1a; 协程是什么&#xff0c;有什么特点&#xff0c;协程的优势是什么如何理解事件和事件循环协程的创建方式&#xff0c;如何控制协程的并发量在协程中使用aiohttp发送HTTP请求aiohttp案例协程中的异常处理&#xff0c;…

flowable工作流 完成任务代码 及扩展节点审核人(实现多级部门主管 审核等)详解【JAVA+springboot】

低代码项目 使用flowable 工作流 完成任务代码 详解 可以看到 complete()方法 传递了流程变量参数var 前端传递此参数就可以实现 流程中 审批 更新流程变量参数var 也可以进行更多扩展 实现流程中更新表单内容功能 启动流程实例代码 实现对于流程自定义 动态节点审核人 功…

五款效率软件助你事半功倍

1、&#x1f517; 亿可达 作为一款自动化工具&#xff0c;亿可达被誉为国内版的免费Zaiper。它允许用户无需编程知识即可将不同软件连接起来&#xff0c;构建自动化的工作流程。其界面设计清新且直观&#xff0c;描述语言简洁易懂&#xff0c;使得用户可以轻松上手。 2、&…

剪画小程序:干货丨3款照片转换成动漫形象的工具,赶紧收藏!

打开工具剪画&#xff0c;主页找到“照片转动漫”功能&#xff0c;上传图片即可转为漫画照片 有多种动漫模型&#xff0c;包括动漫、普通、艺术风、素描风等&#xff0c;还有更多趣味玩法如黏土风、3D风、Jade(玉石风)、WaterColor&#xff08;水彩风&#xff09;等等 照片就漫…

Redis之常用实战场景

1.Redis数据丢失场景 1.1 持久化丢失 采用RDB或者不持久化&#xff0c;就会有数据丢失&#xff0c;因为是手动或者配置以快照的形式来进行备份。 解决: 启用AOF&#xff0c;以命令追加的形式进行备份&#xff0c;但是默认也会有1s丢失&#xff0c;这是在性能与数据安全性中寻…

HTML、HTML5一览

文章目录 HTML简介标签基本标签格式化文本链接图像块级元素列表表格框架表单实体 HTML5 此篇用于优化csdn第一篇文章 HTML 简介 HTML 是用来描述网页的一种语言。 HTML 指的是超文本标记语言: HyperText Markup Language HTML 不是一种编程语言&#xff0c;而是一种标记语言…

sublime如何写python

推荐一款好用且轻量级的编辑器——sublime—text3&#xff0c;sublime现在支持的语言有很多。 右边弹出的列表可以往下拉&#xff0c;亮点是支持了python&#xff0c;而且不需要安装任何的python环境&#xff0c;直接下载sublime就可以编写python代码并运行了。 使用方法&…

Java面经——SpringCloud微服务

SpringCloud SpringCloud的五大组件 注册中心网关远程调用负载均衡熔断降级 谈谈你对SpringCloud的理解 SpringCloud是为了解决微服务架构中出现的一系列服务治理难题的而提出的一套规范&#xff0c;统一了标准。降低了微服务架构的开发难度。有了 Spring Cloud 这样的技术生…

Three.js——基础纹理、凹凸纹理、法向贴图、环境贴图、canvas贴图

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 ⚡开源项目&#xff1a; rich-vue3 &#xff08;基于 Vue3 TS Pinia Element Plus Spring全家桶 MySQL&#xff09; &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1…

linux嵌入式设备测试wifi信号强度方法

首先我们要清楚设备具体链接在哪个wifi热点上 执行&#xff1a;nmcli dev wifi list rootubuntu:/home/ubuntu# nmcli dev wifi list IN-USE BSSID SSID MODE CHAN RATE SIGNAL BARS > * 14:EB:08:51:7D:20 wifi22222_5G Infr…

香橙派安装 opencv 4.9.0

香橙派Orange AI Pro / 华为昇腾310 使用源码方式安装opencv 4.9.0 下载源码到香橙派 https://opencv.org/releases/ 解压 unzip opencv-4.9.0.zip进入解压后的文件 cd opencv-4.9.0创建构建目录build mkdir build进入目录 cd build使用cmake配置后续的构建环境 cmake -D…

SwiftUI 利用 Swizz 黑魔法为系统创建的默认对象插入新协议方法(二)

功能需求 在 SwiftUI 的开发中,我们往往需要借助底层 UIKit 的“上帝之手”来进一步实现额外的定制功能。比如,在可拖放(Dragable)SwiftUI 的实现中,会缺失拖放取消的回调方法让我们这些秃头码农们“欲哭无泪” 如上图所示,我们在拖放取消时将界面中的一切改变都恢复如初…

SpringBoot校园疫情管理系统-计算机毕业设计源码81164

摘 要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;校园当然也不例外。校园疫情管理系统是以实际运用为开发背景&#xff0c;运用软件工程原理和开发方法&#xff0c;采用J…

SmartEDA:Multisim与Proteus的强劲对手,引领电子设计新纪元

在电子设计领域&#xff0c;Multisim与Proteus长久以来一直占据着重要的地位&#xff0c;它们以其强大的仿真功能和丰富的组件库&#xff0c;深受设计师们的喜爱。然而&#xff0c;随着科技的不断进步和创新&#xff0c;一款名为SmartEDA的新兴电子设计工具正悄然崭露头角&…

MYSQL数据库客户端常规指令使用

这里新开一章&#xff0c;对MYSQL进行更加底层的系统的一个学习 Mysql常用工具简介 emmmm这里的话就默认大家在linux系统上面都进行了MYSQL的安装了. 在mysql安装完成之后&#xff0c;一般在路径 /usr/bin 下的 我们对该路径进行一个文件的展示 这里是展示出来的辅助工具 …

Web3.0区块链技术开发方案丨ICO与IDO代币开发

在Web3.0时代的到来下&#xff0c;区块链技术不仅改变着金融领域的格局&#xff0c;也在资金筹集和代币发行方面掀起了一场变革。初始代币发行&#xff08;ICO&#xff09;和去中心化代币发行&#xff08;IDO&#xff09;成为了项目融资的主要方式&#xff0c;其基于区块链技术…

【android 9】【input】【8.发送按键事件2——InputDispatcher线程】

系列文章目录 本人系列文章-CSDN博客 目录 系列文章目录 1.简介 1.1流程介绍 1.2 时序图 2.普通按键消息发送部分源码分析&#xff08;按键按下事件&#xff09; 2.1 开机后分发线程阻塞的地方 2.2 InputDispatcher::dispatchOnceInnerLocked 2.3 InputDispatcher::disp…

有没有不用写代码,贴图也简单的HTML WEB 3D 产品展示配置器?

品牌零售商&#xff0c;产品有3D模型但没有贴图&#xff0c;以前是直接送去生产&#xff0c;现在需要上线电商&#xff0c;看到国外挺多这种展示方式的网店&#xff0c;国内有没有这方面的供应商&#xff0c;网店顾客可以自己鼠标转动、换零件、换颜色等看定制效果&#xff0c;…

深入理解并发之LongAdder、DoubleAdder的实现原理

深入理解LongAdder、DoubleAdder的实现原理 本文主要通过LongAdder和DoubleAdder的源码&#xff0c;讲述一下其实现原理。通过LongAdder和DoubleAdder的源码可知。两者都是继承了Striped64的类。下面我们将通过源码的形式讲述一下这三个类都做了哪些事情。 1: Striped64 ​ …