我们常用 SecurityUtils.getSubject().getPrincipal();获取当前登录用户信息,但是这个方法是如何获得用户信息的?Shiro又是如何区分不同用户的身份的?
查看源码得知它是Object,但是实际上,他的返回类型由我们控制。
在Realm类中有个doGetAuthenticationInfo方法,我们常在这里进行登录逻辑处理,其返回类型是AuthenticationInfo
,我们通常使用SimpleAuthenticationInfo
,追进去可以看到其第一个参数就是principal,即我们的用户类型:
因此,如果我们最终
User user = new User();
user.setPassword("111");
user.setName("sxuer");
return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
则SecurityUtils.getSubject().getPrincipal()将得到User类。 若
String user = "sxuer";
return new SimpleAuthenticationInfo(user, "123", user);
则SecurityUtils.getSubject().getPrincipal()将得到字符串。
先说结果:
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如下:
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
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有