前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Shiro会话管理/前后分离身份鉴别原理

Shiro会话管理/前后分离身份鉴别原理

作者头像
devi
发布2021-08-19 15:02:38
1.3K0
发布2021-08-19 15:02:38
举报
文章被收录于专栏:搬砖记录搬砖记录

目录


我们常用 SecurityUtils.getSubject().getPrincipal();获取当前登录用户信息,但是这个方法是如何获得用户信息的?Shiro又是如何区分不同用户的身份的?

问题1. SecurityUtils.getSubject().getPrincipal()返回类型;

查看源码得知它是Object,但是实际上,他的返回类型由我们控制。

在Realm类中有个doGetAuthenticationInfo方法,我们常在这里进行登录逻辑处理,其返回类型是AuthenticationInfo,我们通常使用SimpleAuthenticationInfo,追进去可以看到其第一个参数就是principal,即我们的用户类型:

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

因此,如果我们最终

代码语言:javascript
复制
User user = new User();
user.setPassword("111");
user.setName("sxuer");
return new SimpleAuthenticationInfo(user, user.getPassword(), getName());

则SecurityUtils.getSubject().getPrincipal()将得到User类。 若

代码语言:javascript
复制
String user = "sxuer";
return new SimpleAuthenticationInfo(user, "123", user);

则SecurityUtils.getSubject().getPrincipal()将得到字符串。

问题2. Shiro如何利用session保持会话

先说结果:

  • 若使用Shiro默认的session会话管理:用户登录–>创建session–>创建cookie–>用户二次访问–>从cookie中读取sessionId–>根据sessionId取得用户身份
  • 若使用自定义的session会话管理,适用于前后分离(但需要解决跨域cookie禁止问题):用户登录,同时携带sId–>检查到sId参数,使用自定义getsessionId方法–>保存sessionId到cookie中–>用户二次访问,携带sessionId–>根据sessionId取得用户身份

上述两者的主要区别在于,第二种用户登录时,需要携带一个额外的参数,用于创建后续访问的sessionId。

原理

很容易得知,Shiro中有个会话管理器DefaultWebSessionManager,既然Shiro使用session保持会话,那么核心就在于session的创建以及获取(校验)。

DefaultWebSessionManager中有个getSessionId方法,向上追溯,可以发现Shiro会从request中查询cookie,如果找到了,那就作为sessionId保存–>可以得出,sessionId其实是由客户端控制的。如果从cookie中没找到,就从uri中读取JSESSIONID参数,如果依旧没有,就会抛出找不到的异常。

我们可以重写getSessionId方法,从而实现session的定制(若将cache换成redis,就跟传统上使用redis保存token的原理基本一致)。

假设重写的getSessionId如下:

代码语言:javascript
复制
protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
        // 如果参数中包含“__sid”参数,则使用此sid会话。 例如:http://localhost/project?__sid=xxx&__cookie=true
        String sid = request.getParameter("__sid");
        if (StringUtils.isNotBlank(sid)) {
            // 是否将sid保存到cookie,浏览器模式下使用此参数。
            if (WebUtils.isTrue(request, "__cookie")) {
                HttpServletRequest rq = (HttpServletRequest) request;
                HttpServletResponse rs = (HttpServletResponse) response;
                Cookie template = getSessionIdCookie();
                Cookie cookie = new SimpleCookie(template);
                cookie.setValue(sid);
                cookie.saveTo(rq, rs);
            }
            // 设置当前session状态
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
                    ShiroHttpServletRequest.URL_SESSION_ID_SOURCE); // session来源与url
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sid);
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
            return sid;
        } else {
            return super.getSessionId(request, response);
        }
    }

当用户登录时,携带了参数__sid=1,那么Shiro会利用该参数创建session,但是并非该值就是session。

Shiro中有个类叫做SessionDao,显然是用于创建Session的,我们进入查看,会发现有个doCreate,阅读之后可以发现,他会利用sessionIdGenerator生成sessionId,然后使用assignSessionId(session, sessionId)将sessionId设置到session对象中。然后在Cache类中(如CachingSessionDao)以sessionId:session作为键值对保存。

获取sessionId: 从cookie中获取session 若为空,则创建session,保存到cookie中,保存到本地Cache中

相关方法: getSessionId(ServletRequest request, ServletResponse response) getSessionIdCookieValue(request, response) readValue(HttpServletRequest request, HttpServletResponse ignored) getCookie(request, name) cookie.getValue(); request.setAttribute

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-11-19 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 目录
  • 问题1. SecurityUtils.getSubject().getPrincipal()返回类型;
  • 问题2. Shiro如何利用session保持会话
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档