springboot整合shiro+redis 整合完成以后 功能是正常的 但是控制台每隔一段时间就报错
2023-08-30 16:38:36.959 WARN [commons-pool-evictor]redis.clients.jedis.JedisFactory.destroyObject:168 -Error while close
redis.clients.jedis.exceptions.JedisException: Could not return the broken resource to the pool
at redis.clients.jedis.util.Pool.returnBrokenResourceObject(Pool.java:126)
at redis.clients.jedis.util.Pool.returnBrokenResource(Pool.java:103)
at redis.clients.jedis.JedisPool.returnResource(JedisPool.java:389)
at redis.clients.jedis.JedisPool.returnResource(JedisPool.java:15)
at redis.clients.jedis.Jedis.close(Jedis.java:4081)
at redis.clients.jedis.JedisFactory.destroyObject(JedisFactory.java:166)
at org.apache.commons.pool2.PooledObjectFactory.destroyObject(PooledObjectFactory.java:127)
at org.apache.commons.pool2.impl.GenericObjectPool.destroy(GenericObjectPool.java:611)
at org.apache.commons.pool2.impl.GenericObjectPool.evict(GenericObjectPool.java:729)
at org.apache.commons.pool2.impl.BaseGenericObjectPool$Evictor.run(BaseGenericObjectPool.java:160)
at org.apache.commons.pool2.impl.EvictionTimer$WeakRunner.run(EvictionTimer.java:113)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.runAndReset$$$capture(FutureTask.java:308)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.IllegalStateException: Invalidated object not currently part of this pool
at org.apache.commons.pool2.impl.GenericObjectPool.invalidateObject(GenericObjectPool.java:936)
at org.apache.commons.pool2.impl.GenericObjectPool.invalidateObject(GenericObjectPool.java:914)
at redis.clients.jedis.util.Pool.returnBrokenResourceObject(Pool.java:124)
... 18 common frames omitted
2023-08-30 16:38:36.961 WARN [commons-pool-evictor]redis.clients.jedis.JedisFactory.destroyObject:168 -Error while close
redis.clients.jedis.exceptions.JedisException: Could not return the broken resource to the pool
at redis.clients.jedis.util.Pool.returnBrokenResourceObject(Pool.java:126)
at redis.clients.jedis.util.Pool.returnBrokenResource(Pool.java:103)
at redis.clients.jedis.JedisPool.returnResource(JedisPool.java:389)
at redis.clients.jedis.JedisPool.returnResource(JedisPool.java:15)
at redis.clients.jedis.Jedis.close(Jedis.java:4081)
at redis.clients.jedis.JedisFactory.destroyObject(JedisFactory.java:166)
at org.apache.commons.pool2.PooledObjectFactory.destroyObject(PooledObjectFactory.java:127)
at org.apache.commons.pool2.impl.GenericObjectPool.destroy(GenericObjectPool.java:611)
at org.apache.commons.pool2.impl.GenericObjectPool.evict(GenericObjectPool.java:729)
at org.apache.commons.pool2.impl.BaseGenericObjectPool$Evictor.run(BaseGenericObjectPool.java:160)
at org.apache.commons.pool2.impl.EvictionTimer$WeakRunner.run(EvictionTimer.java:113)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.runAndReset$$$capture(FutureTask.java:308)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:748)
下面是我的配置文件
package com.kth.basicadmin.common.config.shiro;
import com.alibaba.druid.support.http.StatViewServlet;
import com.kth.basicadmin.common.utils.LoadPackageClasses;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.web.filter.DelegatingFilterProxy;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
/**
* @author 10412
*/
@Configuration
public class ShiroConfig implements EnvironmentAware{
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean factoryBean = new CustomShiroFilterFactoryBean();
factoryBean.setSecurityManager(securityManager());
// 没有登录的用户只能访问登录页面,设置
factoryBean.setLoginUrl("/login");
// 登录成功后要跳转的链接
factoryBean.setSuccessUrl("/index");
// 未授权界面; ----这个配置了没卵用,具体原因想深入了解的可以自行百度
// factoryBean.setUnauthorizedUrl("/unauth");
// 权限控制map.
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
//配置不登录可以访问的资源,anon 表示资源都可以匿名访问
filterChainDefinitionMap.put("/css/**", "anon");
filterChainDefinitionMap.put("/js/**", "anon");
filterChainDefinitionMap.put("/img/**", "anon");
filterChainDefinitionMap.put("/auth/login", "anon");
/**
* 其他资源都需要认证 authc 表示需要认证才能进行访问 user表示配置记住我或认证通过可以访问的地址
*如果开启限制同一账号登录,改为 .put("/**", "kickout,user");
**/
filterChainDefinitionMap.put("/*Controller/*", "user");
filterChainDefinitionMap.put("/index", "authc");
factoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return factoryBean;
}
@Bean
public MethodInvokingFactoryBean methodInvokingFactoryBean() {
MethodInvokingFactoryBean bean = new MethodInvokingFactoryBean();
bean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager");
bean.setArguments(securityManager());
return bean;
}
@Bean(name = "rememberAuthFilter")
public RememberAuthenticationFilter rememberAuthenticationFilter() {
RememberAuthenticationFilter filter = new RememberAuthenticationFilter();
filter.setUsernameParam("userName");
return filter;
}
/**
* cookie对象;会话Cookie模板 ,默认为: JSESSIONID 问题: 与SERVLET容器名冲突,重新定义为sid或rememberMe,自定义
* @return
*/
@Bean
public SimpleCookie rememberMeCookie(){
//这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
//setcookie的httponly属性如果设为true的话,会增加对xss防护的安全系数。它有以下特点:
//setcookie()的第七个参数
//设为true后,只能通过http访问,javascript无法访问
//防止xss读取cookie
simpleCookie.setHttpOnly(true);
simpleCookie.setPath("/");
//<!-- 记住我cookie生效时间30天 ,单位秒;-->
simpleCookie.setMaxAge(2592000);
return simpleCookie;
}
/**
* cookie管理对象;记住我功能,rememberMe管理器
* @return
*/
@Bean
public CookieRememberMeManager rememberMeManager(){
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
//rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)
cookieRememberMeManager.setCipherKey(Base64.decode("************"));
return cookieRememberMeManager;
}
/**
* FormAuthenticationFilter 过滤器 过滤记住我
* @return
*/
@Bean
public FormAuthenticationFilter formAuthenticationFilter(){
FormAuthenticationFilter formAuthenticationFilter = new FormAuthenticationFilter();
//对应前端的checkbox的name = rememberMe
formAuthenticationFilter.setRememberMeParam("rememberMe");
return formAuthenticationFilter;
}
@Bean
public FilterRegistrationBean registrationBean() {
FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter"));
// 该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理
filterRegistration.addInitParameter("targetFilterLifecycle", "true");
// 可以自己灵活的定义很多,避免一些根本不需要被Shiro处理的请求被包含进来
filterRegistration.addUrlPatterns("/*");
filterRegistration.addUrlPatterns("/WEB-INF/jsp/*");
filterRegistration.addUrlPatterns("/login");
filterRegistration.addUrlPatterns("/index");
filterRegistration.addUrlPatterns("/logout");
return filterRegistration;
}
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 设置realm.
securityManager.setRealm(myShiroRealm());
// 自定义缓存实现 使用redis
securityManager.setCacheManager(cacheManager());
// 自定义session管理 使用redis
securityManager.setSessionManager(sessionManager());
return securityManager;
}
/**
* 身份认证realm; (这个需要自己写,账号密码校验;权限等)
*
* @return
*/
@Bean
public CustomRealm myShiroRealm() {
CustomRealm customRealm = new CustomRealm();
return customRealm;
}
/**
* cacheManager 缓存 redis实现
* 使用的是shiro-redis开源插件
*
* @return
*/
public RedisCacheManager cacheManager() {
RedisCacheManager redisCacheManager = new RedisCacheManager();
redisCacheManager.setRedisManager(redisManager());
return redisCacheManager;
}
/**
* 配置shiro redisManager
* 使用的是shiro-redis开源插件
*
* @return
*/
public RedisManager redisManager() {
RedisManager redisManager = new RedisManager();
Optional<String> hostOpt = Optional.ofNullable(environment.getProperty("spring.redis.host"));
String host = hostOpt.orElse("localhost");
Optional<String> portOpt = Optional.ofNullable(environment.getProperty("spring.redis.port"));
int port = Integer.parseInt(portOpt.orElse("6379"));
Optional<String> timeoutOpt = Optional.ofNullable(environment.getProperty("spring.redis.timeout"));
int timeout = Integer.parseInt(timeoutOpt.orElse("2000"));
Optional<String> expireOpt = Optional.ofNullable(environment.getProperty("spring.redis.expire"));
int expire = Integer.parseInt(expireOpt.orElse("2000"));
Optional<String> passwordOpt = Optional.ofNullable(environment.getProperty("spring.redis.password"));
String password = passwordOpt.orElse("");
redisManager.setHost(host);
redisManager.setPort(port);
// 配置缓存过期时间
redisManager.setExpire(expire);
redisManager.setTimeout(timeout);
if(password!=null&&!"".equals(password)){
redisManager.setPassword(password);
}
return redisManager;
}
/**
* Session Manager
* 使用的是shiro-redis开源插件
*/
@Bean
public DefaultWebSessionManager sessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionDAO(redisSessionDAO());
sessionManager.setGlobalSessionTimeout(Long.valueOf(environment.getProperty("core.sessionMaxTimeout")));
return sessionManager;
}
/**
* RedisSessionDAO shiro sessionDao层的实现 通过redis
* 使用的是shiro-redis开源插件
*/
@Bean
public RedisSessionDAO redisSessionDAO() {
RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
redisSessionDAO.setRedisManager(redisManager());
Optional<String> property = Optional.ofNullable(environment.getProperty("server.servlet.context-path"));
String context = property.orElse("/sso");
redisSessionDAO.setKeyPrefix("shiro:session:" + context.replace("/","") + ":");
return redisSessionDAO;
}
/***
* 授权所用配置
*
* @return
*/
@Bean
public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
/***
* 使授权注解起作用不如不想配置可以在pom文件中加入
* <dependency>
*<groupId>org.springframework.boot</groupId>
*<artifactId>spring-boot-starter-aop</artifactId>
*</dependency>
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
/**
* Shiro生命周期处理器
*
*/
@Bean
public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
private Environment environment;
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Bean
public ServletRegistrationBean<StatViewServlet> druidStatViewServlet() {
ServletRegistrationBean<StatViewServlet> registrationBean =
new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");
// IP白名单 (没有配置或者为空,则允许所有访问)
// registrationBean.addInitParameter("allow", "127.0.0.1");
// IP黑名单 (存在共同时,deny优先于allow)
// registrationBean.addInitParameter("deny", "");
// registrationBean.addInitParameter("loginUsername", "root");
// registrationBean.addInitParameter("loginPassword", "kth54321");
// registrationBean.addInitParameter("resetEnable", "false");
return registrationBean;
}
}