package com.hwlcn.security.spring.web;
import com.hwlcn.security.config.Ini;
import com.hwlcn.security.util.CollectionUtils;
import com.hwlcn.security.util.Nameable;
import com.hwlcn.security.util.StringUtils;
import com.hwlcn.security.web.filter.AccessControlFilter;
import com.hwlcn.security.web.filter.authc.AuthenticationFilter;
import com.hwlcn.security.web.filter.authc.LogoutFilter;
import com.hwlcn.security.web.filter.authz.AuthorizationFilter;
import com.hwlcn.security.web.filter.mgt.DefaultFilterChainManager;
import com.hwlcn.security.web.filter.mgt.FilterChainManager;
import com.hwlcn.security.web.filter.mgt.FilterChainResolver;
import com.hwlcn.security.web.filter.mgt.PathMatchingFilterChainResolver;
import com.hwlcn.security.web.mgt.WebSecurityManager;
import com.hwlcn.security.web.servlet.AbstractSecurityFilter;
import com.hwlcn.security.mgt.SecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;
public class SecurityFilterFactoryBean implements FactoryBean, BeanPostProcessor {
private static transient final Logger log = LoggerFactory.getLogger(SecurityFilterFactoryBean.class);
public static final String URLS = "urls";
private SecurityManager securityManager;
private Map<String, Filter> filters;
private Map<String, String> filterChainDefinitionMap;
private String loginUrl;
private String successUrl;
private String unauthorizedUrl;
private String logoutRedirectUrl;
private AbstractSecurityFilter instance;
public SecurityFilterFactoryBean() {
this.filters = new LinkedHashMap<String, Filter>();
this.filterChainDefinitionMap = new LinkedHashMap<String, String>();
}
public SecurityManager getSecurityManager() {
return securityManager;
}
public void setSecurityManager(SecurityManager securityManager) {
this.securityManager = securityManager;
}
public String getLoginUrl() {
return loginUrl;
}
public void setLoginUrl(String loginUrl) {
this.loginUrl = loginUrl;
}
public String getSuccessUrl() {
return successUrl;
}
public void setSuccessUrl(String successUrl) {
this.successUrl = successUrl;
}
public String getUnauthorizedUrl() {
return unauthorizedUrl;
}
public void setUnauthorizedUrl(String unauthorizedUrl) {
this.unauthorizedUrl = unauthorizedUrl;
}
public Map<String, Filter> getFilters() {
return filters;
}
public void setFilters(Map<String, Filter> filters) {
this.filters = filters;
}
public Map<String, String> getFilterChainDefinitionMap() {
return filterChainDefinitionMap;
}
public void setFilterChainDefinitionMap(Map<String, String> filterChainDefinitionMap) {
this.filterChainDefinitionMap = filterChainDefinitionMap;
}
public void setFilterChainDefinitions(String definitions) {
Ini ini = new Ini();
ini.load(definitions);
Ini.Section section = ini.getSection(URLS);
if (CollectionUtils.isEmpty(section)) {
section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
}
setFilterChainDefinitionMap(section);
}
public Object getObject() throws Exception {
if (instance == null) {
instance = createInstance();
}
return instance;
}
public Class getObjectType() {
return SpringSecurityFilter.class;
}
public boolean isSingleton() {
return true;
}
protected FilterChainManager createFilterChainManager() {
DefaultFilterChainManager manager = new DefaultFilterChainManager();
Map<String, Filter> defaultFilters = manager.getFilters();
for (Filter filter : defaultFilters.values()) {
applyGlobalPropertiesIfNecessary(filter);
}
Map<String, Filter> filters = getFilters();
if (!CollectionUtils.isEmpty(filters)) {
for (Map.Entry<String, Filter> entry : filters.entrySet()) {
String name = entry.getKey();
Filter filter = entry.getValue();
applyGlobalPropertiesIfNecessary(filter);
if (filter instanceof Nameable) {
((Nameable) filter).setName(name);
}
manager.addFilter(name, filter, false);
}
}
Map<String, String> chains = getFilterChainDefinitionMap();
if (!CollectionUtils.isEmpty(chains)) {
for (Map.Entry<String, String> entry : chains.entrySet()) {
String url = entry.getKey();
String chainDefinition = entry.getValue();
manager.createChain(url, chainDefinition);
}
}
return manager;
}
protected AbstractSecurityFilter createInstance() throws Exception {
if (log.isDebugEnabled()) {
log.debug("Creating Secirity Filter instance.");
}
SecurityManager securityManager = getSecurityManager();
if (securityManager == null) {
String msg = "SecurityManager property must be set.";
throw new BeanInitializationException(msg);
}
if (!(securityManager instanceof WebSecurityManager)) {
String msg = "The security manager does not implement the WebSecurityManager interface.";
throw new BeanInitializationException(msg);
}
FilterChainManager manager = createFilterChainManager();
PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
chainResolver.setFilterChainManager(manager);
return new SpringSecurityFilter((WebSecurityManager) securityManager, chainResolver);
}
private void applyLoginUrlIfNecessary(Filter filter) {
String loginUrl = getLoginUrl();
if (StringUtils.hasText(loginUrl) && (filter instanceof AccessControlFilter)) {
AccessControlFilter acFilter = (AccessControlFilter) filter;
String existingLoginUrl = acFilter.getLoginUrl();
if (AccessControlFilter.DEFAULT_LOGIN_URL.equals(existingLoginUrl)) {
acFilter.setLoginUrl(loginUrl);
}
}
}
private void applyLogoutRedirectUrlIfNecessary(Filter filter) {
String logoutRedirectUrl = getLogoutRedirectUrl();
if (StringUtils.hasText(logoutRedirectUrl) && (filter instanceof LogoutFilter)) {
LogoutFilter logoutFilter = (LogoutFilter) filter;
String existingLoginUrl = logoutFilter.getRedirectUrl();
if (LogoutFilter.DEFAULT_REDIRECT_URL.equals(existingLoginUrl)) {
logoutFilter.setRedirectUrl(logoutRedirectUrl);
}
}
}
private void applySuccessUrlIfNecessary(Filter filter) {
String successUrl = getSuccessUrl();
if (StringUtils.hasText(successUrl) && (filter instanceof AuthenticationFilter)) {
AuthenticationFilter authcFilter = (AuthenticationFilter) filter;
String existingSuccessUrl = authcFilter.getSuccessUrl();
if (AuthenticationFilter.DEFAULT_SUCCESS_URL.equals(existingSuccessUrl)) {
authcFilter.setSuccessUrl(successUrl);
}
}
}
private void applyUnauthorizedUrlIfNecessary(Filter filter) {
String unauthorizedUrl = getUnauthorizedUrl();
if (StringUtils.hasText(unauthorizedUrl) && (filter instanceof AuthorizationFilter)) {
AuthorizationFilter authzFilter = (AuthorizationFilter) filter;
String existingUnauthorizedUrl = authzFilter.getUnauthorizedUrl();
if (existingUnauthorizedUrl == null) {
authzFilter.setUnauthorizedUrl(unauthorizedUrl);
}
}
}
private void applyGlobalPropertiesIfNecessary(Filter filter) {
applyLoginUrlIfNecessary(filter);
applySuccessUrlIfNecessary(filter);
applyUnauthorizedUrlIfNecessary(filter);
applyLogoutRedirectUrlIfNecessary(filter);//退出后跳转界面
}
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof Filter) {
if (log.isDebugEnabled()) {
log.debug("Found filter chain candidate filter '{}'", beanName);
}
Filter filter = (Filter) bean;
applyGlobalPropertiesIfNecessary(filter);
getFilters().put(beanName, filter);
} else {
if (log.isTraceEnabled()) {
log.trace("Ignoring non-Filter bean '{}'", beanName);
}
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
private static final class SpringSecurityFilter extends AbstractSecurityFilter {
protected SpringSecurityFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver) {
super();
if (webSecurityManager == null) {
throw new IllegalArgumentException("WebSecurityManager property cannot be null.");
}
setSecurityManager(webSecurityManager);
if (resolver != null) {
setFilterChainResolver(resolver);
}
}
}
public String getLogoutRedirectUrl() {
return logoutRedirectUrl;
}
public void setLogoutRedirectUrl(String logoutRedirectUrl) {
this.logoutRedirectUrl = logoutRedirectUrl;
}
}