理解Cookie和Session机制 —— 通过Session实现登陆保持

前言

通过Session实现登陆保持的原理很简单,保存在服务端中的Session可以保存用户名和id等一些信息,在用户登陆成功后,将这些信息保存在Session中即可,服务端会自动在创建session的时候将该session的id通过响应头的方式返回给客户端。客户端在下次请求的时候就会自动带上该sessionId(cookie名未JSSSIONID),服务端就会通过该id找到保存在服务端的seesion,取得该用户的id来识别用户并判断该用户是否登陆成功。

效果

在这里插入图片描述
在这里插入图片描述

服务端代码

import com.test.common.PJCommon;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Controller
@RequestMapping("/sLoginDemo")
public class SloginController {
    /***
     * 测试登录
     * 这里假设用户(userName=admin,password=1111)
     */
    @RequestMapping(value = "/login.do", method = RequestMethod.POST)
    @ResponseBody
    public Map login(HttpServletRequest request, HttpServletResponse response) {
        Map<String,Object> retMap = new HashMap<String,Object>();
        Map<String,String> paramMap = PJCommon.getRequestParamMapAndSessionInfo(request);
        try {
            String account = paramMap.get("account").toString(); // 获取account参数
            String password = paramMap.get("password").toString(); // 获取password参数

            /*
             * 获取或者创建Session
             * ajax请求会自动带上名为"JSESSIONID"的cookie(如果客户端有这个cookie的话),该值就是服务端创建session后,返回客户端的seesionId
             * getSession会根据这个id查询服务端是否有这个session,如果有的话就会获取该session,如果没有的话就会新建一个新的session
             * Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,并维护该Session。
             * 用户每访问服务器一次,无论是否读写Session,服务器都认为该用户的Session“活跃(active)”了一次。
             * */
            HttpSession session = request.getSession(); // 获取Session对象
            Object personObj = session.getAttribute("person");
            // 判断personObj是否存在,如果存在则不是新建的session,直接返回账户信息即可
            if (personObj != null) {
                retMap.put("state", 0);
                retMap.put("person", personObj);
                retMap.put("message", "session登陆成功");
                return retMap;
            }
            // 如果不存在,则是新建的session,需要重新验证账号密码
            if (!"admin".equals(account) || !"1111".equals(password)) {
                session.invalidate(); // 作废session
                // 账号密码校验不通过
                retMap.put("state", -1);
                retMap.put("message", "账号/密码错误");
                return retMap;
            }
            // 验证通过
            Map personInfo = new HashMap();
            personInfo.put("name", "huzhenv5");
            personInfo.put("age", "18");
            session.setAttribute("person", personInfo); // 设置Session中的属性
            // 设置Session维持时间,单位是秒(0或者负数表示session永远不超时)
            // spring boot 可以在配置文件中配置默认的session超时时间
            // 通过以下代码设置session超时时间,优先级更高
            session.setMaxInactiveInterval(10);

            retMap.put("state", 0);
            retMap.put("person", personInfo);
            retMap.put("message", "账号/密码登陆成功");

        } catch (Exception e) {
            e.printStackTrace();
            retMap.put("state", -2);
            retMap.put("message", "登陆失败");
        }
        return retMap;
    }

    /***
     * 注销登录
     */
    @RequestMapping(value = "/logout.do", method = RequestMethod.POST)
    @ResponseBody
    public Map logout(HttpServletRequest request, HttpServletResponse response) {
        Map<String,Object> retMap = new HashMap<String,Object>();
        Map<String,String> paramMap = PJCommon.getRequestParamMapAndSessionInfo(request);
        try {
            HttpSession session = request.getSession(); // 获取Session对象
            session.invalidate(); // 作废session
            // 注销成功
            retMap.put("state", 0);
            retMap.put("message", "注销成功");

        } catch (Exception e) {
            e.printStackTrace();
            retMap.put("state", -2);
            retMap.put("message", "注销失败");
        }
        return retMap;
    }

}

前端登陆页脚本

// 页面初始化方法
$(document).ready(function(){
    // login(false);
});

function doLogin() {
    login(true);
}

/**
 * 登陆方法
 * @param showAlter 失败是否报错
 * */
function login(showAlter) {
    var account = $('#accountInput').val();
    var ps = $('#psInput').val();
    // 请求
    $.ajax({
        type : 'POST',
        data: {
            account: account,
            password: ps
        },
        dataType: 'json',
        url : "../../sLoginDemo/login.do",
        success: function(res) {
            if (res.state == 0) {
                console.log(res.message);
                location.href = '../sMain/sMain.html'
            } else {
                showAlter && alert('失败:' + res.message);
            }
        },
        error: function(err) {
            showAlter && alert('错误:' + err.message);
        }
    })
}

前端注销页脚本

function logout() {
    $.ajax({
        type : 'POST',
        dataType: 'json',
        url : "../../sLoginDemo/logout.do",
        success: function(res) {
            if (res.state == 0) {
                location.href = '../sLogin/sLogin.html'
            } else {
                alert('失败:' + res.message);
            }
        },
        error: function(err) {
            alert('错误:' + err.message);
        }
    })
}

和通过Cookie方式实现的比较

Cookie优点:

  1. 不占用服务端内存
  2. 分布式的时候不用考虑session无法共享的问题
  3. 由于验证信息保存在客户端,可以将登陆状态保持较长时间

Cookie缺点:

  1. 每次请求Cookie内容较多,增请求量
  2. 如果存储内容过多,容易超过浏览器对Cookie大小的限制
  3. 每次请求均需要进行安全验证

Session优点:

  1. 客户端发送的Cookie仅有一个JSESSIONID,该部分请求量小
  2. 用户信息保存在服务端,可以直接取用,不用每次请求都进行验证

Session缺点:

  1. 高并发情况,占用大量的服务端内存
  2. 分布式的时候session不能共享
  3. 不通过其它方式辅助的话,由于session占用服务端内存,登陆状态无法保持较长时间

Git

该工程通过spring boot实现,完整的工程可以访问笔者的GitHub

GitHub链接:https://github.com/huzhen-v5/spring-boot-swagger
分支名:logindemo

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值