SecurityInterceptor 核心
AbstractSecurityInterceptor
public abstract class AbstractSecurityInterceptor implements InitializingBean, ApplicationEventPublisherAware, MessageSourceAware { protected final Log logger = LogFactory.getLog(this.getClass()); protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor(); private ApplicationEventPublisher eventPublisher; private AccessDecisionManager accessDecisionManager; private AfterInvocationManager afterInvocationManager; private AuthenticationManager authenticationManager = new AbstractSecurityInterceptor.NoOpAuthenticationManager(); private RunAsManager runAsManager = new NullRunAsManager(); private boolean alwaysReauthenticate = false; private boolean rejectPublicInvocations = false; private boolean validateConfigAttributes = true; private boolean publishAuthorizationSuccess = false; public AbstractSecurityInterceptor() { } public void afterPropertiesSet() throws Exception { Assert.notNull(this.getSecureObjectClass(), "Subclass must provide a non-null response to getSecureObjectClass()"); Assert.notNull(this.messages, "A message source must be set"); Assert.notNull(this.authenticationManager, "An AuthenticationManager is required"); Assert.notNull(this.accessDecisionManager, "An AccessDecisionManager is required"); Assert.notNull(this.runAsManager, "A RunAsManager is required"); Assert.notNull(this.obtainSecurityMetadataSource(), "An SecurityMetadataSource is required"); Assert.isTrue(this.obtainSecurityMetadataSource().supports(this.getSecureObjectClass()), "SecurityMetadataSource does not support secure object class: " + this.getSecureObjectClass()); Assert.isTrue(this.runAsManager.supports(this.getSecureObjectClass()), "RunAsManager does not support secure object class: " + this.getSecureObjectClass()); Assert.isTrue(this.accessDecisionManager.supports(this.getSecureObjectClass()), "AccessDecisionManager does not support secure object class: " + this.getSecureObjectClass()); if (this.afterInvocationManager != null) { Assert.isTrue(this.afterInvocationManager.supports(this.getSecureObjectClass()), "AfterInvocationManager does not support secure object class: " + this.getSecureObjectClass()); } if (this.validateConfigAttributes) { Collection<ConfigAttribute> attributeDefs = this.obtainSecurityMetadataSource().getAllConfigAttributes(); if (attributeDefs == null) { this.logger.warn("Could not validate configuration attributes as the SecurityMetadataSource did not return any attributes from getAllConfigAttributes()"); } else { Set<ConfigAttribute> unsupportedAttrs = new HashSet(); Iterator var3 = attributeDefs.iterator(); while(true) { ConfigAttribute attr; do { do { do { if (!var3.hasNext()) { if (unsupportedAttrs.size() != 0) { throw new IllegalArgumentException("Unsupported configuration attributes: " + unsupportedAttrs); } this.logger.debug("Validated configuration attributes"); return; } attr = (ConfigAttribute)var3.next(); } while(this.runAsManager.supports(attr)); } while(this.accessDecisionManager.supports(attr)); } while(this.afterInvocationManager != null && this.afterInvocationManager.supports(attr)); unsupportedAttrs.add(attr); } } } } protected InterceptorStatusToken beforeInvocation(Object object) { Assert.notNull(object, "Object was null"); boolean debug = this.logger.isDebugEnabled(); if (!this.getSecureObjectClass().isAssignableFrom(object.getClass())) { throw new IllegalArgumentException("Security invocation attempted for object " + object.getClass().getName() + " but AbstractSecurityInterceptor only configured to support secure objects of type: " + this.getSecureObjectClass()); } else { Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource().getAttributes(object); if (attributes != null && !attributes.isEmpty()) { if (debug) { this.logger.debug("Secure object: " + object + "; Attributes: " + attributes); } if (SecurityContextHolder.getContext().getAuthentication() == null) { this.credentialsNotFound(this.messages.getMessage("AbstractSecurityInterceptor.authenticationNotFound", "An Authentication object was not found in the SecurityContext"), object, attributes); } Authentication authenticated = this.authenticateIfRequired(); try { this.accessDecisionManager.decide(authenticated, object, attributes); } catch (AccessDeniedException var7) { this.publishEvent(new AuthorizationFailureEvent(object, attributes, authenticated, var7)); throw var7; } if (debug) { this.logger.debug("Authorization successful"); } if (this.publishAuthorizationSuccess) { this.publishEvent(new AuthorizedEvent(object, attributes, authenticated)); } Authentication runAs = this.runAsManager.buildRunAs(authenticated, object, attributes); if (runAs == null) { if (debug) { this.logger.debug("RunAsManager did not change Authentication object"); } return new InterceptorStatusToken(SecurityContextHolder.getContext(), false, attributes, object); } else { if (debug) { this.logger.debug("Switching to RunAs Authentication: " + runAs); } SecurityContext origCtx = SecurityContextHolder.getContext(); SecurityContextHolder.setContext(SecurityContextHolder.createEmptyContext()); SecurityContextHolder.getContext().setAuthentication(runAs); return new InterceptorStatusToken(origCtx, true, attributes, object); } } else if (this.rejectPublicInvocations) { throw new IllegalArgumentException("Secure object invocation " + object + " was denied as public invocations are not allowed via this interceptor. This indicates a configuration error because the rejectPublicInvocations property is set to 'true'"); } else { if (debug) { this.logger.debug("Public object - authentication not attempted"); } this.publishEvent(new PublicInvocationEvent(object)); return null; } } } protected void finallyInvocation(InterceptorStatusToken token) { if (token != null && token.isContextHolderRefreshRequired()) { if (this.logger.isDebugEnabled()) { this.logger.debug("Reverting to original Authentication: " + token.getSecurityContext().getAuthentication()); } SecurityContextHolder.setContext(token.getSecurityContext()); } } protected Object afterInvocation(InterceptorStatusToken token, Object returnedObject) { if (token == null) { return returnedObject; } else { this.finallyInvocation(token); if (this.afterInvocationManager != null) { try { returnedObject = this.afterInvocationManager.decide(token.getSecurityContext().getAuthentication(), token.getSecureObject(), token.getAttributes(), returnedObject); } catch (AccessDeniedException var5) { AuthorizationFailureEvent event = new AuthorizationFailureEvent(token.getSecureObject(), token.getAttributes(), token.getSecurityContext().getAuthentication(), var5); this.publishEvent(event); throw var5; } } return returnedObject; } } private Authentication authenticateIfRequired() { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication.isAuthenticated() && !this.alwaysReauthenticate) { if (this.logger.isDebugEnabled()) { this.logger.debug("Previously Authenticated: " + authentication); } return authentication; } else { authentication = this.authenticationManager.authenticate(authentication); if (this.logger.isDebugEnabled()) { this.logger.debug("Successfully Authenticated: " + authentication); } SecurityContextHolder.getContext().setAuthentication(authentication); return authentication; } } private void credentialsNotFound(String reason, Object secureObject, Collection<ConfigAttribute> configAttribs) { AuthenticationCredentialsNotFoundException exception = new AuthenticationCredentialsNotFoundException(reason); AuthenticationCredentialsNotFoundEvent event = new AuthenticationCredentialsNotFoundEvent(secureObject, configAttribs, exception); this.publishEvent(event); throw exception; } public AccessDecisionManager getAccessDecisionManager() { return this.accessDecisionManager; } public AfterInvocationManager getAfterInvocationManager() { return this.afterInvocationManager; } public AuthenticationManager getAuthenticationManager() { return this.authenticationManager; } public RunAsManager getRunAsManager() { return this.runAsManager; } public abstract Class<?> getSecureObjectClass(); public boolean isAlwaysReauthenticate() { return this.alwaysReauthenticate; } public boolean isRejectPublicInvocations() { return this.rejectPublicInvocations; } public boolean isValidateConfigAttributes() { return this.validateConfigAttributes; } public abstract SecurityMetadataSource obtainSecurityMetadataSource(); public void setAccessDecisionManager(AccessDecisionManager accessDecisionManager) { this.accessDecisionManager = accessDecisionManager; } public void setAfterInvocationManager(AfterInvocationManager afterInvocationManager) { this.afterInvocationManager = afterInvocationManager; } public void setAlwaysReauthenticate(boolean alwaysReauthenticate) { this.alwaysReauthenticate = alwaysReauthenticate; } public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { this.eventPublisher = applicationEventPublisher; } public void setAuthenticationManager(AuthenticationManager newManager) { this.authenticationManager = newManager; } public void setMessageSource(MessageSource messageSource) { this.messages = new MessageSourceAccessor(messageSource); } public void setPublishAuthorizationSuccess(boolean publishAuthorizationSuccess) { this.publishAuthorizationSuccess = publishAuthorizationSuccess; } public void setRejectPublicInvocations(boolean rejectPublicInvocations) { this.rejectPublicInvocations = rejectPublicInvocations; } public void setRunAsManager(RunAsManager runAsManager) { this.runAsManager = runAsManager; } public void setValidateConfigAttributes(boolean validateConfigAttributes) { this.validateConfigAttributes = validateConfigAttributes; } private void publishEvent(ApplicationEvent event) { if (this.eventPublisher != null) { this.eventPublisher.publishEvent(event); } } private static class NoOpAuthenticationManager implements AuthenticationManager { private NoOpAuthenticationManager() { } public Authentication authenticate(Authentication authentication) throws AuthenticationException { throw new AuthenticationServiceException("Cannot authenticate " + authentication); } } }
FilterSecurityInterceptor
public class FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter { // ~ Static fields/initializers // ===================================================================================== private static final String FILTER_APPLIED = "__spring_security_filterSecurityInterceptor_filterApplied"; // ~ Instance fields // ================================================================================================ private FilterInvocationSecurityMetadataSource securityMetadataSource; private boolean observeOncePerRequest = true; // ~ Methods // ======================================================================================================== /** * Not used (we rely on IoC container lifecycle services instead) * * @param arg0 ignored * * @throws ServletException never thrown */ public void init(FilterConfig arg0) throws ServletException { } /** * Not used (we rely on IoC container lifecycle services instead) */ public void destroy() { } /** * Method that is actually called by the filter chain. Simply delegates to the * {@link #invoke(FilterInvocation)} method. * * @param request the servlet request * @param response the servlet response * @param chain the filter chain * * @throws IOException if the filter chain fails * @throws ServletException if the filter chain fails */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { FilterInvocation fi = new FilterInvocation(request, response, chain); invoke(fi); } public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() { return this.securityMetadataSource; } public SecurityMetadataSource obtainSecurityMetadataSource() { return this.securityMetadataSource; } public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource newSource) { this.securityMetadataSource = newSource; } public Class<?> getSecureObjectClass() { return FilterInvocation.class; } public void invoke(FilterInvocation fi) throws IOException, ServletException { if ((fi.getRequest() != null) && (fi.getRequest().getAttribute(FILTER_APPLIED) != null) && observeOncePerRequest) { // filter already applied to this request and user wants us to observe // once-per-request handling, so don't re-do security checking fi.getChain().doFilter(fi.getRequest(), fi.getResponse()); } else { // first time this request being called, so perform security checking if (fi.getRequest() != null && observeOncePerRequest) { fi.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE); } InterceptorStatusToken token = super.beforeInvocation(fi); try { fi.getChain().doFilter(fi.getRequest(), fi.getResponse()); } finally { super.finallyInvocation(token); } super.afterInvocation(token, null); } } /** * Indicates whether once-per-request handling will be observed. By default this is * <code>true</code>, meaning the <code>FilterSecurityInterceptor</code> will only * execute once-per-request. Sometimes users may wish it to execute more than once per * request, such as when JSP forwards are being used and filter security is desired on * each included fragment of the HTTP request. * * @return <code>true</code> (the default) if once-per-request is honoured, otherwise * <code>false</code> if <code>FilterSecurityInterceptor</code> will enforce * authorizations for each and every fragment of the HTTP request. */ public boolean isObserveOncePerRequest() { return observeOncePerRequest; } public void setObserveOncePerRequest(boolean observeOncePerRequest) { this.observeOncePerRequest = observeOncePerRequest; } }
SecurityMetadataSource
public interface SecurityMetadataSource extends AopInfrastructureBean { Collection<ConfigAttribute> getAttributes(Object var1) throws IllegalArgumentException; Collection<ConfigAttribute> getAllConfigAttributes(); boolean supports(Class<?> var1); }
FilterInvocationSecurityMetadataSource
public interface FilterInvocationSecurityMetadataSource extends SecurityMetadataSource { }
0