package com.sunda.spmsweb.shiro;

import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
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.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

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

/**
 * @program: spms
 * @author: Wayne Wu
 * @description: shiro 配置信息
 * @create: 2020-10-26 15:40
 */
@Configuration
public class ShiroConfig {

    //将自己的验证方式加入容器
    @Bean
    public CustomRealm myCustomRealm() {
        return new CustomRealm();
    }


    /**
     * 先走 filter ，然后 filter 如果检测到请求头存在 token，则用 token 去 login，走 Realm 去验证
     *
     * anon：无需认证就可以访问
     * authc：必须认证了才能访问
     * user：必须用有了 记住我 功能才能用
     * perms：拥有对某个资源的权限才能访问
     * role：拥有某个角色权限才能访问
     *
     */
    @Bean
    public ShiroFilterFactoryBean factory(SecurityManager securityManager) {
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();

        // 添加自己的过滤器并且取名为jwt
        Map<String, Filter> filterMap = new LinkedHashMap<>();
        //设置我们自定义的JWT过滤器
        filterMap.put("jwt", new JWTFilter());
        factoryBean.setFilters(filterMap);
        factoryBean.setSecurityManager(securityManager);
        //登录页
        //factoryBean.setLoginUrl("/login");
        //首页
        //factoryBean.setSuccessUrl("/index");
        // 设置无权限时跳转的 url;
        factoryBean.setUnauthorizedUrl("/err");
        Map<String, String> filterRuleMap = new LinkedHashMap<>();
        //配置退出，过滤器，其中的具体的退出代码Shiro已经以我们实现了
        filterRuleMap.put("/logout","logout");
        filterRuleMap.put("/login","anon");
        filterRuleMap.put("/static/**", "anon");
        // 访问 /unauthorized/** 不通过JWTFilter
        filterRuleMap.put("/mqtest/**", "anon");
        filterRuleMap.put("/unauthorized/**", "anon");
        //放行 swagger 资源
        filterRuleMap.put("/swagger-resources/**", "anon");
        filterRuleMap.put("/doc.html", "anon");
        filterRuleMap.put("/v2/**", "anon");
        filterRuleMap.put("/webjars/**", "anon");
        // 放行 druid 资源
        filterRuleMap.put("/druid/**", "anon");
        filterRuleMap.put("/favicon.ico", "anon");
        filterRuleMap.put("/err/**", "anon");
        //放行 OA 登录请求
        filterRuleMap.put("/oa/login", "anon");
        filterRuleMap.put("/oa/esblogin", "anon");
        //放行 ESB 请求
        filterRuleMap.put("/esb/*", "anon");
        //放行 邮件推送 请求  白名单
        filterRuleMap.put("/mailSpms/*", "anon");
        //放行 SAP装箱单接口推送 请求  白名单
        filterRuleMap.put("/zxdSpms/*", "anon");
        //放行 图片打印 请求
        filterRuleMap.put("/barCode/getBarCode", "anon");
        filterRuleMap.put("/ureport/**", "anon");
        filterRuleMap.put("/actuator/**", "anon");//健康监控
        filterRuleMap.put("/image/uploadMaterialPic", "anon");//上传非目录物料申请图片增加白名单
        // 所有请求通过我们自己的JWT Filter
        filterRuleMap.put("/**", "jwt");
        factoryBean.setFilterChainDefinitionMap(filterRuleMap);
        return factoryBean;
    }

    /**
     * 注入 securityManager
     */
    @Bean
    public SecurityManager securityManager(CustomRealm customRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置自定义 realm.
        securityManager.setRealm(customRealm);

        /*
         * 关闭shiro自带的session，详情见文档
         * http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29
         */
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        securityManager.setSubjectDAO(subjectDAO);
        return securityManager;
    }

    /**
     * 添加注解支持
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        // 强制使用cglib，防止重复代理和可能引起代理出错的问题
        // https://zhuanlan.zhihu.com/p/29161098
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    /**
     * 开启shiro aop注解支持. 使用代理方式; 所以需要开启代码支持;
     *
     * @param securityManager 安全管理器
     * @return 授权Advisor
     */

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }
}
