org.rdlinux.ezsecurity.spring.boot.autoconfig.EzSecurityAutoConfiguration Maven / Gradle / Ivy
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