All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.rdlinux.ezsecurity.spring.boot.autoconfig.EzSecurityAutoConfiguration Maven / Gradle / Ivy

There is a newer version: 0.1.6
Show newest version
package org.rdlinux.ezsecurity.spring.boot.autoconfig;

import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.subject.SubjectContext;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.mgt.DefaultWebSubjectFactory;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.rdlinux.ezsecurity.constant.AuthConstant;
import org.rdlinux.ezsecurity.shiro.content.EzSecurityContent;
import org.rdlinux.ezsecurity.shiro.holder.ErrorConstantHolder;
import org.rdlinux.ezsecurity.shiro.redis.cache.ShiroRedisCacheManager;
import org.rdlinux.ezsecurity.shiro.security.client.AuthClient;
import org.rdlinux.ezsecurity.shiro.security.client.ClientHolder;
import org.rdlinux.ezsecurity.shiro.security.filter.*;
import org.rdlinux.ezsecurity.shiro.security.interceptor.CustomAuthorizationAttributeSourceAdvisor;
import org.rdlinux.ezsecurity.shiro.security.realm.SecurityRealm;
import org.rdlinux.ezsecurity.shiro.security.rootfilter.secutirylogic.impl.DefaultSecurityLogic;
import org.rdlinux.ezsecurity.shiro.security.session.*;
import org.rdlinux.ezsecurity.shiro.spring.ShiroFilterFactoryBean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.lang.NonNull;

import javax.annotation.PostConstruct;
import javax.servlet.Filter;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Configuration
@ConditionalOnClass({EzSecurityProperties.class})
@EnableConfigurationProperties(EzSecurityProperties.class)
public class EzSecurityAutoConfiguration implements BeanFactoryAware {
    private final EzSecurityProperties ezSecurityProperties;
    private BeanFactory beanFactory;
    private List clients;
    private RedisTemplate redisTemplate;

    public EzSecurityAutoConfiguration(EzSecurityProperties ezSecurityProperties) {
        this.ezSecurityProperties = ezSecurityProperties;
    }

    private EzSecurityConfigurationAdvice getConfigurationAdvice() {
        try {
            return this.beanFactory.getBean(EzSecurityConfigurationAdvice.class);
        } catch (BeansException e) {
            throw new RuntimeException(e);
        }
    }


    @Override
    public void setBeanFactory(@NonNull BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
        this.initRedisTemplate();
        this.initEzSecurityContent();
        ObjectProvider customizerProvider = this.beanFactory
                .getBeanProvider(EzSecurityPropertiesCustomizer.class);
        List customizers = customizerProvider.orderedStream()
                .collect(Collectors.toList());
        for (EzSecurityPropertiesCustomizer customizer : customizers) {
            customizer.customize(this.ezSecurityProperties);
        }
    }

    /**
     * 初始化content
     */
    private void initEzSecurityContent() {
        EzSecurityConfigurationAdvice configurationAdvice = this.getConfigurationAdvice();
        EzSecurityContent.setErrorConstantHolder(new ErrorConstantHolder() {
            @Override
            public int getUnAuthenticated() {
                return EzSecurityAutoConfiguration.this.ezSecurityProperties.getUnAuthenticatedCode();
            }

            @Override
            public int getUnAuthorized() {
                return EzSecurityAutoConfiguration.this.ezSecurityProperties.getUnAuthorizedCode();
            }

            @Override
            public String getErrorMsg(int code) {
                if (code == EzSecurityAutoConfiguration.this.ezSecurityProperties.getUnAuthenticatedCode()) {
                    return configurationAdvice.getUnAuthenticatedMsg();
                } else {
                    return configurationAdvice.getUnAuthorizedMsg();
                }
            }
        });
        EzSecurityContent.setResponseRetConvert(configurationAdvice.getResponseRetConvert());
    }

