前言:

  在前后端项目中, 前端有可能会要求, 后台返回一个 sessionId 给他, 然后他在请求后台接口时, 把这个sessionId 带给后台, 后台拿到这个sessionId , 就能识别, 是那个用户.

  在shiro中, 会返回一个 JSESSIONID , 其实就是sessionId .

  如果不想把sessionId 放在参数中, 或者贴在链接后面, 暴露给用户, 那么我们还能选择把 sessionId 放在请求头中, 这样比较隐秘一些. 不会那么明显.

一.  DefaultWebSessionManager

  在配置shiro的时候, 我们经常会配置  org.apache.shiro.web.session.mgt.DefaultWebSessionManager , 那么我们先来看看这个类中的相关方法吧.

1. onStart 方法

  

  在这个方法中, 我们其实可以很明显的看到有一个storeSessionId 方法, 在这个方法中, 会将 sessionId 存入到cookie中.

  

  如果我们可以继承这个类, 然后重写onStart方法, 那么是否可以实现, 将sessionId放到响应头中去, 前端可以从响应头中获取到sessionId.

   那既然有处理sesisonId的方法, 那么是否有get sessionId的方法呢? 如果有这个方法, 我们重写它, 改为从请求头中读取sessionid, 不就可以了么.

  那来找一下看看:

  

  确实有的. 里面的具体实现, 就不看了, 不是这篇的主题.

  

二. 自定义 DefaultWebSessionManager 类

