前言:

  在前后端项目中, 前端有可能会要求, 后台返回一个 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. 计蒜客 2019 蓝桥杯省赛 B 组模拟赛(三)一笔画

    #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> us ...

  2. 接口约束的另一种方法:Class类的isAssignableFrom

    Class类的isAssignableFrom是个不常用的方法,感觉这个方法的名字取得不是很好,所以有必要在此解析一下,以免在看源码时产生歧义,这个方法的签名如下: public native boo ...

  3. 爸爸在家庭中最应该扮演的角色,是爸爸本爸!zz

    不然呢?还是爸爸应该cosplay什么物种?细想下,爸爸这个角色很多人是不称职的,经常加班或完全不管孩子的隐形人.肆意把脾气撒在孩子身上的炸弹君.动不动就不耐烦的刺猬......孩子经常挂在嘴边的不是 ...

  4. vue学习_01

    一.什么是VUE 渐进式的前端框架,MVVM(Model,view,viewmodel)模式,饿了么用的就是vue框架 二.VUE基本语法 1.引入vue: <script src=" ...

  5. 性能测试---CPU内存部分

    CPU内存的测试可以通过top命令来测试 ,如下是我写的bat脚本,其中的测试进程可以替换为你自己需要测试的进程. @echo offecho============================= ...

  6. 7-unittest和requests重构、封装处理get/post请求

    1.概念说明 ① unittest:python中自带的单元测试框架,封装了一些校验返回的结果方法和一些用例执行前的初始化操作 ② TestCase:测试用例 ③ TestSuite:测试套,即多个测 ...

  7. Java常见开发规范

    1 背景概述 作为程序员大军中的一员,笔者工作于沈阳数通畅联软件技术有限公司.在任职工作的第一天就听领导强调开发规范的重要性,但是笔者心里还想为什么开发规范是最重要的,难道是不应该是实现功能就万事大吉 ...

  8. 816. Ambiguous Coordinates

    We had some 2-dimensional coordinates, like "(1, 3)" or "(2, 0.5)".  Then, we re ...

  9. RichText 富文本开源项目总结

    在Android开发中,我们不免会遇到富文本的编辑和展示的需求,以下是本人之前star的富文本编辑器的开源项目,供大家参考: 一.RichEditor 开源项目地址:https://github.co ...

  10. 吴恩达机器学习笔记8-多变量线性回归(Linear Regression with Multiple Variables)--多维特征

    我们探讨了单变量/特征的回归模型,现在我们对房价模型增加更多的特征,例如房间数楼层等,构成一个含有多个变量的模型,模型中的特征为(