shiro 获取请求头中的 rememberMe
前言:
上一篇提到了, 将 sessionId 放到请求头中去, 那rememberMe是否也可以放到请求头中去呢.
其实不管是sessionId还是rememberMe, shiro都会默认往cookie里面放, 那么rememberMe肯定也是可以放到请求头中去的.
有兴趣的朋友可以去看看 org.apache.shiro.web.mgt.CookieRememberMeManager 的实现.
废话不多说了, 直接上实现吧.
一. 实现
import org.apache.shiro.codec.Base64;
import org.apache.shiro.mgt.AbstractRememberMeManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.subject.SubjectContext;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.subject.WebSubjectContext;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; public class HeaderRememberMeManager extends AbstractRememberMeManager { private static final Logger log = LoggerFactory.getLogger(HeaderRememberMeManager.class); // header 中 固定使用的 key
public static final String DEFAULT_REMEMBER_ME_HEADER_NAME = "remember-me"; @Override
protected void rememberSerializedIdentity(Subject subject, byte[] serialized) {
if (!WebUtils.isHttp(subject)) {
if (log.isDebugEnabled()) {
String msg = "Subject argument is not an HTTP-aware instance. This is required to obtain a servlet request and response in order to set the rememberMe cookie. Returning immediately and ignoring rememberMe operation.";
log.debug(msg);
} } else {
HttpServletResponse response = WebUtils.getHttpResponse(subject);
String base64 = Base64.encodeToString(serialized);
// 设置 rememberMe 信息到 response header 中
response.setHeader(DEFAULT_REMEMBER_ME_HEADER_NAME, base64);
}
} private boolean isIdentityRemoved(WebSubjectContext subjectContext) {
ServletRequest request = subjectContext.resolveServletRequest();
if (request == null) {
return false;
} else {
Boolean removed = (Boolean) request.getAttribute(ShiroHttpServletRequest.IDENTITY_REMOVED_KEY);
return removed != null && removed;
}
} @Override
protected byte[] getRememberedSerializedIdentity(SubjectContext subjectContext) {
if (!WebUtils.isHttp(subjectContext)) {
if (log.isDebugEnabled()) {
String msg = "SubjectContext argument is not an HTTP-aware instance. This is required to obtain a servlet request and response in order to retrieve the rememberMe cookie. Returning immediately and ignoring rememberMe operation.";
log.debug(msg);
} return null;
} else {
WebSubjectContext wsc = (WebSubjectContext) subjectContext;
if (this.isIdentityRemoved(wsc)) {
return null;
} else {
HttpServletRequest request = WebUtils.getHttpRequest(wsc);
// 在request header 中获取 rememberMe信息
String base64 = request.getHeader(DEFAULT_REMEMBER_ME_HEADER_NAME);
if ("deleteMe".equals(base64)) {
return null;
} else if (base64 != null) {
base64 = this.ensurePadding(base64);
if (log.isTraceEnabled()) {
log.trace("Acquired Base64 encoded identity [" + base64 + "]");
} byte[] decoded = Base64.decode(base64);
if (log.isTraceEnabled()) {
log.trace("Base64 decoded byte array length: " + (decoded != null ? decoded.length : 0) + " bytes.");
} return decoded;
} else {
return null;
}
}
}
} private String ensurePadding(String base64) {
int length = base64.length();
if (length % 4 != 0) {
StringBuilder sb = new StringBuilder(base64); for (int i = 0; i < length % 4; ++i) {
sb.append('=');
} base64 = sb.toString();
} return base64;
} @Override
protected void forgetIdentity(Subject subject) {
if (WebUtils.isHttp(subject)) {
HttpServletRequest request = WebUtils.getHttpRequest(subject);
HttpServletResponse response = WebUtils.getHttpResponse(subject);
this.forgetIdentity(request, response);
} } @Override
public void forgetIdentity(SubjectContext subjectContext) {
if (WebUtils.isHttp(subjectContext)) {
HttpServletRequest request = WebUtils.getHttpRequest(subjectContext);
HttpServletResponse response = WebUtils.getHttpResponse(subjectContext);
this.forgetIdentity(request, response);
}
} private void forgetIdentity(HttpServletRequest request, HttpServletResponse response) {
//设置删除标示
response.setHeader(DEFAULT_REMEMBER_ME_HEADER_NAME, "deleteMe");
}
}
二. 配置
<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="MD5"/>
<property name="hashIterations" value="1"/>
<property name="storedCredentialsHexEncoded" value="true"/>
</bean> <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"/> <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"/> <bean id="rememberMeManager" class="web.shiro.headtoken.HeaderRememberMeManager">
<property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}"/>
<!-- <property name="cookie" ref="rememberMeCookie" />-->
</bean> <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<constructor-arg value="rememberMe"/>
<property name="httpOnly" value="true"/>
<property name="maxAge" value="2592000"/><!-- 30天 -->
</bean> <bean id="sessionManager" class="web.shiro.headtoken.DefaultHeaderSessionManager">
<property name="sessionDAO" ref="sessionDAO"/>
<!-- <property name="sessionIdCookie" ref="sessionIdCookie"/>-->
<property name="globalSessionTimeout" value="3600000"/>
<property name="sessionValidationInterval" value="3600000"/>
</bean> <bean id="shiroRealm" class="web.shiro.ShiroRealm">
<property name="credentialsMatcher" ref="credentialsMatcher"/>
<property name="authenticationCachingEnabled" value="true"/>
<property name="authenticationCacheName" value="authenticationCache"/>
<property name="authorizationCachingEnabled" value="true"/>
<property name="authorizationCacheName" value="authorizationCache"/>
</bean> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="sessionManager" ref="sessionManager"/>
<property name="realm" ref="shiroRealm"/>
<property name="cacheManager" ref="cacheManager"/>
<!-- 定义RememberMe的管理器 -->
<property name="rememberMeManager" ref="rememberMeManager"/>
</bean> <bean name="loginFilter" class="web.shiro.filter.JsonAuthLoginFilter" /> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="${shiro.loginUrl}"/>
<property name="filters">
<map>
<entry key="login" value-ref="loginFilter" />
</map>
</property>
<property name="filterChainDefinitions">
<value>
/logout=logout
/user/retrievePwd = anon
/user/signOut = anon
/user/loginGet = anon
/swagger-ui.html = anon
/swagger-resources = anon
/swagger-resources/** = anon
/v2/api-docs = anon
/webjars/** = anon
/webjars/springfox-swagger-ui/** = anon
/user/login = anon
/user/register = anon
/** = login
</value>
</property>
</bean> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor"/> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean>
三. 测试方法
1. 通过浏览器登录, 获取到rememberMe

2. 通过postman, 访问接口

这里其实有个问题, 以前这里用cookie的时候, 还能有个cookie的过期时间影响, 比如cookie只保持30天, 那么过了30天之后, 这个cookie不能再使用了, rememberMe就不能使用了.
但是在这里, 却没有这个功能了, 如果想把这个功能加上去, 就必须重写更多的方法来实现这个功能.
比如, 我们可以将过期时间, 加入到 rememberMe中去, 当然, 必须要经过编码才行, 不能太明显. 这样, 来保证rememberMe的过期后, 需要再去登录.
shiro 获取请求头中的 rememberMe的更多相关文章
- shiro 获取请求头中的 sessionId
前言: 在前后端项目中, 前端有可能会要求, 后台返回一个 sessionId 给他, 然后他在请求后台接口时, 把这个sessionId 带给后台, 后台拿到这个sessionId , 就能识别, ...
- WebAPi获取请求头中对应键值
/// <summary> /// 依据键获取请求头中值数据 /// </summary> /// <param name="request"> ...
- shiro + jwt 实现 请求头中的 rememberMe 时间限制功能
前言: 上一篇提出, 通过修改 rememberMe 的编码来实现 rememberMe的功能的设想, 事后我去尝试实现了一番, 发现太麻烦, 还是不要那么做吧. 程序还是要越简单越好. 那功能总是要 ...
- 获取请求头中User-Agent工具类
public class AgentUserKit { private static String pattern = "^Mozilla/\\d\\.\\d\\s+\\(+.+?\\)&q ...
- 【工具类】获取请求头中User-Agent工具类
public class AgentUserKit { private static String pattern = "^Mozilla/\\d\\.\\d\\s+\\(+.+?\\)&q ...
- 获取请求 header 中指定字段的值
private function getHeader($name) {//获取请求头中$name的值 $name = 'HTTP_' . $name; foreach ($_SERVER as $ke ...
- HTTP 请求头中的 Remote_Addr,X-Forwarded-For,X-Real-IP
REMOTE_ADDR 表示发出请求的远程主机的 IP 地址,remote_addr代表客户端的IP,但它的值不是由客户端提供的,而是服务端根据客户端的ip指定的,当你的浏览器访问某个网站时,假设中间 ...
- Ajax 请求头中常见content-type
四种常见的 POST 提交数据方式 HTTP 协议是以 ASCII 码传输,建立在 TCP/IP 协议之上的应用层规范.规范把 HTTP 请求分为三个部分:状态行.请求头.消息主体.协议规定 POST ...
- HTTP 请求头中的 X-Forwarded-For(转)
原文:https://imququ.com/post/x-forwarded-for-header-in-http.html 我一直认为,对于从事 Web 前端开发的同学来说,HTTP 协议以及其他常 ...
随机推荐
- Eclipse的设置
1 Eclipse的工作空间和新建工程 1.1: 工作空间 * 其实就是我们写的源代码所在的目录 1.2: 创建工程(项目) * 右键/Package Explore 空白区/new /Java Pr ...
- 前台js接收后台的json数据
后台返回的json数据,如php的: return json_encode($data); 在前台 js接收如下: function json2object(str){ var jsstr = str ...
- Day06 (黑客成长日记) 初识函数和返回值的作用
定义函数: 1.初识函数: 我们在学习字符串时,有这样的操作: li = 'tsy be ba bvake ' print(len(li)) 这样可以打印出li的长度,我们利用了python中的len ...
- js监听全屏下的esc事件
window.onresize = function() { if (!checkFull()) { //触发esc事件,执行业务逻辑. } }; function checkFull() { var ...
- Lucene用法示例
整理一下 ELK 和 Grafana 中会用到的 Lucene 用法: 通配符 示例1:过滤出 url 中包含 .pw/ 的 网址 url.keyword:*.pw\/* 正则表达式 示例1:过滤出 ...
- JavaGC学习笔记
1.简介Java在JVM虚拟机上的垃圾回收(GC)机制,在合适的时间触发垃圾回收,将不需要的内存空间回收释放,避免无限制的内存增长导致的OOM. 1.1 Java堆内存结构Java将堆内存分为3大部分 ...
- SolrCloud的搭建与稳定性测试
转载请注明出处:http://www.cnblogs.com/wubdut/p/7573738.html 一.集群搭建 1. zookeeper搭建(版本:3.4) 1.1 zoo.cfg配置文件: ...
- mysql的一点小错误
当使用sql语句时,字段记得使用``反向单引号,而不是单引号
- FPGA中带优先级的if else if与不带优先级的case的探讨
我们知道在书本上都说让我们尽量使用不带优先级的的数据选择器,今天我们就来探讨一下二者的区别. 例子1:带优先级的的数据选择器,综合成功,且没有任何警告. module detection_prio # ...
- 自动化单元测试工具 EvoSuite 的简单使用 【转载】
转载:https://www.cnblogs.com/hughding/p/evosuite.html 一.EvoSuite简介 EvoSuite是由Sheffield等大学联合开发的一种开源工具,用 ...