package cc.mrbird.febs.common.authentication; 
 | 
  
 | 
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; 
 | 
import cc.mrbird.febs.common.properties.FebsProperties; 
 | 
import lombok.RequiredArgsConstructor; 
 | 
import org.apache.commons.lang3.StringUtils; 
 | 
import org.apache.shiro.codec.Base64; 
 | 
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.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 org.springframework.util.Base64Utils; 
 | 
  
 | 
import java.nio.charset.StandardCharsets; 
 | 
import java.util.ArrayList; 
 | 
import java.util.Arrays; 
 | 
import java.util.Collection; 
 | 
import java.util.LinkedHashMap; 
 | 
  
 | 
/** 
 | 
 * Shiro 配置类 
 | 
 * 
 | 
 * @author MrBird 
 | 
 */ 
 | 
@Configuration 
 | 
@RequiredArgsConstructor 
 | 
public class ShiroConfig { 
 | 
  
 | 
    private final FebsProperties febsProperties; 
 | 
  
 | 
    @Value("${spring.redis.host}") 
 | 
    private String host; 
 | 
    @Value("${spring.redis.port}") 
 | 
    private int port; 
 | 
    @Value("${spring.redis.password:}") 
 | 
    private String password; 
 | 
    @Value("${spring.redis.timeout}") 
 | 
    private int timeout; 
 | 
    @Value("${spring.redis.database:0}") 
 | 
    private int database; 
 | 
  
 | 
    /** 
 | 
     * shiro 中配置 redis 缓存 
 | 
     * 
 | 
     * @return RedisManager 
 | 
     */ 
 | 
    private RedisManager redisManager() { 
 | 
        RedisManager redisManager = new RedisManager(); 
 | 
        redisManager.setHost(host + ":" + port); 
 | 
        if (StringUtils.isNotBlank(password)) { 
 | 
            redisManager.setPassword(password); 
 | 
        } 
 | 
        redisManager.setTimeout(timeout); 
 | 
        redisManager.setDatabase(database); 
 | 
        return redisManager; 
 | 
    } 
 | 
  
 | 
    private RedisCacheManager cacheManager() { 
 | 
        RedisCacheManager redisCacheManager = new RedisCacheManager(); 
 | 
        redisCacheManager.setRedisManager(redisManager()); 
 | 
        return redisCacheManager; 
 | 
    } 
 | 
  
 | 
    @Bean 
 | 
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { 
 | 
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); 
 | 
  
 | 
        // 设置 securityManager 
 | 
        shiroFilterFactoryBean.setSecurityManager(securityManager); 
 | 
        // 登录的 url 
 | 
        shiroFilterFactoryBean.setLoginUrl(febsProperties.getShiro().getLoginUrl()); 
 | 
        // 登录成功后跳转的 url 
 | 
        shiroFilterFactoryBean.setSuccessUrl(febsProperties.getShiro().getSuccessUrl()); 
 | 
        // 未授权 url 
 | 
        shiroFilterFactoryBean.setUnauthorizedUrl(febsProperties.getShiro().getUnauthorizedUrl()); 
 | 
  