import org.apache.commons.lang.StringUtils;
import org.apache.shiro.session.ExpiredSessionException;
import org.apache.shiro.session.InvalidSessionException;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.DefaultSessionManager;
import org.apache.shiro.session.mgt.DelegatingSession;
import org.apache.shiro.session.mgt.SessionContext;
import org.apache.shiro.session.mgt.SessionKey;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.session.mgt.WebSessionKey;
import org.apache.shiro.web.session.mgt.WebSessionManager;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.Serializable; public class DefaultHeaderSessionManager extends DefaultSessionManager implements WebSessionManager { private static final Logger log = LoggerFactory.getLogger(DefaultHeaderSessionManager.class); private final String X_AUTH_TOKEN = "x-auth-token"; @Override
protected void onStart(Session session, SessionContext context) {
//super.onStart(session, context);
if (!WebUtils.isHttp(context)) {
log.debug("SessionContext argument is not HTTP compatible or does not have an HTTP request/response pair. No session ID cookie will be set.");
} else {
HttpServletRequest request = WebUtils.getHttpRequest(context);
HttpServletResponse response = WebUtils.getHttpResponse(context);
Serializable sessionId = session.getId();
this.storeSessionId(sessionId, request, response);
request.removeAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_IS_NEW, Boolean.TRUE);
}
} //获取sessionid
@Override
public Serializable getSessionId(SessionKey key) {
Serializable id = super.getSessionId(key);
if (id == null && WebUtils.isWeb(key)) {
ServletRequest request = WebUtils.getRequest(key);
ServletResponse response = WebUtils.getResponse(key);
id = getSessionId(request, response);
}
return id;
} protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
return this.getReferencedSessionId(request, response);
} // 请求头中获取 sessionId 并把sessionId 放入 response 中
private String getSessionIdHeaderValue(ServletRequest request, ServletResponse response) {
if (!(request instanceof HttpServletRequest)) {
log.debug("Current request is not an HttpServletRequest - cannot get session ID cookie. Returning null.");
return null;
}
else {
HttpServletRequest httpRequest = (HttpServletRequest) request; // 在request 中 读取 x-auth-token 信息 作为 sessionId
String sessionId = httpRequest.getHeader(this.X_AUTH_TOKEN); // 每次读取之后 都把当前的 sessionId 放入 response 中
HttpServletResponse httpResponse = (HttpServletResponse) response; if (StringUtils.isNotEmpty(sessionId)) {
httpResponse.setHeader(this.X_AUTH_TOKEN, sessionId);
log.info("Current session ID is {}", sessionId);
} return sessionId;
}
} //获取sessionid
private Serializable getReferencedSessionId(ServletRequest request, ServletResponse response) {
String id = this.getSessionIdHeaderValue(request, response); //DefaultWebSessionManager 中代码 直接copy过来
if (id != null) {
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, "header");
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
}
//不会把sessionid放在URL后
request.setAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED, Boolean.FALSE);
return id;
} // 移除sessionid 并设置为 deleteMe 标识
private void removeSessionIdHeader(HttpServletRequest request, HttpServletResponse response) {
response.setHeader(this.X_AUTH_TOKEN, "deleteMe");
} /**
* 把sessionId 放入 response header 中
* onStart时调用
* 没有sessionid时 会产生sessionid 并放入 response header中
*/
private void storeSessionId(Serializable currentId, HttpServletRequest ignored, HttpServletResponse response) {
if (currentId == null) {
String msg = "sessionId cannot be null when persisting for subsequent requests.";
throw new IllegalArgumentException(msg);
} else {
String idString = currentId.toString(); response.setHeader(this.X_AUTH_TOKEN, idString); log.info("Set session ID header for session with id {}", idString); log.trace("Set session ID header for session with id {}", idString);
}
} // 创建session
@Override
protected Session createExposedSession(Session session, SessionContext context) {
if (!WebUtils.isWeb(context)) {
return super.createExposedSession(session, context);
} else {
ServletRequest request = WebUtils.getRequest(context);
ServletResponse response = WebUtils.getResponse(context);
SessionKey key = new WebSessionKey(session.getId(), request, response);
return new DelegatingSession(this, key);
}
} @Override
protected Session createExposedSession(Session session, SessionKey key) {
if (!WebUtils.isWeb(key)) {
return super.createExposedSession(session, key);
} else {
ServletRequest request = WebUtils.getRequest(key);
ServletResponse response = WebUtils.getResponse(key);
SessionKey sessionKey = new WebSessionKey(session.getId(), request, response);
return new DelegatingSession(this, sessionKey);
}
} @Override
protected void onExpiration(Session s, ExpiredSessionException ese, SessionKey key) {
super.onExpiration(s, ese, key);
this.onInvalidation(key);
} @Override
protected void onInvalidation(Session session, InvalidSessionException ise, SessionKey key) {
super.onInvalidation(session, ise, key);
this.onInvalidation(key);
} private void onInvalidation(SessionKey key) {
ServletRequest request = WebUtils.getRequest(key);
if (request != null) {
request.removeAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID);
} if (WebUtils.isHttp(key)) {
log.debug("Referenced session was invalid. Removing session ID header.");
this.removeSessionIdHeader(WebUtils.getHttpRequest(key), WebUtils.getHttpResponse(key));
} else {
log.debug("SessionKey argument is not HTTP compatible or does not have an HTTP request/response pair. Session ID cookie will not be removed due to invalidated session.");
} } @Override
protected void onStop(Session session, SessionKey key) {
super.onStop(session, key);
if (WebUtils.isHttp(key)) {
HttpServletRequest request = WebUtils.getHttpRequest(key);
HttpServletResponse response = WebUtils.getHttpResponse(key);
log.debug("Session has been stopped (subject logout or explicit stop). Removing session ID cookie.");
this.removeSessionIdHeader(request, response);
} else {
log.debug("SessionKey argument is not HTTP compatible or does not have an HTTP request/response pair. Session ID cookie will not be removed due to stopped session.");
}
} @Override
public boolean isServletContainerSessions() {
return false;
} }

三. 配置

<bean id="sessionManager" class="ccdc.zykt.web.shiro.headtoken.DefaultHeaderSessionManager">
<property name="sessionDAO" ref="sessionDAO"/>
<property name="globalSessionTimeout" value="3600000"/>
<property name="sessionValidationInterval" value="3600000"/>
</bean>
<bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"/>

四. 演示方法

1. 通过浏览器访问登录接口, 拿到sessionId, 也就是这里的 x-auth-token

2. 打开postman, 将x-auth-token放入到请求头中, 在访问接口

确实可以识别用户, 拿到数据.

