黑马点评短信登录功能

一、基于session实现短信登录

1、发送短信验证码

流程图如下:
在这里插入图片描述
1、实现UserController下的sendCode方法:

    /**
     * 发送手机验证码
     */
    @PostMapping("/code")
    public Result sendCode(@RequestParam("phone") String phone, HttpSession session) {
        // 发送短信验证码并保存验证码
        return userService.sendCode(phone, session);
    }

2、在userService下添加sendCode方法,根据流程图实现每一步的功能,校验手机号以及生成验证码的功能都是直接封装好的,在这里仅仅是利用后端模拟了发送验证码的功能:

    public Result sendCode(String phone, HttpSession session) {

        //1、校验手机号
        if(isPhoneInvalid(phone)){

            //2、手机号无效,返回错误信息
            return Result.fail("手机号无效!");
        }
        //3、手机号有效,生成验证码
        String code = RandomUtil.randomNumbers(6);
        //4、将验证码保存在session中
        session.setAttribute("code", code);
        //5、模拟发送验证码
        log.debug("发送验证码成功:验证码:{}", code);
        //返回ok
        return Result.ok();
    }
   

3、前端验证码获取成功
在这里插入图片描述

2、短信验证码登录注册

流程图如下:
在这里插入图片描述
1、实现UserController的下的login方法:

    /**
     * 登录功能
     * @param loginForm 登录参数,包含手机号、验证码;或者手机号、密码
     */
    @PostMapping("/login")
    public Result login(@RequestBody LoginFormDTO loginForm, HttpSession session){
        // 实现登录功能
        return userService.login(loginForm, session);
    }

2、在UserService下添加login方法,同样根据流程图实现功能,在这里隐藏了用户的敏感信息,如密码等,仅在session中存入电话,头像以及昵称信息,通过BeanUtil.copyProperties()实现属性复制,将User对象转化为UserDto:

    public Result login(LoginFormDTO loginForm, HttpSession session) {
        //1、校验手机号
        String phone = loginForm.getPhone();
        if(isPhoneInvalid(phone)){
            //2、手机号无效,返回错误信息
            return Result.fail("手机号无效!");
        }
        //手机号有效
        //4、取出session中的验证码
        Object cacheCode = session.getAttribute("code");
        //5、取出登录时输入的验证码
        String loginCode = loginForm.getCode();
        //6、校验验证码,如果验证码过期或者未获取到,以及验证码不正确
        if(cacheCode == null || !cacheCode.toString().equals(loginCode)){
            //7、返回错误信息
            return Result.fail("验证码错误");
        }
        //8、查询用户是否存在
        User user = query().eq("phone", phone).one();
        //9、不存在,创建新用户
        if(user == null) {
            user = createUserWithPhone(phone);
        }
        //10、将用户信息存入session
        session.setAttribute("user", BeanUtil.copyProperties(user, UserDTO.class));//隐藏用户的敏感信息,仅返回用户手机号,id,头像
        return Result.ok();
    }

    private User createUserWithPhone(String phone) {
        User user  = new User();
        user.setPhone(phone);
        user.setNickName(USER_NICK_NAME_PREFIX + RandomUtil.randomString(10));
        //保存用户
        save(user);
        return user;
    }

3、校验登录状态

在第2步中,我们已经实现了短信验证码登录注册的功能,但是没有做登录校验。
在这里插入图片描述
上图中的请求是携带了 cookie 的,cookie 里是包含了 JSESSIONID 的。

服务端可以基于 JSESSIONID 来获得 session ,再从 session 里取出用户,进而来判断该用户是否存在。

但是这个流程里有一个问题,我们需要在每一个 controller 里来写这些业务逻辑。

在这里插入图片描述
我们可以通过拦截器(由 SpringMVC 提供)来统一拦截判断,最后决定是否放行。

此外,如果要做分布式 session,会存在系统负担和性能以及安全问题。考虑到系统负担和安全,我们可以在拦截器拦截到之后,将 session 中的用户信息保存到 ThreadLocal 中。每一个进入 Tomcat 的请求都是一个独立的线程,那么将来 ThreadLocal 就会在线程内开启一个独立的空间去保存这些请求(请求中携带了对应的用户信息)。这样一来,不同的用户访问 controller,都是一个独立的线程,每一个线程都有自己的用户信息,相互独立不干扰,controller 从 ThreadLocal 中取出用户信息。)

1、我们新建一个拦截器loginIntercepter

public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //1、获取session
        HttpSession session = request.getSession();
        //2、获取session中的用户
        Object user = session.getAttribute("user");

        //3、判断用户是否存在
        if(user == null) {
            //4、不存在,拦截,返回401状态码
            response.setStatus(401);
            return false;
        }

        //5、存在,保存信息到ThreadLocal
        UserHolder.saveUser((UserDTO) user);
        //6、放行
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //7、移除用户
        UserHolder.removeUser();
    }
}

2、接下来我们配置这个拦截器,新建一个MvcConfig 实现 WebMvcConfigurer接口,将拦截器添加,并且排除掉不需要拦截的路径(发送短信验证码,短信验证码登录等):

@Configuration
public class MvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .excludePathPatterns(
                        "/shop/**",
                        "/voucher/**",
                        "/shop-type/**",
                        "/upload/**",
                        "/blog/hot",
                        "/user/code",
                        "/user/login"
                );
    }
}

4、session共享问题的分析

在这里插入图片描述
所以如果在多台Tomcat的情况下,就会存在session的共享问题,在后续通过Redis来解决这个问题,Redis同样满足内存存储以及键值对的结构,最为重要的一点就是可以实现数据共享。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值