实现用户登录信息在多请求下的保存

用户登录信息如何保存

总体思路

上一篇《cookie 和 session》中介绍过使用cookie和session保存用户登录信息存在的问题,以及目前主流的解决方案–使用数据库来保存用户的登录信息。那么如何在保证访问速度和安全的情况下保存用户的登录信息呢?我们可以在数据库保存用户的登录信息,登录信息中存有随机生成的用户登录的凭证,一旦用户成功登录之后,我们将这个随机生成的凭证通过Cookie传给浏览器,下次浏览器再次向服务器发送请求的时候,就会将凭证带上一起发给服务器,服务器通过检查这个凭证,就可以得到用户的登录信息。为了计解决并发情况下的同步问题,使用ThreadLocal来保存用户的信息,当请求结束之后把用户信息给移除掉即可。

  1. 用户登录信息的表设计:
    登录信息表段设计
    字段说明:
    (1)user_id:用户的ID,可以通过这个Id去用户表查到该用户的详细信息,以便显示用户的头像信息。
    (2)ticket:用户登录的凭证,是一个随机生成的UUID,用户第一次登录之后会通过Cookie传到浏览器本地保存,之后用户发送请求时带上这个凭证。
    (3)status:用户的登录状态,0表示正常登录,1表示退出登录状态。
    (4)expired:这次登录的有效日期。

  2. 登录代码的实现:

public Map<String,Object> login(String username,String password,int expiredSeconds){
        Map<String,Object> map = new HashMap<>();
        if(StringUtils.isBlank(username)){
            map.put("usernameMsg","账号不能为空!");
            return map;
        }
        if(StringUtils.isBlank(password)){
            map.put("passwordMsg","密码不能为空!");
            return map;
        }
        User user = userMapper.selectByName(username);
        if(user==null){
            map.put("usernameMsg","该账号不存在!");
            return map;
        }

        if(user.getStatus()==0){
            map.put("usernameMsg","该账号未激活!");
        }

        if(!CommunityUtil.md5(password + user.getSalt()).equalsIgnoreCase(user.getPassword())){
            map.put("passwordMsg","密码不正确!");
            return map;
        }
        LoginTicket loginTicket = new LoginTicket();
        loginTicket.setUserId(user.getId());
        loginTicket.setTicket(CommunityUtil.generateUUID());
        loginTicket.setStatus(0);
        loginTicket.setExpired(new Date(System.currentTimeMillis() + 1000 * expiredSeconds));
        loginTicketMapper.insertLoginTicket(loginTicket);

        map.put("ticket",loginTicket.getTicket());	//在controller层存到Cookie中
        return map;
    }
  1. 通过拦截器获取用户的登录信息,从而使得登录成功之后,可以正常访问其他页面。实现逻辑:拦截器拦截除静态资源外的所有请求,然后判断是否带有登录凭证,如果带有登录凭证,那就通过凭证去查询用户的登录信息,如果登录信息正常,那么就通过登录信息查询用户的用户信息,并将用户信息保存在ThreadLocal中,在处理完请求后,将用户信息传给ModelAndView以便前端获取用户信息,当处理完模板以后,将ThreadLocal中的用户信息清除,防止内存泄漏。

@Component
public class LoginTicketInterceptor implements HandlerInterceptor {

    @Autowired
    UserService userService;

    @Autowired
    HostHolder hostHolder;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        //从cookie中获取凭证
        String ticket = CookieUtil.getValue(request,"ticket");
        if(ticket != null){
            //查询凭证
            LoginTicket loginTicket = userService.findLoginTicket(ticket);
            //检查凭证是否有效
            if((loginTicket != null && loginTicket.getStatus() == 0 && loginTicket.getExpired().after(new Date()))){
                //根据凭证查询用户
                User user = userService.findUserById(loginTicket.getUserId());
                //在本次请求中持有用户信息
                if(user != null){
                    hostHolder.setUsers(user);
                }
            }
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        //获取用户信息
        User user = hostHolder.getUsers();
        //通过ModelAndView把用户信息传给模板
         if(user != null && modelAndView != null){
             modelAndView.addObject("loginUser",user);
         }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        //清除掉用户信息
        hostHolder.clear();
    }
}

//获取Cookie的工具类
public class CookieUtil {
    public static String getValue(HttpServletRequest request,String name){
        if(request == null || name == null){
            throw new IllegalArgumentException("参数为空!");
        }
        Cookie[] cookies = request.getCookies();
        if(cookies != null){
            for(Cookie cookie : cookies){
                if(cookie.getName().equals(name)){
                    return cookie.getValue();
                }
            }
        }
        return null;
    }
}
//保存用户信息的工具类
@Component
public class HostHolder {
    private ThreadLocal<User> users = new ThreadLocal<>();

    public void setUsers(User user){
        users.set(user);
    }

    public User getUsers(){
        return users.get();
    }

    public void clear(){
        users.remove();
    }
}

//注册拦截器
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private LoginTicketInterceptor loginTicketInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginTicketInterceptor)
                .excludePathPatterns("/**/*.css","/**/*.js","/**/.png","/**/*.jpg","/**/*.jpeg");
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值