shiro 获取请求头中的 sessionId的更多相关文章

  1. shiro 获取请求头中的 rememberMe

    前言: 上一篇提到了, 将 sessionId 放到请求头中去, 那rememberMe是否也可以放到请求头中去呢. 其实不管是sessionId还是rememberMe, shiro都会默认往coo ...

  2. WebAPi获取请求头中对应键值

    /// <summary> /// 依据键获取请求头中值数据 /// </summary> /// <param name="request"> ...

  3. 获取请求头中User-Agent工具类

    public class AgentUserKit { private static String pattern = "^Mozilla/\\d\\.\\d\\s+\\(+.+?\\)&q ...

  4. 【工具类】获取请求头中User-Agent工具类

    public class AgentUserKit { private static String pattern = "^Mozilla/\\d\\.\\d\\s+\\(+.+?\\)&q ...

  5. 获取请求 header 中指定字段的值

    private function getHeader($name) {//获取请求头中$name的值 $name = 'HTTP_' . $name; foreach ($_SERVER as $ke ...

  6. shiro + jwt 实现 请求头中的 rememberMe 时间限制功能

    前言: 上一篇提出, 通过修改 rememberMe 的编码来实现 rememberMe的功能的设想, 事后我去尝试实现了一番, 发现太麻烦, 还是不要那么做吧. 程序还是要越简单越好. 那功能总是要 ...

  7. HTTP 请求头中的 Remote_Addr,X-Forwarded-For,X-Real-IP

    REMOTE_ADDR 表示发出请求的远程主机的 IP 地址,remote_addr代表客户端的IP,但它的值不是由客户端提供的,而是服务端根据客户端的ip指定的,当你的浏览器访问某个网站时,假设中间 ...

  8. Ajax 请求头中常见content-type

    四种常见的 POST 提交数据方式 HTTP 协议是以 ASCII 码传输,建立在 TCP/IP 协议之上的应用层规范.规范把 HTTP 请求分为三个部分:状态行.请求头.消息主体.协议规定 POST ...

  9. HTTP 请求头中的 X-Forwarded-For(转)

    原文:https://imququ.com/post/x-forwarded-for-header-in-http.html 我一直认为,对于从事 Web 前端开发的同学来说,HTTP 协议以及其他常 ...

随机推荐

  1. django中views中方法的request参数

    知其然亦要知其所以然 views每个方法的参数都是request,那么问题来了,request为何物? 首先,几乎每个方法都是取数据(无论是从数据库,还是从第三方接口),然后进行一定的处理,之后传给前 ...

  2. HTML表单标签

    <form>标签 1.在HTML中,<form></form>标记对用来创建一个表单,即定义表单的开始和结束位置,在标记对之间的一切都属于表单的内容.每个表单元素开 ...

  3. 移动端--用PX为单位+JS框架 实现页面布局

    一:大家先下载metahandler.js 二:准备一个用px实现的移动页面(宽度固定死的页面),引入metahandler.js框架 1.视口设置 width=640,是根据psd图来设置,有多宽设 ...

  4. C++ STL next_permutation(快速排列组合)

    排列组合必备!! https://blog.csdn.net/bengshakalakaka/article/details/78515480

  5. js的window.open()改写

    说明:window.open(url,"_blank")方法替换如下: function openUrl(url) { try { if (/MSIE\s*(\d+\.\d+);/ ...

  6. 转 Refresh Excel Pivot Tables Automatically Using SSIS Script Task

    Refresh Excel Pivot Tables Automatically Using SSIS Script Task https://www.mssqltips.com/sqlservert ...

  7. NLP文本相似度

    NLP文本相似度 相似度 相似度度量:计算个体间相似程度 相似度值越小,距离越大,相似度值越大,距离越小 最常用--余弦相似度:​ 一个向量空间中两个向量夹角的余弦值作为衡量两个个体之间差异的大小 余 ...

  8. iptables log日志记录功能扩展应用:iptables自动配置临时访问策略,任意公网登录服务器

    一.修改日志记录: 1. 修改配置文件: vi /etc/rsyslog.conf 添加以下内容 #iptables log kern.=notice /var/log/iptables.log 2. ...

  9. 《Java性能调优》学习笔记(1)

    性能的参考指标 执行时间 -- 从代码开始运行到结束的时间 CPU时间 -- 函数或者线程占用CPU的时间 内存分配 -- 程序在运行时占用内存的情况 磁盘吞吐量 -- 描述IO的使用情况 网络吞吐量 ...

  10. Windows Server2012 搭建域错误“本地Administraor账户不需要密码”

    标签:MSSQL/SQLServer/域控制器提升的先决条件验证失败/密码不符合要求 概述 在安装WindowsServer2012域控出现administrator账户密码不符合要求的错误,但是实际 ...