①实现基于session的登录流程:发送验证码、登录注册、校验登陆状态

简介: ①实现基于session的登录流程:发送验证码、登录注册、校验登陆状态


实现基于session的登录流程:发送验证码、登录注册、校验登陆状态


🚀流程介绍

登录流程

①验证码发送

  • 发送验证码
  • 用户输入手机号,点击发送按钮进行手机号提交,程序会校验手机号是否合法,不合法时要求用户重新输入手机号,合法则在后台生成对应的验证码并保存至session,之后通过短信方式将验证码发送给用户。
  • 什么是HttpSession?
  • HttpSession是Java Web中的一个接口,它提供了一种在服务器端存储和检索用户相关信息的机制。当用户第一次访问Web应用程序时,服务器会为该用户创建一个唯一的session ID,并将该ID存储在一个名为JSESSIONID的cookie中,然后将该ID与一个新的HttpSession对象相关联。在用户与Web应用程序交互期间,可以使用HttpSession对象来存储和检索与该用户相关的信息。当用户关闭浏览器或超过session超时时间时,session对象将被销毁。
    以下是获取和使用HttpSession对象的常用方法:
    1.获取HttpSession对象:
HttpSession session = request.getSession();
  • 2.向session中存储数据:
session.setAttribute("key", value);
  • 3.从session中获取数据:
Object value = session.getAttribute("key");
  • 4.从session中删除数据:
session.removeAttribute("key");
  • 5.使session失效:
session.invalidate();


②用户登录、注册

  • 注册、登录
  • 用户将手机号、验证码输入,后台从session中获取验证码与用户输入的验证码进行比对校验,如果不一致则无法通过校验,提示用户验证码错误,验证码一直则后台根据手机号查询用户,若用户不存在,则为用户创建账号信息并保存至数据库中,最后无论用户是否存在,都将用户的信息保存至session中,方便后续业务获取当前用户信息。


③校验登录状态

  • 校验登陆状态
  • 用户在客户端发起请求时,Cookie会携带用户的 JsessionId 后台,后台根据 JsessionId 从session中获取用户信息,如果没有用户信息就表示未登录,会对请求进行拦截,如果有用户信息,将其存入到本地线程 ThreadLocal 中并放行。
  • 为什么使用ThreadLocal:
  • 每个用户其实对应都是去找tomcat线程池中的一个线程来完成工作的, 使用完成后再进行回收,既然每个请求都是独立的,所以在每个用户去访问我们的工程时,我们可以使用threadlocal来做到线程隔离,每个线程操作自己的一份数据。
  • 什么是 JsessionId ?
  • JSessionId是Java Web应用程序中的一个会话标识符,用于跟踪用户与Web应用程序之间的会话。当用户第一次访问Web应用程序时,服务器会为该用户创建一个唯一的JSessionId,并将其存储在cookie中。在随后的请求中,浏览器会将该cookie发送回服务器,以便服务器可以识别用户并维护会话状态。
    在Java Web应用程序中,可以使用HttpSession对象来访问和管理会话状态。




🚀代码实现

业务逻辑实现


  • 统一返回类型 实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {
    private Boolean success;
    private String errorMsg;
    private Object data;
    private Long total;
    public static Result ok(){
        return new Result(true, null, null, null);
    }
    public static Result ok(Object data){
        return new Result(true, null, data, null);
    }
    public static Result ok(List<?> data, Long total){
        return new Result(true, null, data, total);
    }
    public static Result fail(String errorMsg){
        return new Result(false, errorMsg, null, null);
    }
}


  • 校验手机号、邮箱、验证码格式
