package com.goku.coreui.sys.config.shiro;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.cache.ehcache.EhCacheManager;
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.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;


/**
 * shiro配置类
 * Created by nbfujx on 2017/11/7.
 */
@Configuration
public class ShiroConfig {
    /**
     * LifecycleBeanPostProcessor,这是个DestructionAwareBeanPostProcessor的子类,
     * 负责org.apache.shiro.util.Initializable类型bean的生命周期的,初始化和销毁。
     * 主要是AuthorizingRealm类的子类,以及EhCacheManager类。
     */
    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }


    /**
     * ShiroRealm,这是个自定义的认证类,继承自AuthorizingRealm,
     * 负责用户的认证和权限的处理,可以参考JdbcRealm的实现。
     */
    @Bean(name = "shiroRealm")
    @DependsOn("lifecycleBeanPostProcessor")
    public ShiroRealm shiroRealm() {
        ShiroRealm realm = new ShiroRealm();
        realm.setCacheManager(ehCacheManager());
        return realm;
    }

    /**
     * EhCacheManager,缓存管理,用户登陆成功后,把用户信息和权限信息缓存起来,
     * 然后每次用户请求时,放入用户的session中,如果不设置这个bean,每个请求都会查询一次数据库。
     */
    @Bean(name = "ehCacheManager")
    @DependsOn("lifecycleBeanPostProcessor")
    public EhCacheManager ehCacheManager() {
        return new EhCacheManager();
    }

    /**
     * SecurityManager,权限管理,这个类组合了登陆,登出,权限,session的处理,是个比较重要的类。
     */
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(shiroRealm());
        securityManager.setCacheManager(ehCacheManager());
        return securityManager;
    }


    /**
     * ShiroFilterFactoryBean,是个factorybean,为了生成ShiroFilter。
     * 它主要保持了三项数据,securityManager,filters,filterChainDefinitionManager。
     */
    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shiroFilterFactoryBean() {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager());

        Map<String, Filter> filters = new LinkedHashMap<String, Filter>();
        filters.put("restauthc", new RestAuthShiroFilter());
        shiroFilterFactoryBean.setFilters(filters);

        Map<String, String> filterChainDefinitionManager = new LinkedHashMap<String, String>();
        //登录
        filterChainDefinitionManager.put("/login", "anon");
        filterChainDefinitionManager.put("/doLogin", "anon");
        //登出
        filterChainDefinitionManager.put("/logout", "anon");
        //静态资源
        filterChainDefinitionManager.put("/js/**","anon");
        filterChainDefinitionManager.put("/css/**","anon");
        filterChainDefinitionManager.put("/img/**","anon");
        filterChainDefinitionManager.put("/lib/**","anon");
        //业务操作
        filterChainDefinitionManager.put("/api/**", "restauthc,authc,perms");//"authc,perms");
        filterChainDefinitionManager.put("/**", "authc,perms");//"authc,perms");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionManager);

        shiroFilterFactoryBean.setLoginUrl("/login");
        //登录成功后要跳转的连接
        shiroFilterFactoryBean.setSuccessUrl("/home");
        //未授权界面
        shiroFilterFactoryBean.setUnauthorizedUrl("/404");
        return shiroFilterFactoryBean;
    }

    /**
     * DefaultAdvisorAutoProxyCreator,Spring的一个bean,由Advisor决定对哪些类的方法进行AOP代理。
     */
    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
        defaultAAP.setProxyTargetClass(true);
        return defaultAAP;
    }

    /**
     * AuthorizationAttributeSourceAdvisor,shiro里实现的Advisor类,
     * 内部使用AopAllianceAnnotationsAuthorizingMethodInterceptor来拦截用以下注解的方法。
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor aASA = new AuthorizationAttributeSourceAdvisor();
        aASA.setSecurityManager(securityManager());
        return aASA;
    }


    @Bean(name = "shiroDialect")
    public ShiroDialect shiroDialect(){
        return new ShiroDialect();
    }

}