    @SuppressWarnings({"rawtypes"})
    public void initRedisTemplate() {
        if (this.ezSecurityProperties.isEnableRedisCache() && this.beanFactory.containsBean("redisTemplate")) {
            RedisTemplate redisTemplate = this.beanFactory.getBean("redisTemplate", RedisTemplate.class);
            RedisConnectionFactory connectionFactory = redisTemplate.getConnectionFactory();
            if (connectionFactory != null) {
                final RedisTemplate template = new RedisTemplate<>();
                template.setConnectionFactory(connectionFactory);
                template.setKeySerializer(new StringRedisSerializer());
                template.setHashKeySerializer(new StringRedisSerializer());
                template.afterPropertiesSet();
                this.redisTemplate = template;
            }
        }
    }

    @PostConstruct
    public void init() {
        this.clients = new LinkedList<>();
        this.clients = this.getConfigurationAdvice().getClients(this.clients);
        this.clients.sort(Comparator.comparingInt(AuthClient::getOrder));
    }

    /**
     * session key存储器
     */
    @Bean
    public SessionKeyStore sessionKeyStore() {
        if (this.ezSecurityProperties.isEnableRedisCache()) {
            return new RedisSessionKeyStore(this.redisTemplate);
        } else {
            return new DefaultSessionKeyStore(this.ezSecurityProperties.getSessionTimeout() * 1000);
        }
    }

    @Bean
    public SecurityRealm securityRealm() {
        return new SecurityRealm(this.ezSecurityProperties.getCachePrefix());
    }

    /**
     * 认证client holder
     */
    @Bean
    public ClientHolder clientHolder() {
        AuthClient defaultAuthClient = null;
        String defaultAuthTypeName = this.ezSecurityProperties.getDefaultAuthType();
        if (defaultAuthTypeName == null || defaultAuthTypeName.isEmpty()) {
            defaultAuthTypeName = AuthConstant.USER_AUTH_TYPE;
        }
        for (AuthClient client : this.clients) {
            if (defaultAuthTypeName.equals(client.getAuthType())) {
                defaultAuthClient = client;
                break;
            }
        }
        return new ClientHolder(defaultAuthClient, this.clients);
    }

    /**
     * shiro会话管理
     */
    @Bean
    public SessionManager shiroSessionManage() {
        SecurityWebSessionManager shiroSessionManage = new SecurityWebSessionManager(this.sessionKeyStore(),
                this.clientHolder());
        // 设置redisSessionDAO
        if (this.ezSecurityProperties.isEnableRedisCache()) {
            shiroSessionManage.setSessionDAO(new SecurityShiroRedisSessionDAO(this.redisTemplate,
                    this.sessionKeyStore(), this.ezSecurityProperties.getCachePrefix()));
        }
        shiroSessionManage.setGlobalSessionTimeout(this.ezSecurityProperties.getSessionTimeout() * 1000);
        SimpleCookie simpleCookie = new SimpleCookie();
        simpleCookie.setName(AuthConstant.SESSION_ID_COOKIE_NAME);
        simpleCookie.setPath("/");
        shiroSessionManage.setSessionIdCookie(simpleCookie);
        // 是否启用会话调度
        shiroSessionManage.setSessionValidationSchedulerEnabled(this.ezSecurityProperties.getEnableSession());
        return shiroSessionManage;
    }