public class RegexUtils {
    /**
     * 是否是无效手机格式
     * @param phone 要校验的手机号
     * @return true:符合,false:不符合
     */
    public static boolean isPhoneInvalid(String phone){
        return mismatch(phone, RegexPatterns.PHONE_REGEX);
    }
    /**
     * 是否是无效邮箱格式
     * @param email 要校验的邮箱
     * @return true:符合,false:不符合
     */
    public static boolean isEmailInvalid(String email){
        return mismatch(email, RegexPatterns.EMAIL_REGEX);
    }
    /**
     * 是否是无效验证码格式
     * @param code 要校验的验证码
     * @return true:符合,false:不符合
     */
    public static boolean isCodeInvalid(String code){
        return mismatch(code, RegexPatterns.VERIFY_CODE_REGEX);
    }
    // 校验是否不符合正则格式
    private static boolean mismatch(String str, String regex){
        if (StrUtil.isBlank(str)) { //Hutool工具:StrUtil
            return true;
        }
        return !str.matches(regex);
    }
}


  • 发送短信验证码 业务
@Override
    public Result sendCode(String phone, HttpSession session) {
        //1. 手机号不合法?
        if(RegexUtils.isPhoneInvalid(phone)){
            //2. 不合法,返回错误信息
            return Result.fail("手机号格式错误!");
        }
        //3. 借助工具类,生成验证码(Hutool工具)
        String code = RandomUtil.randomNumbers(6);
        //4. 保存验证码至session域
        session.setAttribute("code",code);
        //5. 发送验证码
        log.debug("发送短信验证码成功,验证码: " + code);  //日志、方便控制台查看
        /*
            调用验证码服务...(具体逻辑参照具体服务供应商的文档)
        */
        //6. 返回ok
        return Result.ok();
    }


  • 登录、注册 业务
/**
     *   session实现登录功能
     * @param loginForm
     * @param session
     * @return
     */
    @Override
    public Result login(LoginFormDTO loginForm, HttpSession session) {
        //1. 校验手机号
        String phone = loginForm.getPhone();
        if(RegexUtils.isPhoneInvalid(phone)){
            //2. 返回错误信息
            return Result.fail("手机号格式错误");
        }
        //3. 校验验证码
        Object cacheCode = session.getAttribute("code");
        String code = loginForm.getCode();
        if(code == null || !code.toString().equals(cacheCode)){
            //不一致,返回错误信息
            return Result.fail("验证码错误");
        }
        // 一致,根据手机号获取用户
        User user = this.query().eq("phone", phone).one(); //(mybatisPlus提供的Service层方法)
        //5. 判断用户是否存在
        if(user == null){
            //6. 不存在,创建新用户
            user = new User();
            user.setPhone(phone); //设置phone
            user.setNickName(USER_NICK_NAME_PREFIX + RandomUtil.randomString(10)); //设置随机昵称
            this.save(user); // 存入数据库(mybatisPlus提供的Service层方法)
        }
        //7. 用户存在,存入session域
        session.setAttribute("user", BeanUtil.copyProperties(user, UserDTO.class));
        //返回ok
        return Result.ok();
    }


  • 创建并设置ThreadLocal 自定义工具类
public class UserHolder {
    private static final ThreadLocal<UserDTO> tl = new ThreadLocal<>();
    public static void saveUser(UserDTO user){
        tl.set(user);
    }
    public static UserDTO getUser(){
        return tl.get();
    }
    public static void removeUser(){
        tl.remove();
    }
}


  • 校验登陆状态 拦截器
/**
 * TODO 登录 拦截器
 * @author .29.
 * @create 2023-11-26 16:37
 */
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 1.获取session
        HttpSession session = request.getSession();
        //2. 获取用户
        Object user = session.getAttribute("user");
        //3. 验证用户是否存在
        if(user == null){
            //4. 不存在,进行拦截,返回401状态码
            response.setStatus(401);
            return false;
        }
        //5. 存在,存入ThreadLocal(自定义工具类UserHolder,作用:创建并设置ThreadLocal)
        UserHolder.saveUser((UserDTO) user);
        //6. 放行
        return true;
    }
}

  • Spring Boot使用Spring MVC拦截器的步骤如下:
  • 1.创建一个拦截器类并实现HandlerInterceptor接口,该接口包含三个方法:preHandle、postHandle和afterCompletion。preHandle方法在请求处理之前调用,postHandle方法在请求处理之后调用,afterCompletion方法在视图渲染之后调用。
  • 2.在拦截器类上使用@Component@Configuration注解将其声明为Spring组件。
  • 3.创建一个配置类并实现WebMvcConfigurer接口,该接口包含一个addInterceptors方法,用于注册拦截器。
  • 4.在addInterceptors方法中使用addInterceptor方法注册拦截器,并使用addPathPatterns方法指定要拦截的请求路径。


  • 使拦截器生效 SpringMvc配置类