 | 
        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); 
 | 
        // 设置免认证 url 
 | 
        String[] anonUrls = StringUtils.splitByWholeSeparatorPreserveAllTokens(febsProperties.getShiro().getAnonUrl(), ","); 
 | 
        for (String url : anonUrls) { 
 | 
            filterChainDefinitionMap.put(url, "anon"); 
 | 
        } 
 | 
        // 配置退出过滤器,其中具体的退出代码 Shiro已经替我们实现了 
 | 
        filterChainDefinitionMap.put(febsProperties.getShiro().getLogoutUrl(), "logout"); 
 | 
  
 | 
        filterChainDefinitionMap.put("/api/**", "anon"); 
 | 
  
 | 
        filterChainDefinitionMap.put("/swagger-ui.html/**", "anon"); 
 | 
        filterChainDefinitionMap.put("/swagger-resources/**", "anon"); 
 | 
        filterChainDefinitionMap.put("/v2/api-docs", "anon"); 
 | 
        filterChainDefinitionMap.put("/webjars/**", "anon"); 
 | 
        filterChainDefinitionMap.put("/wsxg", "anon"); 
 | 
  
 | 
        // 除上以外所有 url都必须认证通过才可以访问,未通过认证自动访问 LoginUrl 
 | 
        filterChainDefinitionMap.put("/**", "user"); 
 | 
  
 | 
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); 
 | 
        return shiroFilterFactoryBean; 
 | 
    } 
 | 
  
 | 
    @Bean 
 | 
    public SecurityManager securityManager(ShiroRealm shiroRealm) { 
 | 
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); 
 | 
        // 配置 SecurityManager,并注入 shiroRealm 
 | 
        securityManager.setRealm(shiroRealm); 
 | 
        // 配置 shiro session管理器 
 | 
        securityManager.setSessionManager(sessionManager()); 
 | 
        // 配置 缓存管理类 cacheManager 
 | 
        securityManager.setCacheManager(cacheManager()); 
 | 
        // 配置 rememberMeCookie 
 | 
        securityManager.setRememberMeManager(rememberMeManager()); 
 | 
        return securityManager; 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * rememberMe cookie 效果是重开浏览器后无需重新登录 
 | 
     * 
 | 
     * @return SimpleCookie 
 | 
     */ 
 | 
    private SimpleCookie rememberMeCookie() { 
 | 
        // 设置 cookie 名称,对应 login.html 页面的 <input type="checkbox" name="rememberMe"/> 
 | 
        SimpleCookie cookie = new SimpleCookie("rememberMe"); 
 | 
        // 设置 cookie 的过期时间,单位为秒,这里为一天 
 | 
        cookie.setMaxAge(febsProperties.getShiro().getCookieTimeout()); 
 | 
        return cookie; 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * cookie管理对象 
 | 
     * 
 | 
     * @return CookieRememberMeManager 
 | 
     */ 
 | 
    private CookieRememberMeManager rememberMeManager() { 
 | 
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); 
 | 
        cookieRememberMeManager.setCookie(rememberMeCookie()); 
 | 
        // rememberMe cookie 加密的密钥 
 | 
        String encryptKey = "febs_shiro_key"; 
 | 
        byte[] encryptKeyBytes = encryptKey.getBytes(StandardCharsets.UTF_8); 
 | 
        String rememberKey = Base64Utils.encodeToString(Arrays.copyOf(encryptKeyBytes, 16)); 
 | 
        cookieRememberMeManager.setCipherKey(Base64.decode(rememberKey)); 
 | 
        return cookieRememberMeManager; 
 | 
    } 
 | 
  
 | 
    @Bean 
 | 
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { 
 | 
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); 
 | 
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); 
 | 
        return authorizationAttributeSourceAdvisor; 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * 用于开启 Thymeleaf 中的 shiro 标签的使用 
 | 
     * 
 | 
     * @return ShiroDialect shiro 方言对象 
 | 
     */ 
 | 
    @Bean 
 | 
    public ShiroDialect shiroDialect() { 
 | 
        return new ShiroDialect(); 
 | 
    } 
 | 
  
 | 
    @Bean 
 | 
    public RedisSessionDAO redisSessionDAO() { 
 | 
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO(); 
 | 
        redisSessionDAO.setRedisManager(redisManager()); 
 | 
        return redisSessionDAO; 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * session 管理对象 
 | 
     * 
 | 
     * @return DefaultWebSessionManager 
 | 
     */ 
 | 
    @Bean 
 | 
    public DefaultWebSessionManager sessionManager() { 
 | 
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); 
 | 
        Collection<SessionListener> listeners = new ArrayList<>(); 
 | 
        listeners.add(new ShiroSessionListener()); 
 | 
        // 设置 session超时时间 
 | 
        sessionManager.setGlobalSessionTimeout(febsProperties.getShiro().getSessionTimeout() * 1000L); 
 | 
        sessionManager.setSessionListeners(listeners); 
 | 
        sessionManager.setSessionDAO(redisSessionDAO()); 
 | 
        sessionManager.setSessionIdUrlRewritingEnabled(false); 
 | 
        return sessionManager; 
 | 
    } 
 | 
} 
 |