1
|
package com.ruoyi.framework.config; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import javax.servlet.Filter; import com.ruoyi.framework.shiro.realm.CasRealm; import io.buji.pac4j.filter.CallbackFilter; import io.buji.pac4j.filter.SecurityFilter; import io.buji.pac4j.subject.Pac4jSubjectFactory; import org.apache.commons.io.IOUtils; import org.apache.shiro.cache.ehcache.EhCacheManager; import org.apache.shiro.codec.Base64; import org.apache.shiro.config.ConfigurationException; import org.apache.shiro.io.ResourceUtils; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.CookieRememberMeManager; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.servlet.SimpleCookie; import org.pac4j.core.config.Config; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.spring.SpringUtils; import com.ruoyi.framework.shiro.realm.UserRealm; import com.ruoyi.framework.shiro.session.OnlineSessionDAO; import com.ruoyi.framework.shiro.session.OnlineSessionFactory; import io.buji.pac4j.filter.LogoutFilter; //import com.ruoyi.framework.shiro.web.filter.LogoutFilter; import com.ruoyi.framework.shiro.web.filter.captcha.CaptchaValidateFilter; import com.ruoyi.framework.shiro.web.filter.kickout.KickoutSessionFilter; import com.ruoyi.framework.shiro.web.filter.online.OnlineSessionFilter; import com.ruoyi.framework.shiro.web.filter.sync.SyncOnlineSessionFilter; import com.ruoyi.framework.shiro.web.session.OnlineWebSessionManager; import com.ruoyi.framework.shiro.web.session.SpringSessionValidationScheduler; import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; /** * 权限配置加载 * * @author ruoyi */ @Configuration public class ShiroConfig { public static final String PREMISSION_STRING = "perms[\"{0}\"]"; /** * Session超时时间,单位为毫秒(默认30分钟) */ @Value("${shiro.session.expireTime}") private int expireTime; /** * 相隔多久检查一次session的有效性,单位毫秒,默认就是10分钟 */ @Value("${shiro.session.validationInterval}") private int validationInterval; /** * 同一个用户最大会话数 */ @Value("${shiro.session.maxSession}") private int maxSession; /** * 踢出之前登录的/之后登录的用户,默认踢出之前登录的用户 */ @Value("${shiro.session.kickoutAfter}") private boolean kickoutAfter; /** * 验证码开关 */ @Value("${shiro.user.captchaEnabled}") private boolean captchaEnabled; /** * 验证码类型 */ @Value("${shiro.user.captchaType}") private String captchaType; /** * 设置Cookie的域名 */ @Value("${shiro.cookie.domain}") private String domain; /** * 设置cookie的有效访问路径 */ @Value("${shiro.cookie.path}") private String path; /** * 设置HttpOnly属性 */ @Value("${shiro.cookie.httpOnly}") private boolean httpOnly; /** * 设置Cookie的过期时间,秒为单位 */ @Value("${shiro.cookie.maxAge}") private int maxAge; /** * 登录地址 */ @Value("${shiro.user.loginUrl}") private String loginUrl; /** * 权限认证失败地址 */ @Value("${shiro.user.unauthorizedUrl}") private String unauthorizedUrl; /* liupsh cas begin*/ /** 项目工程路径 */ @Value("${cas.project.url}") private String projectUrl; /** 项目cas服务路径 */ @Value("${cas.server.url}") private String casServerUrl; /** 客户端名称 */ @Value("${cas.client-name}") private String clientName; /* liupsh cas end*/ /** * 缓存管理器 使用Ehcache实现 */ @Bean public EhCacheManager getEhCacheManager() { net.sf.ehcache.CacheManager cacheManager = net.sf.ehcache.CacheManager.getCacheManager("ruoyi"); EhCacheManager em = new EhCacheManager(); if (StringUtils.isNull(cacheManager)) { em.setCacheManager(new net.sf.ehcache.CacheManager(getCacheManagerConfigFileInputStream())); return em; } else { em.setCacheManager(cacheManager); return em; } } /** * 返回配置文件流 避免ehcache配置文件一直被占用,无法完全销毁项目重新部署 */ protected InputStream getCacheManagerConfigFileInputStream() { String configFile = "classpath:ehcache/ehcache-shiro.xml"; InputStream inputStream = null; try { inputStream = ResourceUtils.getInputStreamForPath(configFile); byte[] b = IOUtils.toByteArray(inputStream); InputStream in = new ByteArrayInputStream(b); return in; } catch (IOException e) { throw new ConfigurationException( "Unable to obtain input stream for cacheManagerConfigFile [" + configFile + "]", e); } finally { IOUtils.closeQuietly(inputStream); } } /** * 自定义Realm */ @Bean public UserRealm userRealm(EhCacheManager cacheManager) { UserRealm userRealm = new UserRealm(); userRealm.setCacheManager(cacheManager); return userRealm; } /** * 自定义sessionDAO会话 */ @Bean public OnlineSessionDAO sessionDAO() { OnlineSessionDAO sessionDAO = new OnlineSessionDAO(); return sessionDAO; } /** * 自定义sessionFactory会话 */ @Bean public OnlineSessionFactory sessionFactory() { OnlineSessionFactory sessionFactory = new OnlineSessionFactory(); return sessionFactory; } /** * 会话管理器 */ @Bean public OnlineWebSessionManager sessionManager() { OnlineWebSessionManager manager = new OnlineWebSessionManager(); // 加入缓存管理器 manager.setCacheManager(getEhCacheManager()); // 删除过期的session manager.setDeleteInvalidSessions(true); // 设置全局session超时时间 manager.setGlobalSessionTimeout(expireTime * 60 * 1000); // 去掉 JSESSIONID manager.setSessionIdUrlRewritingEnabled(false); // 定义要使用的无效的Session定时调度器 manager.setSessionValidationScheduler(SpringUtils.getBean(SpringSessionValidationScheduler.class)); // 是否定时检查session manager.setSessionValidationSchedulerEnabled(true); // 自定义SessionDao manager.setSessionDAO(sessionDAO()); // 自定义sessionFactory manager.setSessionFactory(sessionFactory()); return manager; } /** * 安全管理器 */ @Bean public SecurityManager securityManager(CasRealm casRealm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 设置realm. securityManager.setRealm(casRealm); // 记住我 securityManager.setRememberMeManager(rememberMeManager()); // 注入缓存管理器; securityManager.setCacheManager(getEhCacheManager()); // session管理器 securityManager.setSessionManager(sessionManager()); securityManager.setSubjectFactory(subjectFactory()); return securityManager; } /** * 使用 pac4j 的 subjectFactory * @return */ @Bean public Pac4jSubjectFactory subjectFactory(){ return new Pac4jSubjectFactory(); } @Bean public CasRealm casRealm(){ CasRealm realm = new CasRealm(); // 使用自定义的realm realm.setClientName(clientName); realm.setCachingEnabled(false); //暂时不使用缓存 realm.setAuthenticationCachingEnabled(false); realm.setAuthorizationCachingEnabled(false); //realm.setAuthenticationCacheName("authenticationCache"); //realm.setAuthorizationCacheName("authorizationCache"); return realm; } /** * 加载shiroFilter权限控制规则(从数据库读取然后配置) * @param shiroFilterFactoryBean */ private void loadShiroFilterChain(ShiroFilterFactoryBean shiroFilterFactoryBean){ /*下面这些规则配置最好配置到配置文件中 */ Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); // 对静态资源设置匿名访问 filterChainDefinitionMap.put("/favicon.ico**", "anon"); filterChainDefinitionMap.put("/ruoyi.png**", "anon"); filterChainDefinitionMap.put("/css/**", "anon"); filterChainDefinitionMap.put("/docs/**", "anon"); filterChainDefinitionMap.put("/fonts/**", "anon"); filterChainDefinitionMap.put("/img/**", "anon"); filterChainDefinitionMap.put("/ajax/**", "anon"); filterChainDefinitionMap.put("/js/**", "anon"); filterChainDefinitionMap.put("/ruoyi/**", "anon"); filterChainDefinitionMap.put("/druid/**", "anon"); filterChainDefinitionMap.put("/captcha/captchaImage**", "anon"); //内部接口调用 filterChainDefinitionMap.put("/hiapi/**", "anon"); filterChainDefinitionMap.put("/", "securityFilter"); filterChainDefinitionMap.put("/application/**", "securityFilter"); filterChainDefinitionMap.put("/index", "securityFilter"); filterChainDefinitionMap.put("/callback", "callbackFilter"); filterChainDefinitionMap.put("/logout", "logout"); // filterChainDefinitionMap.put("/**","anon"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); } /** * Shiro过滤器配置 */ @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager , Config config) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // Shiro的核心安全接口,这个属性是必须的 shiroFilterFactoryBean.setSecurityManager(securityManager); // 添加casFilter到shiroFilter中 loadShiroFilterChain(shiroFilterFactoryBean); Map<String, Filter> filters = new HashMap<>(3); //cas 资源认证拦截器 SecurityFilter securityFilter = new SecurityFilter(); securityFilter.setConfig(config); securityFilter.setClients(clientName); filters.put("securityFilter", securityFilter); //cas 认证后回调拦截器 CallbackFilter callbackFilter = new CallbackFilter(); callbackFilter.setConfig(config); callbackFilter.setDefaultUrl(projectUrl); filters.put("callbackFilter", callbackFilter); // 注销 拦截器 LogoutFilter logoutFilter = new LogoutFilter(); logoutFilter.setConfig(config); logoutFilter.setCentralLogout(true); logoutFilter.setLocalLogout(true); logoutFilter.setDefaultUrl(projectUrl + "/callback?client_name=" + clientName); filters.put("logout",logoutFilter); shiroFilterFactoryBean.setFilters(filters); return shiroFilterFactoryBean; } /** * 自定义在线用户处理过滤器 */ @Bean public OnlineSessionFilter onlineSessionFilter() { OnlineSessionFilter onlineSessionFilter = new OnlineSessionFilter(); onlineSessionFilter.setLoginUrl(loginUrl); return onlineSessionFilter; } /** * 自定义在线用户同步过滤器 */ @Bean public SyncOnlineSessionFilter syncOnlineSessionFilter() { SyncOnlineSessionFilter syncOnlineSessionFilter = new SyncOnlineSessionFilter(); return syncOnlineSessionFilter; } /** * 自定义验证码过滤器 */ @Bean public CaptchaValidateFilter captchaValidateFilter() { CaptchaValidateFilter captchaValidateFilter = new CaptchaValidateFilter(); captchaValidateFilter.setCaptchaEnabled(captchaEnabled); captchaValidateFilter.setCaptchaType(captchaType); return captchaValidateFilter; } /** * cookie 属性设置 */ public SimpleCookie rememberMeCookie() { SimpleCookie cookie = new SimpleCookie("rememberMe"); cookie.setDomain(domain); cookie.setPath(path); cookie.setHttpOnly(httpOnly); cookie.setMaxAge(maxAge * 24 * 60 * 60); return cookie; } /** * 记住我 */ public CookieRememberMeManager rememberMeManager() { CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); cookieRememberMeManager.setCookie(rememberMeCookie()); cookieRememberMeManager.setCipherKey(Base64.decode("fCq+/xW488hMTCD+cmJ3aQ==")); return cookieRememberMeManager; } /** * 同一个用户多设备登录限制 */ public KickoutSessionFilter kickoutSessionFilter() { KickoutSessionFilter kickoutSessionFilter = new KickoutSessionFilter(); kickoutSessionFilter.setCacheManager(getEhCacheManager()); kickoutSessionFilter.setSessionManager(sessionManager()); // 同一个用户最大的会话数,默认-1无限制;比如2的意思是同一个用户允许最多同时两个人登录 kickoutSessionFilter.setMaxSession(maxSession); // 是否踢出后来登录的,默认是false;即后者登录的用户踢出前者登录的用户;踢出顺序 kickoutSessionFilter.setKickoutAfter(kickoutAfter); // 被踢出后重定向到的地址; kickoutSessionFilter.setKickoutUrl("/login?kickout=1"); return kickoutSessionFilter; } /** * thymeleaf模板引擎和shiro框架的整合 */ @Bean public ShiroDialect shiroDialect() { return new ShiroDialect(); } /** * 开启Shiro注解通知器 */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor( @Qualifier("securityManager") SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } }
|