package com.stone.conf.shiro; import com.stone.conf.filter.AjaxPermissionsAuthorizationFilter; import com.stone.conf.session.ShiroSessionListener; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.codec.Base64; import org.apache.shiro.mgt.RememberMeManager; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.session.SessionListener; 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.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.servlet.Filter; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.Map; /** * shiro 配置核心类 * * @author zhoujl * @since 2018-07-05 */ @Slf4j @Configuration public class ShiroConfig { @Value("${spring.redis.host}") private String host; @Value("${spring.redis.port}") private int port; @Value("${spring.redis.timeout}") private int timeout; /** * cacheManager 缓存 redis实现 * 使用的是shiro-redis开源插件 */ private RedisCacheManager cacheManager() { RedisCacheManager redisCacheManager = new RedisCacheManager(); redisCacheManager.setRedisManager(redisManager()); final String CACHE_KEY = "shiro:cache:"; redisCacheManager.setKeyPrefix(CACHE_KEY); // 配置缓存的话要求放在session里面的实体类必须有个id标识 redisCacheManager.setPrincipalIdFieldName("id"); return redisCacheManager; } /** * 配置shiro redisManager * 使用的是shiro-redis开源插件 */ private RedisManager redisManager() { RedisManager redisManager = new RedisManager(); redisManager.setHost(host + ":" + port); redisManager.setTimeout(timeout); return redisManager; } /** * RedisSessionDAO shiro sessionDao层的实现 通过redis * 使用的是shiro-redis开源插件 */ @Bean public RedisSessionDAO redisSessionDAO() { RedisSessionDAO redisSessionDAO = new RedisSessionDAO(); redisSessionDAO.setRedisManager(redisManager()); redisSessionDAO.setSessionIdGenerator(sessionIdGenerator()); String SESSION_KEY = "shiro:session:"; redisSessionDAO.setKeyPrefix(SESSION_KEY); int EXPIRE = 1800; redisSessionDAO.setExpire(EXPIRE); return redisSessionDAO; } /** * SessionID生成器 */ @Bean public ShiroSessionIdGenerator sessionIdGenerator(){ return new ShiroSessionIdGenerator(); } /** * 配置保存sessionId的cookie */ @Bean("sessionIdCookie") public SimpleCookie sessionIdCookie(){ //这个参数是cookie的名称 SimpleCookie simpleCookie = new SimpleCookie("sid"); //setcookie的httponly属性如果设为true的话,会增加对xss防护的安全系数 simpleCookie.setHttpOnly(true); simpleCookie.setPath("/"); //maxAge=-1表示浏览器关闭时失效此Cookie simpleCookie.setMaxAge(-1); return simpleCookie; } /** * 配置session监听 */ @Bean("sessionListener") public ShiroSessionListener sessionListener(){ return new ShiroSessionListener(); } /** * Session Manager * 使用的是shiro-redis开源插件 */ @Bean public DefaultWebSessionManager sessionManager() { DefaultWebSessionManager webSessionManager = new DefaultWebSessionManager(); Collection listeners = new ArrayList<>(); // 配置监听 listeners.add(sessionListener()); webSessionManager.setSessionListeners(listeners); webSessionManager.setSessionIdCookie(sessionIdCookie()); webSessionManager.setSessionDAO(redisSessionDAO()); // 全局会话超时时间(单位毫秒) webSessionManager.setGlobalSessionTimeout(30 * 60 * 1000); // 是否开启删除无效的session对象 默认为true webSessionManager.setDeleteInvalidSessions(true); // 是否开启定时调度器进行检测过期session 默认为true webSessionManager.setSessionValidationSchedulerEnabled(true); // 设置session失效的扫描时间, 清理用户直接关闭浏览器造成的孤立会话 默认为 1个小时 webSessionManager.setSessionValidationInterval(60 * 1000); // 取消url 后面的 JSESSIONID webSessionManager.setSessionIdUrlRewritingEnabled(false); return webSessionManager; } @Bean("shiroFilter") public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); // 拦截器. Map filterChainDefinitionMap = new LinkedHashMap<>(); // 配置不会被拦截的链接 顺序判断 // :这是一个坑呢,一不小心代码就不好使了; // 配置swagger访问路径 加载顺序不可改变 // filterChainDefinitionMap.put("/user/login", "anon"); filterChainDefinitionMap.put("/**", "user"); // 自定义拦截器 Map filtersMap = new LinkedHashMap<>(); filtersMap.put("user", new AjaxPermissionsAuthorizationFilter()); shiroFilterFactoryBean.setFilters(filtersMap); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } /** * 注入 securityManager */ @Bean(name = "securityManager") public SecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 设置realm. securityManager.setRealm(myShiroRealm()); // 自定义缓存实现 使用redis securityManager.setCacheManager(cacheManager()); // 自定义session管理 使用redis securityManager.setSessionManager(sessionManager()); return securityManager; } /** * 身份验证器 */ @Bean public MyShiroRealm myShiroRealm() { return new MyShiroRealm(); } }