凡事都在事上磨,这样才能精进,成长进步提高! ------ 博客园首页

Cookie + session 理解

Http是一种无状态的应用层传输协议。可以理解成请求之间没有联系。但是很多场景,比如需要知道上次是哪个用户登录了。这时就要用到cookie和session了。
一. Cookie
Cookie是一种客户端技术,可以理解成用户信息存储在客户端。客户端第一次请求服务器时,如果需要记录用户状态,就用response特意给客户端生成一个Cookie,客户端会自动保存起来。当再次请求时,客户端把Cookie也提交给服务器。服务器通过request拿到cookie,就可以判断用户状态。下面举个简单的代码应用。
 
 
//自定义拦截器,要结合MyWebConfig使用
@Component
public class CookieInterceptor implements HandlerInterceptor {
    private static final Logger LOGGER = LoggerFactory.getLogger(CookieInterceptor.class);

    /**
     * 在业务处理器处理请求之前被调用。预处理,可以进行编码、安全控制、权限校验等处理;
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("CookieInterceptor preHandle");
        String requestURI = request.getRequestURI();
        Cookie[] cookies = request.getCookies();
        //1.如果是登录接口,则设置cookie
        if (requestURI.contains("/loginInfo/login")) {
            response.addCookie(new Cookie("hasLogined", "true"));
            //2.如果不是登录接口,则校验有无cookie
        } else {
            boolean flag = false;
            if (cookies != null) {
                for (Cookie cookie : cookies) {
                    if (cookie.getName().equals("hasLogined")) {
                        flag = true;
                        break;
                    }
                }
            }
            if (!flag) {
                LOGGER.error("please login first");
                return false;
            }
        }
        return true;
    }
 
举例代码里,我们把Cookie处理放在拦截器里,一般项目里也都可以这样处理,拦截器可以用请求做一些预处理,比如这里用Cookie校验用户的登录状态。如果请求是登录接口,那么生成一个Cookie(客户端可以存储多个cookie),用response.addCookie方法即可传给客户端。当不是登录的请求过来时,就先从request里拿到所有Cookie,看看是否有用户登录状态,如果没有直接被拦截。这里只是个简单的应用,实际场景会相对复杂,也可以给cookie设置域,存活时间等。
 
二. Session
Session是一种服务器端技术,可以理解成把用户登录状态存在服务器端。登录接口里,服务器生成一个Session,里面可以保存用户信息。当请求业务接口时,先获取Session,再进一步核对用户信息。那么客户端是怎么获取到Session的呢,实际上Session还是要配合Cookie使用,在生成Session时候,底层会把这个Session对应的SessionId存到Cookie中传给客户端,再次请求时就可以拿到SessionId去服务器里找对应的Session。下面举个简单的代码应用。
 
private Set<String> sessionIds = Sets.newHashSet();
/**
 * 在业务处理器处理请求之前被调用。预处理,可以进行编码、安全控制、权限校验等处理;
 */
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    System.out.println("SessionInterceptor preHandle");
    String requestURI = request.getRequestURI();
    //1.如果是登录接口,则设置session
    if (requestURI.contains("/loginInfo/login")) {
        // 用户登陆时如果携带了sessionid,则先将session做invalid处理
        HttpSession session = request.getSession(false);
        if (null != session) {
            session.invalidate();
        }
        // ture,则如果获取不到session,会生成一个;因为上面已失效,所以这里会新生成一个
        session = request.getSession(true);
        String sessionId = session.getId();
        System.out.println("preHandle sessionId=" + sessionId);
        //可以将sessionID存到数据库,redis,内存中;分布式场景中一般会存到redis;此处存在内存中
        sessionIds.add(sessionId);

        //额外业务
        InfoVO infoVO = new InfoVO();
        infoVO.setName("libai");
        session.setAttribute("myKey",infoVO);
    } else {
        String sessionId = request.getSession().getId();
        System.out.println("request sessionId = " + sessionId);

        if (!sessionIds.contains(sessionId)) {
            LOGGER.error("please login first");
            return false;
        }

        //额外业务
        HttpSession session = request.getSession();
        InfoVO myKey =(InfoVO) session.getAttribute("myKey");
        System.out.println(myKey);
    }
    return true;
}
 
同样把Session处理放到拦截器里。可以看到生成Session很简单,就是request.getSession(boolean flag)。flag为false表示获取Session,如果获取不到为null。如果flag为true,如果获取不到,则新生成一个Session。上面的业务场景每次登陆都把原来的Session失效,新生成一个Session。然后把Session对应的SessionId(随机生成的字符串,大概长这样:D8F5058D22978D71D14644777571AD18)存到内存里。再次请求时,Cookie就会附带SessionId(叫JSESSIONID),简单的场景用SessionId就可以判断登陆状态了。复杂场景里,也可以把真个用户信息放到Session里,如上面代码里注释的额外业务里。
 
三. 总结
Cookie有安全问题,因为用户信息直接放到客户端,可以被别人看到。另外Cookie存的信息也有限。
Session有性能问题,因为Session一般也会存额外一些信息,比如可以存购物车信息,存在服务器端,用占用服务器的性能。
posted @   追风fc  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
历史上的今天:
2022-08-02 人生大事--- 选对伴侣
点击右上角即可分享
微信分享提示