    /**
     * shiro securityManager
     */
    @Bean
    public SecurityManager shiroSecurityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        List realms = new ArrayList<>(3);
        realms.add(this.securityRealm());
        // 自定义realm
        securityManager.setRealms(realms);
        // 设置shrio会话管理
        securityManager.setSessionManager(this.shiroSessionManage());
        // 设置shrio缓存管理
        if (this.ezSecurityProperties.isEnableRedisCache()) {
            securityManager.setCacheManager(new ShiroRedisCacheManager(this.redisTemplate,
                    this.ezSecurityProperties.getCacheTimeout() * 1000));
        }
        // 设置subject工厂
        securityManager.setSubjectFactory(new DefaultWebSubjectFactory() {
            @Override
            public Subject createSubject(final SubjectContext context) {
                // 是否创建session
                context.setSessionCreationEnabled(EzSecurityAutoConfiguration.this.ezSecurityProperties
                        .getEnableSession());
                return super.createSubject(context);
            }
        });
        SecurityUtils.setSecurityManager(securityManager);
        DefaultSubjectDAO subjectDAO = (DefaultSubjectDAO) securityManager.getSubjectDAO();
        DefaultSessionStorageEvaluator sessionStorageEvaluator = (DefaultSessionStorageEvaluator) subjectDAO
                .getSessionStorageEvaluator();
        // 是否启用session存储
        sessionStorageEvaluator.setSessionStorageEnabled(this.ezSecurityProperties.getEnableSession());
        return securityManager;
    }

    /**
     * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
     */
    @Bean
    @ConditionalOnMissingBean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor =
                new CustomAuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    @Bean
    public FilterRegistrationBean delegatingFilterProxy() throws Exception {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setLoginUrl(this.ezSecurityProperties.getLoginUrl());
        shiroFilterFactoryBean.setUnauthorizedUrl(null);
        shiroFilterFactoryBean.setSuccessUrl(null);
        // 设置shiro security管理器
        shiroFilterFactoryBean.setSecurityManager(this.shiroSecurityManager());
        DefaultSecurityLogic securityLogic = new DefaultSecurityLogic();
        securityLogic.setEnableSession(this.ezSecurityProperties.getEnableSession());
        securityLogic.setClientHolder(this.clientHolder());
        securityLogic.setSessionKeyStore(this.sessionKeyStore());
        shiroFilterFactoryBean.setSecurityLogic(securityLogic);
        // 自定义shiro拦截器
        Map filters = new HashMap<>();
        // 跨域处理拦截器
        filters.put(AuthConstant.DEFAULT_ORIGIN_FILTER_NAME, new CorsFilter());
        filters.put(CorsFilter.name, new CorsFilter());
        filters.put(HeartbeatRequestFilter.name, new HeartbeatRequestFilter());
        filters.put(RedirectionFilter.name, new RedirectionFilter(this.ezSecurityProperties.getRedirections()));
        LogoutFilter logoutFilter = new LogoutFilter();
        filters.put(LogoutFilter.name, logoutFilter);
        LoginFilter loginFilter = new LoginFilter();
        filters.put(LoginFilter.name, loginFilter);
        filters.put(AuthConstant.DEFAULT_AUTHC_FILTER_NAME, new CustomFormAuthenticationFilter());
        filters.put(AuthConstant.DEFAULT_ROLE_FILTER_NAME, new CunstomRolesAuthorizationFilter());
        filters.put(AuthConstant.DEFAULT_PERMISSION_FILTER_NAME, new CustomPermissionsAuthorizationFilter());
        Map customFilters = this.getConfigurationAdvice().getFilters();
        if (customFilters != null && !customFilters.isEmpty()) {
            filters.putAll(customFilters);
        }
        shiroFilterFactoryBean.setFilters(filters);
        if (EzSecurityAutoConfiguration.log.isDebugEnabled()) {
            EzSecurityAutoConfiguration.log.debug(String.format("配置拦截器的url:%s",
                    this.ezSecurityProperties.getFilterChainDefinitions()));
        }
        shiroFilterFactoryBean.setFilterChainDefinitionMap(this.ezSecurityProperties.getFilterChainDefinitions());
        shiroFilterFactoryBean.setExceptionHandler(this.getConfigurationAdvice().getShiroFilterExceptionHandler());
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(Objects.requireNonNull(shiroFilterFactoryBean.getObject()));
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.setName("ezSecurityFilter");
        filterRegistrationBean.setOrder(this.ezSecurityProperties.getRootFilterOrder());
        filterRegistrationBean.setEnabled(true);
        return filterRegistrationBean;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy