栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JSON Web Tokens - Session 会话机制

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JSON Web Tokens - Session 会话机制

文章目录
    • 1. Session存储数据
    • 2. 获取Session数据
    • 3. 关闭浏览器后Session ID失效问题
    • 4. 在分布式环境下Session存在的问题
    • 5. Cookie+MySQL实现登录功能

1. Session存储数据
@RequestMapping(path = "/set/session", method = RequestMethod.GET)
@ResponseBody
public String setSession(HttpSession session) {
    session.setAttribute("name","zhagnsan");
    session.setAttribute("age",17);
    return "set sesion";
}

Session是依赖于Cookie实现的,除了把Session对象保存在服务器的内存中以外,还会创建一个Cookie对象,Cookie的key=JSESSIONID,Cookie的vaue=sessionId,这个sessionId唯一的标识一个Session对象。

2. 获取Session数据
@RequestMapping("/get/session")
@ResponseBody
public String getSession(HttpSession session){
    System.out.println(session.getAttribute("name"));
    System.out.println(session.getAttribute("age"));
    return "get session";
}

如下,当浏览器再次访问服务器时,请求头中会带有Cookie,这个Cookie就是之前存储的SessionId。

我发现当我关闭浏览器后,Session ID便失效了。

3. 关闭浏览器后Session ID失效问题

只要浏览器不关闭,以后每次访问服务器,浏览器都会带着这个Session ID,但是浏览器关闭后,这个Session ID就失效了,此时之前浏览器保存的Session ID便没了,那么怎么进行验证呢?

Session是一种服务器端的对象,保存在服务器中。 每个Session 有一个唯一的Session id。 Session的超时也是由服务器来控制,大部分的Session机制都使用进程中Cookie来保存Session id的,关闭浏览器后这个进程也就自动消失了,进程中的Cookie自然就消失了,那么Session id也跟着消失了,再次连接到服务器时也就无法找到原来的Session了。

其实服务器是不会知道浏览器关闭了没有,所以关闭浏览器时服务器是不会删除Session的,也正是这个原因服务器才会设置一个Session失效时间的(默认20分钟),不然服务器早晚会被撑爆。

客户端用cookie保存了sessionID:

客户端用cookie保存了sessionID,在没有把浏览器关掉的时候,这个sessionID会一直保存在浏览器中,每次请求的时候都会把这个sessionID提交到服务器,所以服务器认为我们是登录的;

如果太长时间没有请求服务器,服务器会认为我们已经所以把浏览器关掉了,这个时候服务器会把该sessionID从内存中清除掉,这个时候如果我们再去请求服务器,sessionID已经不存在了,所以服务器并没有在内存中找到对应的 sessionID,这是需要重新登录。

客户端没有用cookie保存sessionID :

如果我们请求服务器,因为没有提交sessionID上来,服务器会认为你是一个全新的请求,服务器会给你分配一个新的sessionID,这就是 为什么我们每次打开一个新的浏览器的时候都会产生一个新的sessionID。

当我们一旦把浏览器关掉后,再打开浏览器再请求该页面,它会让我们登录,这是为什么?

我们明明已经登录了,而且还没有超时,sessionID肯定还在服务器上的,为什么现在我们又要再一次登录呢?这是因为我们关掉浏览再请求的时候,我们提交的信息没有把刚才的sessionID一起提交到服务器,所以服务器不知道我们是同一个人,所以这时服务器又为我们分配一个新的sessionID。

4. 在分布式环境下Session存在的问题

在分布式环境中,小明通过服务器1登录了系统, 那 session 会保存在服务器1上, 假设小明的下一次请求被转发到服务器3怎么办? 服务器3可没有小明的 session 啊。

于是出现了session 的复制, 服务器1创建Session并存储数据后,将Session复制到其他服务器上,这样小明即使访问服务器3怎也能找到Session,因为每个服务器上都存储了Session 数据。但是这样也会存在一定的问题,比如服务器内存压力大,且服务器之间是耦合的。

于是又出现了共享Session,将Session都存储在一台服务器上,Session的创建和获取都在这个服务器,但是如果服务器挂了,那么Session数据就全丢失了。

于是又演变成了目前比较主流的方法:

  • 客户端的信息不存在Session中了,能存在Cookie中就存在Cookie中;

  • 有些敏感数据无法存储在Cookie中,就存储在数据库中或redis中,数据库可以做集群;

5. Cookie+MySQL实现登录功能

这种方式虽然没有使用到Session,但是原理和Session原理类似,也需要依赖于Cookie:

  • 浏览器请求登录,服务器在MySQL中保存登录信息,登陆成功后将 ticket(ticket唯一标识这条用户信息,类似于session id)通过Cookie返回给浏览器并保存,而不是直接将敏感信息保存在Cookie中;
  • 当浏览器再次访问时,请求 Cookie 中会带有 ticket,通过 ticket 访问数据库可以得到用户信息并验证;

核心代码:

@PostMapping("/login")
public String login(String username,String password,boolean rememberme,
                  Model model,HttpSession session,HttpServletResponse response){

    // Cookie的过期时间
    int expiredSeconds = rememberme ? REMEMBERME_EXPIRED_SECONDS : DEFAULT_EXPIRED_SECONDS;
    
    //登录
    Map map = userService.login(username, password, expiredSeconds);
    
     // 登录成功,将ticket通过cookie响应给浏览器
    if(map.containsKey("ticket")){
        Cookie cookie = new Cookie("ticket",map.get("ticket").toString());
        cookie.setPath(contextPath);
        cookie.setMaxAge(expiredSeconds);
        response.addCookie(cookie);
        // 重定向到首页 
        return "redirect:/index";
    }else{
        // 登录失败
        model.addAttribute("usernameMsg",map.get("usernameMsg"));
        model.addAttribute("passwordMsg",map.get("passwordMsg"));
        return "/site/login";
    }
}
public Map login(String username,String password,int expiredSeconds){
    //生成登录凭证
    LoginTicket loginTicket = new LoginTicket();
    loginTicket.setUserId(user.getId());
    loginTicket.setStatus(0);
    loginTicket.setExpired(new Date(System.currentTimeMillis()+expiredSeconds*1000));
    
    // 随机字符串
    loginTicket.setTicket(CommunityUtil.generateUUID());
    
    //存入数据库中
    loginTicketMapper.insertLoginTicket(loginTicket);

    //将登录凭证的ticket放入map中,以便在controller层将其通过cookie响应给浏览器
    map.put("ticket",loginTicket.getTicket());
    return map;
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/887747.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号