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 协议以及其他常 ...
随机推荐
- CODEFORCES ROUND #740 ANALYSES BY TEAM:RED & BLACK
A.Alyona and copybooks Problems: 给你一个数n和代价分别为a, b, c.数量不限的1, 2, 3,求将n凑成4的倍数的最小代价 Analysis: cj:取个模随便凑 ...
- 使用ServletContextListener关闭Redisson连接
ServletContextListener 监听器 在 Servlet API 中有一个 ServletContextListener 接口,它能够监听 ServletContext 对象的生命周 ...
- 作业 -- 几道简单的Python题
1.编写程序,要求生成10240个随机[0,512)之间的整数,并统计每个元素出现的次数. 2.编写程序,要求当用户输入一个列表和两个整数作为下标时,程序可以使用切片获取并输出列表中截取两个下标之间的 ...
- 不同后台服务器共用同一session
建一个类继承SessionStateStoreProviderBase类,override Initialize.SetAndReleaseItemExclusive.ReleaseItemExclu ...
- cv2.cvtColor Unsupported depth of input image
源代码 import cv2 import numpy as ny img = ny.zeros( ( 3 , 3 )) img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB) ...
- socket的阻塞与非阻塞,同步与非同步
网络编程中通常提到四种方式,同步/异步,阻塞/非阻塞.以下对它们的概念进行总结 1.同步/异步:主要针对C端 同步:所谓同步,就是在C端发出一个功能调用时,在没有得到结果之前,调用不返回,也就是必须一 ...
- hdu 4370
这个题说实话我没看出来,我看的别人的博客 https://blog.csdn.net/u013761036/article/details/39377499 这个人讲的很清楚,可以直接去看他的 题目给 ...
- 可参数化的带优先级的数据选择器的FPGA实现方式探讨
在FPGA设计中,大部分情况下我们都得使用到数据选择器.并且为了设计参数化,可调,通常情况下我们需要一个参数可调的数据选择器,比如M选1,M是可调的参数. 如果,数据选择器是不带优先级的,我们可以使用 ...
- 调用接口,发送https请求
调用https接口有两种方式 一:是导入证书; 证书调用https请求本人还不知道,希望看见此博客的大神给我回复. 二:是创建信任管理器. 第一步:实现X509TrustManager接口,里面的方法 ...
- 背水一战 Windows 10 (108) - 通知(Tile): application tile 基础, secondary tile 基础
[源码下载] 背水一战 Windows 10 (108) - 通知(Tile): application tile 基础, secondary tile 基础 作者:webabcd 介绍背水一战 Wi ...