LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

【C#】手机短信登录开发,还能这样玩?

admin
2024年4月12日 23:15 本文热度 35

我们项目开发中比较通用的登录方式是用账号密码登录,但实际生活中短信登录的方式是大家所常用的。

下面的文章,前三步我先进行了短信登录的实现,最后一步对其进行了异常处理封装的细节优化。

实现验证码登录流程分析

1)发送验证码

用户在提交手机号后,会校验手机号是否合法,如果不合法,则要求用户重新输入手机号。

如果手机号合法,后台此时生成对应的验证码,同时将验证码进行保存,然后再通过短信的方式将验证码发送给用户。

2)短信验证码登录、注册

用户需输入收到的验证码及关联的手机号码。服务器后台会从当前的Session中提取先前存储的验证码,并与用户所输入的进行比对。若两者不匹配,用户将无法完成验证过程。若验证码相符,系统将依据用户输入的手机号码在数据库中进行用户查询。若查询结果显示该手机号尚未注册,系统将自动创建新的用户账户,并将基础信息存入数据库。无论用户是已存在或是新注册,系统都会更新 Session 信息,保存用户的登录凭证,以便用户能够顺利进行后续操作并随时访问其账户信息。

代码实现验证码发送

这里我使用 MyBatisX 实现项目的初始化。

1)正则表达式类

使用正则表达式分别对手机号、密码、验证码进行校验。

正则表达式可以去网上找,我这里提供下我的实现方式,可以作为参考。

public class RegexPatterns {
    /**
     * 手机号正则
     */
    public static final String PHONE_REGEX="1\\d{10}";
    /**
     * 邮箱正则
     */
    public static final String EMAIL_REGEX="/^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$/";
    /**
     * 验证码正则
     */
    public static final String VERIFY_CODE_REGEX="^[a-zA-Z\\d]{6}$";

}

2)正则校验工具类

对 Controller 层传入的手机号进行校验。

满足手机号正则表达式,手机号 11 位,并且只能为数字,才能校验通过

这里我使用的是 Hutool 工具类来校验手机号和验证码是否合法。

我贴一下 Hutool 的官网,有需要更加深层次了解的小伙伴可以访问下哦!

Hutool 官网:https://doc.hutool.cn/pages/index/

public class RegexUtils {

    /**
     * 校验手机号是否合法
     * @param phone
     * @return
     */
    public static boolean isPhoneInvalid(String phone){
        boolean matches = phone.matches(RegexPatterns.PHONE_REGEX);
        return matches;
    }

    /**
     * 校验验证码是否合法
     * @param code
     * @return
     */
    public boolean isCodeInvalid(String code){
        boolean matches = code.matches(RegexPatterns.VERIFY_CODE_REGEX);
        return matches;
    }
}

3)Controller 层

@GetMapping("/code")
    public boolean SendCode(String phone, HttpSession session){
        boolean b = userService.sendCode(phone, session);
        return b;
    }

4)Service 层

首先,系统会将用户输入的手机号通过正则表达式校验工具类进行验证,确保其格式正确无误。一旦手机号通过校验,程序便会自动生成一个随机验证码,并将其安全地存储在服务器的 Session 中。为了便于开发者实时监控验证码的生成和发送状态,系统特别设计了在控制台以 debug 模式输出验证码的功能,从而确保了整个验证流程的透明度和可追踪性。

@Resource
private UserService userService;

public boolean sendCode(String phone, HttpSession session) {
    //1、校验手机号是否合法
    if (!RegexUtils.isPhoneInvalid(phone)) {
        return false;
    }
    //2、生成随机验证吗
    String code = RandomUtil.randomNumbers(6);
    //3、保存验证码
    session.setAttribute("code",code);
    //4、打印日志
    log.debug("发送短信验证码成功,验证码:{}",code);
    return true;
}

注意:这里需要开启 debug 日志

controller 层中加入@Slf4j注解

logging:
  level:
    com.example: debug
# 开启debug日志

结果:

实现验证码登录注册

短信验证登录注册逻辑:

1、校验手机号

2、校验验证码(取出 Session 中保存的验证码与表单中的输入的验证码吗进行比较)

