前言:

  上一篇提到了, 将 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的更多相关文章

  1. shiro 获取请求头中的 sessionId

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

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

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

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

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

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

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

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

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

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

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

  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. JPA-04

    一.JPQL JPA的查询语言(和SQL非常像,面向对象的查询语言) 有list集合可以用size看长度 分页:setFirstResult().setMaxResults(); 获取总条数:getS ...

  2. fortran常用语句--读写带注释文档、动态数组等语法

    1.判断读取文档有多少行数据(文档最后的空行不计入其中): 首先在变量定义区域下方和执行语句前声明在程序中要被调用的GetFileN函数: external GetFileN 接下来在函数外部后边写上 ...

  3. java.lang.RuntimeException: Invalid action class configuration that references an unknown class name

    ---恢复内容开始--- 转自 : https://www.cnblogs.com/javawebsoa/archive/2013/05/25/3098190.html java.lang.Runti ...

  4. POJ2947-Widget Factory

    工厂里每件期间的生产时间为3-9天,告诉你有N个器件和M个计划,每个计划都是说明生产1-N号器件的时间,最后问你每件器件的生产时间.或者多解或没有解. 例如样例 2 3 2 MON THU 1 2 3 ...

  5. ubuntu hadoop环境搭建

    安装Ubuntu系统:这个自行安装 下载jdk:我下的是1.8.0_141d的,下载好后在usr/lib下新建一个jvm的文件夹用来存放Java的文件,下载好的jdk可以在其他地方解压或者jvm里面解 ...

  6. noip第28课资料

  7. python猜数字GUI版本V0.2

    使用类方式编写猜数字游戏GUI版本. 思路:初始化数字以及初始化wegdits,编写button click event判断代码的函数,每猜一次点击button调用一次该函数,并计算猜的次数.如果猜对 ...

  8. HDU1263水果

    //#include<bits/stdc++.h> #include<map> #include<cstdio> #include<string> #i ...

  9. Eigen3安装及注意

    执行命令: sudo apt-get install libeigen3-dev 安装后执行以下命令 运行命令: sudo cp -r /usr/include/eigen3/Eigen /usr/i ...

  10. TCP/IP(一)之开启计算机网络之路

    阅读目录(Content) 一.局域网.广域网和Internet 1.1.局域网 1.2.广域网 1.3.Internet 二.计算机数据之间通信的过程 2.1.路由器的功能(转发收到的分组) 三.O ...