shiro是如何实现session管理的(关于shiro刷新最后一次请求时间来控制session超时)
1、session的创建在用户登录的时候查创建成功,然后可以通过 SessionDao 这个类获取到关于session的一些信息,比如:session的 session.getLastAccessTime()最后一次刷新时间,session的 超时时间session.getTimeout()(这里的这个超时时间是静默多长时间session自动失效),还有sessionId session.getId(),
2、session的失效时间是通过 session.getLastAccessTime()这个去判断的,也就是通过session的最后一次刷新时间去判断,而session最后一次操作时间是由shiro框架自动去刷新,调用的是touch()方法,而具体的实现是通过这个AbstractShiroFilter类实现的,而这类实现是继承自OncePerrequestFilter 这个类,实现了其中的 doFilterInternal 这个方法实现的,而AbstractShiroFilter 类是通过ShiroFilterFactoryBean 中的一个内部类SpringShiroFilter 这个类的构造方法来调用。 而ShiroFilterFactoryBean这个类又是通过DelegatingFilterProxy 代理来调用,这个DelegatingFilterProxy 代理最后注册到filterRegistrationBean 这个类中,实现了shiro的功能。
3、解决思路,由于之前项目中已经有了代理类代理咱的shiroFilter 过滤器。代码如下:
@Bean
public FilterRegistrationBean delegatingFilterProxy(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
DelegatingFilterProxy proxy = new DelegatingFilterProxy();
proxy.setTargetFilterLifecycle(true);
proxy.setTargetBeanName("shiroFilter");//这里代理了shiroFilter
filterRegistrationBean.setFilter(proxy);
return filterRegistrationBean;
}
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();//这里还是原来的类ShiroFilterFactoryBean,后面将会改写
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 拦截器
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/**", "anon");
//filterChainDefinitionMap.put("/system/submitLogin", "anon");
//filterChainDefinitionMap.put("/**", "authc");
//配置退出过滤器,其中的具体代码Shiro已经替我们实现了
//filterChainDefinitionMap.put("/logout", "logout");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
/*
* 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
* shiroFilterFactoryBean.setLoginUrl("/login");
* shiroFilterFactoryBean.setSuccessUrl("/index");
* shiroFilterFactoryBean.setUnauthorizedUrl("/403");
*/
//Map<String, Filter> filters = new LinkedHashMap<>();
//filters.put("authc" , new CustomAuthenticationFilter());
//shiroFilterFactoryBean.setFilters(filters);
return shiroFilterFactoryBean;
}
4、现在新建两个类来是实现之前shiro框架中 相当于 ShiroFilterFactoryBean 和 AbstractShiroFilter 这个类的功能,
package com.qzt.config.shiro.filter;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.Filter;
import org.apache.shiro.config.Ini;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.util.CollectionUtils;
import org.apache.shiro.util.Nameable;
import org.apache.shiro.util.StringUtils;
import org.apache.shiro.web.config.IniFilterChainResolverFactory;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.apache.shiro.web.filter.authc.AuthenticationFilter;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;
import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
import org.apache.shiro.web.filter.mgt.FilterChainManager;
import org.apache.shiro.web.filter.mgt.FilterChainResolver;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.mgt.WebSecurityManager;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class ExtendShiroFilterFactoryBean implements FactoryBean, BeanPostProcessor {
private static transient final Logger log = LoggerFactory.getLogger(ShiroFilterFactoryBean.class);
private SecurityManager securityManager;
private Map<String, Filter> filters;
private Map<String, String> filterChainDefinitionMap; //urlPathExpression_to_comma-delimited-filter-chain-definition
private String loginUrl;
private String successUrl;
private String unauthorizedUrl;
private ExtendAbstractShiroFilter instance;
public ExtendShiroFilterFactoryBean() {
this.filters = new LinkedHashMap<String, Filter>();
this.filterChainDefinitionMap = new LinkedHashMap<String, String>(); //order matters!
}
public SecurityManager getSecurityManager() {
return securityManager;
}
public void setSecurityManager(SecurityManager securityManager) {
this.securityManager = securityManager;
}
public String getLoginUrl() {
return loginUrl;
}
public void setLoginUrl(String loginUrl) {
this.loginUrl = loginUrl;
}
public String getSuccessUrl() {
return successUrl;
}
public void setSuccessUrl(String successUrl) {
this.successUrl = successUrl;
}
public String getUnauthorizedUrl() {
return unauthorizedUrl;
}
public void setUnauthorizedUrl(String unauthorizedUrl) {
this.unauthorizedUrl = unauthorizedUrl;
}
public Map<String, Filter> getFilters() {
return filters;
}
public void setFilters(Map<String, Filter> filters) {
this.filters = filters;
}
public Map<String, String> getFilterChainDefinitionMap() {
return filterChainDefinitionMap;
}
public void setFilterChainDefinitionMap(Map<String, String> filterChainDefinitionMap) {
this.filterChainDefinitionMap = filterChainDefinitionMap;
}
public void setFilterChainDefinitions(String definitions) {
Ini ini = new Ini();
ini.load(definitions);
Ini.Section section = ini.getSection(IniFilterChainResolverFactory.URLS);
if (CollectionUtils.isEmpty(section)) {
section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
}
setFilterChainDefinitionMap(section);
}
public Object getObject() throws Exception {
if (instance == null) {
instance = createInstance();
}
return instance;
}
public Class getObjectType() {
return SpringShiroFilter.class;
}
public boolean isSingleton() {
return true;
}
protected FilterChainManager createFilterChainManager() {
DefaultFilterChainManager manager = new DefaultFilterChainManager();
Map<String, Filter> defaultFilters = manager.getFilters();
for (Filter filter : defaultFilters.values()) {
applyGlobalPropertiesIfNecessary(filter);
}
Map<String, Filter> filters = getFilters();
if (!CollectionUtils.isEmpty(filters)) {
for (Map.Entry<String, Filter> entry : filters.entrySet()) {
String name = entry.getKey();
Filter filter = entry.getValue();
applyGlobalPropertiesIfNecessary(filter);
if (filter instanceof Nameable) {
((Nameable) filter).setName(name);
}
manager.addFilter(name, filter, false);
}
}
//build up the chains:
Map<String, String> chains = getFilterChainDefinitionMap();
if (!CollectionUtils.isEmpty(chains)) {
for (Map.Entry<String, String> entry : chains.entrySet()) {
String url = entry.getKey();
String chainDefinition = entry.getValue();
manager.createChain(url, chainDefinition);
}
}
return manager;
}
protected ExtendAbstractShiroFilter createInstance() throws Exception {
log.debug("Creating Shiro Filter instance.");
SecurityManager securityManager = getSecurityManager();
if (securityManager == null) {
String msg = "SecurityManager property must be set.";
throw new BeanInitializationException(msg);
}
if (!(securityManager instanceof WebSecurityManager)) {
String msg = "The security manager does not implement the WebSecurityManager interface.";
throw new BeanInitializationException(msg);
}
FilterChainManager manager = createFilterChainManager();
PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
chainResolver.setFilterChainManager(manager);
return new SpringShiroFilter((WebSecurityManager) securityManager, chainResolver);
}
private void applyLoginUrlIfNecessary(Filter filter) {
String loginUrl = getLoginUrl();
if (StringUtils.hasText(loginUrl) && (filter instanceof AccessControlFilter)) {
AccessControlFilter acFilter = (AccessControlFilter) filter;
//only apply the login url if they haven't explicitly configured one already:
String existingLoginUrl = acFilter.getLoginUrl();
if (AccessControlFilter.DEFAULT_LOGIN_URL.equals(existingLoginUrl)) {
acFilter.setLoginUrl(loginUrl);
}
}
}
private void applySuccessUrlIfNecessary(Filter filter) {
String successUrl = getSuccessUrl();
if (StringUtils.hasText(successUrl) && (filter instanceof AuthenticationFilter)) {
AuthenticationFilter authcFilter = (AuthenticationFilter) filter;
//only apply the successUrl if they haven't explicitly configured one already:
String existingSuccessUrl = authcFilter.getSuccessUrl();
if (AuthenticationFilter.DEFAULT_SUCCESS_URL.equals(existingSuccessUrl)) {
authcFilter.setSuccessUrl(successUrl);
}
}
}
private void applyUnauthorizedUrlIfNecessary(Filter filter) {
String unauthorizedUrl = getUnauthorizedUrl();
if (StringUtils.hasText(unauthorizedUrl) && (filter instanceof AuthorizationFilter)) {
AuthorizationFilter authzFilter = (AuthorizationFilter) filter;
//only apply the unauthorizedUrl if they haven't explicitly configured one already:
String existingUnauthorizedUrl = authzFilter.getUnauthorizedUrl();
if (existingUnauthorizedUrl == null) {
authzFilter.setUnauthorizedUrl(unauthorizedUrl);
}
}
}
private void applyGlobalPropertiesIfNecessary(Filter filter) {
applyLoginUrlIfNecessary(filter);
applySuccessUrlIfNecessary(filter);
applyUnauthorizedUrlIfNecessary(filter);
}
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof Filter) {
log.debug("Found filter chain candidate filter '{}'", beanName);
Filter filter = (Filter) bean;
applyGlobalPropertiesIfNecessary(filter);
getFilters().put(beanName, filter);
} else {
log.trace("Ignoring non-Filter bean '{}'", beanName);
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
private static final class SpringShiroFilter extends ExtendAbstractShiroFilter {
protected SpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver) {
super();
if (webSecurityManager == null) {
throw new IllegalArgumentException("WebSecurityManager property cannot be null.");
}
setSecurityManager(webSecurityManager);
if (resolver != null) {
setFilterChainResolver(resolver);
}
}
}
}
package com.qzt.config.shiro.filter;
import java.io.IOException;
import java.util.concurrent.Callable;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.ExecutionException;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.mgt.FilterChainResolver;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.mgt.WebSecurityManager;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.apache.shiro.web.servlet.OncePerRequestFilter;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.servlet.ShiroHttpServletResponse;
import org.apache.shiro.web.subject.WebSubject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ExtendAbstractShiroFilter extends OncePerRequestFilter {
private static final Logger log = LoggerFactory.getLogger(AbstractShiroFilter.class);
private static final String STATIC_INIT_PARAM_NAME = "staticSecurityManagerEnabled";
private WebSecurityManager securityManager;
private FilterChainResolver filterChainResolver;
private boolean staticSecurityManagerEnabled;
protected ExtendAbstractShiroFilter() {
this.staticSecurityManagerEnabled = false;
}
public WebSecurityManager getSecurityManager() {
return securityManager;
}
public void setSecurityManager(WebSecurityManager sm) {
this.securityManager = sm;
}
public FilterChainResolver getFilterChainResolver() {
return filterChainResolver;
}
public void setFilterChainResolver(FilterChainResolver filterChainResolver) {
this.filterChainResolver = filterChainResolver;
}
public boolean isStaticSecurityManagerEnabled() {
return staticSecurityManagerEnabled;
}
public void setStaticSecurityManagerEnabled(boolean staticSecurityManagerEnabled) {
this.staticSecurityManagerEnabled = staticSecurityManagerEnabled;
}
protected final void onFilterConfigSet() throws Exception {
applyStaticSecurityManagerEnabledConfig();
init();
ensureSecurityManager();
if (isStaticSecurityManagerEnabled()) {
SecurityUtils.setSecurityManager(getSecurityManager());
}
}
private void applyStaticSecurityManagerEnabledConfig() {
String value = getInitParam(STATIC_INIT_PARAM_NAME);
if (value != null) {
Boolean b = Boolean.valueOf(value);
if (b != null) {
setStaticSecurityManagerEnabled(b);
}
}
}
public void init() throws Exception {
}
private void ensureSecurityManager() {
WebSecurityManager securityManager = getSecurityManager();
if (securityManager == null) {
log.info("No SecurityManager configured. Creating default.");
securityManager = createDefaultSecurityManager();
setSecurityManager(securityManager);
}
}
protected WebSecurityManager createDefaultSecurityManager() {
return new DefaultWebSecurityManager();
}
protected boolean isHttpSessions() {
return getSecurityManager().isHttpSessionMode();
}
protected ServletRequest wrapServletRequest(HttpServletRequest orig) {
return new ShiroHttpServletRequest(orig, getServletContext(), isHttpSessions());
}
@SuppressWarnings({"UnusedDeclaration"})
protected ServletRequest prepareServletRequest(ServletRequest request, ServletResponse response, FilterChain chain) {
ServletRequest toUse = request;
if (request instanceof HttpServletRequest) {
HttpServletRequest http = (HttpServletRequest) request;
toUse = wrapServletRequest(http);
}
return toUse;
}
protected ServletResponse wrapServletResponse(HttpServletResponse orig, ShiroHttpServletRequest request) {
return new ShiroHttpServletResponse(orig, getServletContext(), request);
}
@SuppressWarnings({"UnusedDeclaration"})
protected ServletResponse prepareServletResponse(ServletRequest request, ServletResponse response, FilterChain chain) {
ServletResponse toUse = response;
if (!isHttpSessions() && (request instanceof ShiroHttpServletRequest) &&
(response instanceof HttpServletResponse)) {
//the ShiroHttpServletResponse exists to support URL rewriting for session ids. This is only needed if
//using Shiro sessions (i.e. not simple HttpSession based sessions):
toUse = wrapServletResponse((HttpServletResponse) response, (ShiroHttpServletRequest) request);
}
return toUse;
}
protected WebSubject createSubject(ServletRequest request, ServletResponse response) {
return new WebSubject.Builder(getSecurityManager(), request, response).buildWebSubject();
}
@SuppressWarnings({"UnusedDeclaration"})
protected void updateSessionLastAccessTime(ServletRequest request, ServletResponse response) {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
// log.info("-------------------------------------uri------" req.getRequestURI());
String requestURI = req.getRequestURI();
try {
if (requestURI.startsWith("/uri/uri")) {// /uri/uri 这个就是前端定时请求的接口
//当是这个接口的时候就不进行对session的最后操作时间进行刷新了
}else{
//if (!isHttpSessions()) { //'native' sessions,这里我去掉了,因为我的session是httpssesion
Subject subject = SecurityUtils.getSubject();
if (subject != null) {
Session session = subject.getSession(false);
if (session != null) {
try {
//刷新session最后访问时间为当前时间
session.touch();
//同步把cookie的超时时间也刷新一下
Cookie cookie2 = new Cookie("token", session.getId().toString());
cookie2.setMaxAge(1800);
cookie2.setHttpOnly(false);
cookie2.setPath("/");
res.addCookie(cookie2);
System.err.println("超时时间========" session.getTimeout());
System.err.println("最后访问时间=====" session.getLastAccessTime());
} catch (Throwable t) {
log.error("session.touch() method invocation has failed. Unable to update"
"the corresponding session's last access time based on the incoming request.", t);
}
}
}
//}
}
} catch (Exception e) {
log.error("error", e);
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse, final FilterChain chain)
throws ServletException, IOException {
Throwable t = null;
try {
final ServletRequest request = prepareServletRequest(servletRequest, servletResponse, chain);
final ServletResponse response = prepareServletResponse(request, servletResponse, chain);
final Subject subject = createSubject(request, response);
subject.execute(new Callable() {
public Object call() throws Exception {
updateSessionLastAccessTime(request, response);
executeChain(request, response, chain);
return null;
}
});
} catch (ExecutionException ex) {
t = ex.getCause();
} catch (Throwable throwable) {
t = throwable;
}
if (t != null) {
if (t instanceof ServletException) {
throw (ServletException) t;
}
if (t instanceof IOException) {
throw (IOException) t;
}
//otherwise it's not one of the two exceptions expected by the filter method signature - wrap it in one:
String msg = "Filtered request failed.";
throw new ServletException(msg, t);
}
}
protected FilterChain getExecutionChain(ServletRequest request, ServletResponse response, FilterChain origChain) {
FilterChain chain = origChain;
FilterChainResolver resolver = getFilterChainResolver();
if (resolver == null) {
log.debug("No FilterChainResolver configured. Returning original FilterChain.");
return origChain;
}
FilterChain resolved = resolver.getChain(request, response, origChain);
if (resolved != null) {
log.trace("Resolved a configured FilterChain for the current request.");
chain = resolved;
} else {
log.trace("No FilterChain configured for the current request. Using the default.");
}
return chain;
}
protected void executeChain(ServletRequest request, ServletResponse response, FilterChain origChain)
throws IOException, ServletException {
FilterChain chain = getExecutionChain(request, response, origChain);
chain.doFilter(request, response);
}
}
5、上面的步骤完事以后需要将原来的shiroFilter进行改写,让使用我自己重新写的类,如下:
@Bean
public FilterRegistrationBean delegatingFilterProxy(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
DelegatingFilterProxy proxy = new DelegatingFilterProxy();
proxy.setTargetFilterLifecycle(true);
proxy.setTargetBeanName("shiroFilter");
filterRegistrationBean.setFilter(proxy);
return filterRegistrationBean;
}
@Bean("shiroFilter")
public ExtendShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
// ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//使用我们上边自定义的类
ExtendShiroFilterFactoryBean shiroFilterFactoryBean= new ExtendShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
//设置一下 拦截器,把定时任务和登录接口一类的过滤掉,防止影响超时时间的刷新
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/net/tips/getMsg", "anon");//是定时任务接口
filterChainDefinitionMap.put("/net/tips/**", "authc");//其他接口依旧拦截
filterChainDefinitionMap.put("/net/collect/getACData", "anon");//过滤定时任务接口
filterChainDefinitionMap.put("/net/collect/**", "authc");//其他接口依旧拦截
filterChainDefinitionMap.put("/net/task/**", "authc");
filterChainDefinitionMap.put("/net/user/login", "anon");//过滤登录接口
filterChainDefinitionMap.put("/net/user/**", "authc");//拦截除登录接口之外的其他接口
//filterChainDefinitionMap.put("/**", "anon");
//filterChainDefinitionMap.put("/system/submitLogin", "anon");
//filterChainDefinitionMap.put("/**", "authc");
//配置退出过滤器,其中的具体代码Shiro已经替我们实现了
//filterChainDefinitionMap.put("/logout", "logout");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
/*
* 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
* shiroFilterFactoryBean.setLoginUrl("/login");
* shiroFilterFactoryBean.setSuccessUrl("/index");
* shiroFilterFactoryBean.setUnauthorizedUrl("/403");
*/
//Map<String, Filter> filters = new LinkedHashMap<>();
//filters.put("authc" , new CustomAuthenticationFilter());
//shiroFilterFactoryBean.setFilters(filters);
return shiroFilterFactoryBean;
}
6、我的项目中要修改的时候下面这个类中的超时时间要注释掉
public class TokenManager {
@Autowired
private static SampleRealm realm;
/**
* 获取当前登录的用户User对象
* @return
*/
public static User getToken(){
User token = (User) SecurityUtils.getSubject().getPrincipal();
SecurityUtils.getSubject().getSession().setTimeout(300000);//我测试的不需要注释,这句设置超时时间,但有情况是要注释掉,不然影响超时其他地方超时时间的设置;看个人情况吧
return token ;
}
7、看个人情况:可以忽略;超时时间要修改sessionManager.setGlobalSessionTimeout(1200000);这个位置的,配置文件中的不管用
8、大功告成
注:自己做完的每个都要进行测试,完整测试,不然其实内部还存在好多的问题的
注意点:
1.session超时时间的设置;
2.cookie超时时间的同步刷新;
3.定时任务的过滤:可以在shiro级别过滤,也可以在过滤器中过滤(不刷新超时时间)
shiro级别过滤
过滤器中过滤
要实现某一个类的功能,不是要继承这个类来实现,而是通过继承这个类所继承的类或者实现这个类所实现的接口来实现。
,免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com