3、不一致:报错

4、一致:根据手机号查询用户

5、判断用户是否存在

6、不存在,根据手机号创建新用户并保存

  • 用户是凭空创建的,所以密码可以没有,

  • 用户呢称和头像都是随机默认的

7、保存用户信息到 Session 中

1)Controller 层

我们登录需要获取两个参数,用户名和手机号,根据手机号来创建用户名。

@PostMapping("/login")
    public boolean login(LoginFormDTO loginFormDTO, HttpSession session){
        boolean login = userService.Login(loginFormDTO, session);
        return login;
    }

为了使代码更加美观,创建一个参数封装类。

/**
 * 用户登录请求参数封装类
 */
@Data
public class LoginFormDTO {
    private String code;
    private String phone;
}

2)Servcie 层

  /**
     * 用户登录
     * @param loginFormDTO
     * @param session
     * @return
     */
    @Override
    public boolean Login(LoginFormDTO loginFormDTO, HttpSession session) {
        //1、首先校验手机号和验证码是否合法
        String phone = loginFormDTO.getPhone();
        if(!RegexUtils.isPhoneInvalid(phone)){
            return false;
        }
        //2、校验验证码
        Object cachecode = session.getAttribute("code");
        String dtoCode = loginFormDTO.getCode();
        if (dtoCode==null&&!dtoCode.equals(cachecode)) {
            return false;
        }
        //3、根据手机号查询用户信息
        QueryWrapper<User> queryWrapper=new QueryWrapper<User>();
        queryWrapper.eq("phone", phone);
        //4、根据查询条件查询数据库中满足以上条件的用户
        User user = userMapper.selectOne(queryWrapper);
        if (user==null) {
            //创建用户
            user=CreateUser(phone);
        }
        //5、保存用户信息到session中
        session.setAttribute("user",user);
        return true;
    }

将创建用户的这段代码单独封装为一个函数。

    /**
     * 创建用户
     * @param phone
     * @return
     */
    private User CreateUser(String phone){
        User user = new User();
        user.setPhone(phone);
        user.setNickName(RandomUtil.randomString(10));
        //保存用户
        save(user);
        return user;
    }

发送验证码

get  http://localhost:8080/api/user/code?phone=13177576913

校验验证码并登录

post http://localhost:8080/api/user/login?phone=13177576913
&code=686422

运行结果:

优化:全局通用返回对象

前面我的测试前端返回的数据都太过单调,因为这是一个功能的实现,并不是做一个完整的项目,但这样看起来确实不太美观。

所以这里使用 ==》全局统一 API 响应框架 ==》对整个接口进行统一的异常处理封装,这样就不需要写那么多的异常处理类了。

1)引入依赖

使用rest-api-spring-boot-starter这个依赖,不用打开 Redis ,但这个依赖需要加上。

<!--RestfulAPI-->
<dependency>
    <groupId>cn.soboys</groupId>
    <artifactId>rest-api-spring-boot-starter</artifactId>
    <version>1.3.0</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2)注解

启动类上加上这个@EnableRestFullApi 注解。

只需要引入依赖和加上注解这两步,Log 日志就变得与上面没优化前的不一样了。

注意:这里的端口号是 8000,也就是说使用这个依赖必须要 8000 端口,我们在配置文件中所设置的 Web 端口没有用了,无法自定义端口

运行后,通过 Postman 测试,测试结果如下图所示:

3)用户信息脱敏

我们这里进行用户脱敏,将返回对象单独封装。

@Data
public class UserDTO {
    private Long id;
    private String nickName;
    private String icon;
}

修改登录login方法中的下面所示内容。

/**
     * copyProperties:属性拷贝——把user中的属性字动拷贝到UserDTO中
     * BeanUtils:使用的是包cn.hutool.core.bean下的工具类
     */
//5、保存用户信息到session中
UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);
session.setAttribute("user", userDTO);

最终,如下图所示成功返回三个信息。

以上,就是今天的分享,希望对大家有帮助。


该文章在 2024/4/12 23:15:39 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2024 ClickSun All Rights Reserved