/**
 * TODO SpringMVC配置类,使拦截器生效
 * @author .29.
 * @create 2023-11-26 16:49
 */
@Configuration
public class MvcConfig implements WebMvcConfigurer {
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //1. 添加登录拦截器、同时设置无需拦截的路径
        registry.addInterceptor(new LoginInterceptor()).excludePathPatterns(
                "/shop/**",
                "/voucher/**",
                "/shop-type/**",
                "/upload/**",
                "/blog/hot",
                "/user/code",
                "/user/login"
        ).order(0); //order默认0,order值越大拦截器越后执行
    }
}




目录
相关文章
|
7月前
|
前端开发 安全 Java
SpringBoot 实现登录验证码(附集成SpringSecurity)
SpringBoot 实现登录验证码(附集成SpringSecurity)
433 0
|
4月前
|
存储 NoSQL 数据库
认证服务---整合短信验证码,用户注册和登录 ,密码采用MD5加密存储 【二】
这篇文章讲述了在分布式微服务系统中添加用户注册和登录功能的过程,重点介绍了用户注册时通过远程服务调用第三方服务获取短信验证码、使用Redis进行验证码校验、对密码进行MD5加密后存储到数据库,以及用户登录时的远程服务调用和密码匹配校验的实现细节。
认证服务---整合短信验证码,用户注册和登录 ,密码采用MD5加密存储 【二】
|
2月前
|
Java
Java 登录输入的验证码
Java 登录输入的验证码
35 1
|
2月前
|
C#
C# 图形验证码实现登录校验代码
C# 图形验证码实现登录校验代码
93 2
|
3月前
|
前端开发 PHP
ThinkPHP 验证码扩展库的使用,以及多应用模式下,如何自定义验证码校验规则
本文介绍了在ThinkPHP框架中使用验证码扩展库的方法,包括安装验证码扩展库、在页面中使用验证码、自定义验证码配置以及校验验证码的步骤和代码示例。
ThinkPHP 验证码扩展库的使用,以及多应用模式下,如何自定义验证码校验规则
|
3月前
|
存储 JSON 前端开发
node使用token来实现前端验证码和登录功能详细流程[供参考]=‘很值得‘
本文介绍了在Node.js中使用token实现前端验证码和登录功能的详细流程,包括生成验证码、账号密码验证以及token验证和过期处理。
65 0
node使用token来实现前端验证码和登录功能详细流程[供参考]=‘很值得‘
|
4月前
|
资源调度 JavaScript API
nest.js + sms 实现短信验证码登录
本文介绍了在Nest.js框架中集成短信验证码登录的实现方案,详细阐述了使用阿里云短信服务的配置流程、资质申请、短信模板设置,并提供了API调用示例和工程代码的运行步骤。
nest.js + sms 实现短信验证码登录
|
4月前
【Azure 环境】中国区Azure B2C 是否支持手机验证码登录呢?
【Azure 环境】中国区Azure B2C 是否支持手机验证码登录呢?
|
4月前
|
NoSQL Java Redis
认证服务---整合短信验证码,验证码倒计时,验证码防刷校验 【一】
这篇文章介绍了如何在分布式微服务项目中整合短信验证码服务,包括使用阿里云短信验证接口、将短信验证功能集成到第三方服务中、其他服务的远程调用,以及通过Redis实现验证码防刷机制的代码实现和遇到的问题解决方案。
|
6月前
|
缓存 NoSQL Java
案例 采用Springboot默认的缓存方案Simple在三层架构中完成一个手机验证码生成校验的程序
案例 采用Springboot默认的缓存方案Simple在三层架构中完成一个手机验证码生成校验的程序
118 5