电商系统:用户模块之登录功能

一、功能描述

用户输入账号密码进行登录,可以通过cookie、session保存当前用户信息

img

二、登录功能

1、Controller层

专门定义一个form包下的UserLoginForm类用于接收请求参数,通过@valid进行参数验证,确保参数不能为空,登录成功后将信息保存到session中

    @PostMapping("/user/login")
    public ResponseVO login(@Valid @RequestBody UserLoginForm userLoginForm, BindingResult bindingResult, HttpSession session){
        if(bindingResult.hasErrors()){
            log.info("登录提交的参数有误,{}", bindingResult.getFieldError().getDefaultMessage());
            return ResponseVO.error(ResponseEnum.PARAM_ERROR, bindingResult);
        }
        ResponseVO<User> responseVO = userService.login(userLoginForm.getUsername(), userLoginForm.getPassword());

        //设置session
        session.setAttribute(MallConst.CURRENT_USER, responseVO.getData());

        return responseVO;
    }

2、Service层

判断用户名、密码是否正确,密码置空

    @Override
    public ResponseVO<User> login(String username, String password) {
        User user = userMapper.selectByUsername(username);
        if(user == null){
            //用户不存在
            return ResponseVO.error(ResponseEnum.USERNAME_OR_PASSWORD_ERROR);
        }
        if(!user.getPassword().equalsIgnoreCase(DigestUtils.md5DigestAsHex(password.getBytes(StandardCharsets.UTF_8)))){
            //密码错误
            return ResponseVO.error(ResponseEnum.USERNAME_OR_PASSWORD_ERROR);
        }
        user.setPassword("");
        return ResponseVO.success(user);
    }

3、Dao层

自定义了根据用户名查找用户sql语句

  <select id="selectByUsername" parameterType="java.lang.String" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List" />
    from mall_user
    where username = #{username,jdbcType=VARCHAR}
  </select>

三、Cookie与Session

1、客户端向服务端发送登录请求

2、服务端在登录controller中,创建了一个session,将用户信息保存在了session中,同时自动将sessionId放入到了cookie中

session.setAttribute(MallConst.CURRENT_USER, responseVO.getData());

3、客户端在收到响应后,自身cookie中保存有sessionId

img

4、客户端向服务端发送请求,cookie中携带着sessionId

5、服务端在根据sessionId查找session,并获取到用户信息

    @GetMapping("/user")
    public ResponseVO<User> userInfo(HttpSession session){
        User user = (User)session.getAttribute(MallConst.CURRENT_USER);
        if(user == null){
            return ResponseVO.error(ResponseEnum.NEED_LOGIN);
        }

        return ResponseVO.success(user);
    }

6、session有存活时间,可以自行配置

7、跨域问题

127.0.0.1与localhost发起请求,cookie也是不同的,其Domain不同

img

四、退出登录

去除session

session.removeAttribute(MallConst.CURRENT_USER);

 @GetMapping("/user/logout")
    public ResponseVO<User> logout(HttpSession session){
        User user = (User)session.getAttribute(MallConst.CURRENT_USER);
        if(user == null){
            return ResponseVO.error(ResponseEnum.NEED_LOGIN);
        }
        session.removeAttribute(MallConst.CURRENT_USER);
        return ResponseVO.success();
    }

五、拦截器-统一判断登录状态

有两种方式

Interceptor,基于url进行拦截,本次采用该方式

AOP,基于包名进行拦截

1、定义一个拦截器配置类,加上@Configuration注解,实现WebMvcConfigurer接口,添加拦截器,添加拦截路径,添加排除路径

@Configuration
public class interceptorConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new UserLoginInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/user/login", "/user/register");
    }
}

2、定义一个拦截器类

实现HandlerIntercepto接口,返回false是拦截,返回true是继续

@Slf4j
public class UserLoginInterceptor implements HandlerInterceptor{

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("preHandle...");
        User user = (User)request.getSession().getAttribute(MallConst.CURRENT_USER);
        if(user == null){
            return false;
        }
        return true;
    }
}

发表评论

后才能评论