Spring Security学习(一)认证与授权

Spring Security

Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。简单来说springsecurity主要对用户进行认证以及授权。认证是指验证用户是否为当前系统中的用户, 授权是指验证用户是否有权限执行某个操作。故此本文着重从认证以及授权两个方向对springsecurity进行分析。

核心组件

  1. SecurityContextHolder
    SecurityContextHolder 提供对 SecurityContext 的访问, SecurityContextHolder 通过 threadLocal存储信息,因而 SecurityContext可以在线程执行期间的任何一处访问。

  2. SecurityContext
    SecurityContext 持有认证对象的相关信息。

  3. Authentication
    spring ssecurity形式的认证主体

  4. GrantedAuthority
    在应用层面对认证主体的授权,包含了权限等信息

  5. UserDetails
    包含了构建认证主体所必须的信息

  6. UserDetailsService
    根据username构建UserDetails

在项目的任何位置我们都可以通过以下代码获取当前用户信息

Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

if (principal instanceof UserDetails) {
String username = ((UserDetails)principal).getUsername();
} else {
String username = principal.toString();
}

认证

spring security 认证授权过程主要是通过核心滤器链实现的

Spring Security核心过滤器链,如下面日志所示:

 o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: any request, [
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@29a98d9f, 
org.springframework.security.web.context.SecurityContextPersistenceFilter@3d7fb838, 
org.springframework.security.web.header.HeaderWriterFilter@3aa41da1, 
org.springframework.security.web.csrf.CsrfFilter@1352434e, 
org.springframework.security.web.authentication.logout.LogoutFilter@4acb7ecc, 
org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@1afd72ef, 
org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@254f906e, 
org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@2da3b078, 
org.springframework.security.web.authentication.www.BasicAuthenticationFilter@1b1c538d, 
org.springframework.security.web.savedrequest.RequestCacheAwareFilter@3a37a501, 
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@2dc3271b, 
org.springframework.security.web.authentication.AnonymousAuthenticationFilter@544e8149, 
org.springframework.security.web.session.SessionManagementFilter@3c83468e, 
org.springframework.security.web.access.ExceptionTranslationFilter@267dc982, 
org.springframework.security.web.access.intercept.FilterSecurityInterceptor@7b122839]

下面先简单介绍这些过滤器的作用:

  1. WebAsyncManagerIntegrationFilter 提供了 securityContext 和 WebAsyncManager 的集成,其会把SecurityContext 设置到异步线程中,使其也能获取到用户上下文认证信息;
  2. SecurityContextPersistenceFilter 主要是在请求开始处理之前,从SecurityContextRepository中获取安全上下文信息填充到SecurityContextHolder,在请求处理结束开始返回响应时,将SecurityContextHolder中的安全上下文信息保存回SecurityContextRepository,并清空SecurityContextHolder。
  3. HeaderWriterFilter 作用是在一个请求的处理过程中为响应对象增加一些头部信息,比如X-Frame-Options, X-XSS-Protection和X-Content-Type-Options等;
  4. CsrfFilter 作用是解决CSRF攻击(跨站请求伪造),通过生成一个不同的,随机的,不可预测的token实现这一功能;
  5. LogoutFilter 用于检测用户退出登录请求,执行相应的处理工作(销毁session和SecurityContextHolder内容等等)以及退出登录后的页面跳转。
  6. UsernamePasswordAuthenticationFilter 用于拦截用户请求,看它是否是一个来自用户名/密码表单登录页面提交的用户登录认证请求,若是,该请求就不会在整个filter chain中继续传递了,而是会被当前过滤器调用所指定的 AuthenticationManager 认证所提交的用户名/密码;
  7. DefaultLoginPageGeneratingFilter 的作用是当安全配置中没有配置相应的登录页面时,该过滤器自动构造一个登录页面给用户;
  8. DefaultLogoutPageGeneratingFilter 的作用是构造一个默认的用户退出页面
  9. BasicAuthenticationFilter 的作用是处理HTTP请求中的BASIC authorization头部,把认证结果写入SecurityContextHolder;
  10. RequestCacheAwareFilter 提取和使用被缓存的请求;
  11. SecurityContextHolderAwareRequestFilter 对请求采用Wrapper/Decorator模式包装成一个可以访问SecurityContextHolder中安全上下文的SecurityContextHolderAwareRequestWrapper。这样接口HttpServletRequest上定义的getUserPrincipal这种安全相关的方法才能访问到相应的安全信息;
  12. AnonymousAuthenticationFilter 用于检测 SecurityContextHolder 中是否存在Authentication对象,如果不存在,说明用户尚未登录,则为其提供一个匿名Authentication对象(AnonymousAuthentication),表明这是一个匿名访问;
  13. SessionManagementFilter 检测从当前请求处理开始到目前为止的过程中是否发生了用户登录认证行为,若有,则会执行相应的session认证策略;
  14. ExceptionTranslationFilter 处理过滤器链中发生的 AccessDeniedException 和 AuthenticationException 异常,将结果响应给客户端;
  15. FilterSecurityInterceptor 执行真正的HTTP资源安全控制

每一个请求在经过这一轮认证通过之后才能真正的访问我们的资源。

重点分析 UsernamePasswordAuthenticationFilter :

用户认证部分主要依靠这个过滤器来实现

该过滤器用于拦截用户登陆请求,看它是否是一个来自用户名/密码表单登录页面提交的用户登录认证请求,缺省使用的匹配模式是:POST /login。一般情况下,如果是用户登录认证请求,该请求就不会在整个过滤器链中继续传递了,而是会被当前过滤器处理并进入响应用户阶段。

public class UsernamePasswordAuthenticationFilter extends
		AbstractAuthenticationProcessingFilter {
	// 默认的用户名密码字段是username,password
	public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";
	public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";

	private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY;
	private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;
	private boolean postOnly = true;

	public UsernamePasswordAuthenticationFilter() {
		super(new AntPathRequestMatcher("/login", "POST"));
	}

	public Authentication attemptAuthentication(HttpServletRequest request,
			HttpServletResponse response) throws AuthenticationException {
		if (postOnly && !request.getMethod().equals("POST")) {
			throw new AuthenticationServiceException(
					"Authentication method not supported: " + request.getMethod());
		}

		// 从请求中获取用户名/密码
		String username = obtainUsername(request);
		String password = obtainPassword(request);

		if (username == null) {
			username = "";
		}

		if (password == null) {
			password = "";
		}

		username = username.trim();

		// 根据用户提供的用户名/密码信息构建一个认证token
		UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
				username, password);

		// Allow subclasses to set the "details" property
		setDetails(request, authRequest);
		// 交给 authenticationManager执行真正的用户身份认证
		return this.getAuthenticationManager().authenticate(authRequest);
	}

	@Nullable
	protected String obtainPassword(HttpServletRequest request) {
		return request.getParameter(passwordParameter);
	}

	@Nullable
	protected String obtainUsername(HttpServletRequest request) {
		return request.getParameter(usernameParameter);
	}
	
	protected void setDetails(HttpServletRequest request,
			UsernamePasswordAuthenticationToken authRequest) {
		authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
	}

	public void setUsernameParameter(String usernameParameter) {
		Assert.hasText(usernameParameter, "Username parameter must not be empty or null");
		this.usernameParameter = usernameParameter;
	}

	public void setPasswordParameter(String passwordParameter) {
		Assert.hasText(passwordParameter, "Password parameter must not be empty or null");
		this.passwordParameter = passwordParameter;
	}

	public void setPostOnly(boolean postOnly) {
		this.postOnly = postOnly;
	}

	public final String getUsernameParameter() {
		return usernameParameter;
	}

	public final String getPasswordParameter() {
		return passwordParameter;
	}
}

父类

public abstract class AbstractAuthenticationProcessingFilter extends GenericFilterBean
		implements ApplicationEventPublisherAware, MessageSourceAware {
		
	protected ApplicationEventPublisher eventPublisher;
	protected AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
	// 认证管理器
	private AuthenticationManager authenticationManager;
	protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
	private RememberMeServices rememberMeServices = new NullRememberMeServices();

	private RequestMatcher requiresAuthenticationRequestMatcher;

	// 登录认证成功时是否继续执行filter chain,缺省为false,该属性安全配置阶段会重新指定, 但安全配置阶段缺省使用的值也是false,表示登录认证成功时直接进入响应用户阶段
	private boolean continueChainBeforeSuccessfulAuthentication = false;

	// session 认证策略
	private SessionAuthenticationStrategy sessionStrategy = new NullAuthenticatedSessionStrategy();

	private boolean allowSessionCreation = true;

	private AuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
	private AuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();

	protected AbstractAuthenticationProcessingFilter(String defaultFilterProcessesUrl) {
		setFilterProcessesUrl(defaultFilterProcessesUrl);
	}

	protected AbstractAuthenticationProcessingFilter(
			RequestMatcher requiresAuthenticationRequestMatcher) {
		Assert.notNull(requiresAuthenticationRequestMatcher,
				"requiresAuthenticationRequestMatcher cannot be null");
		this.requiresAuthenticationRequestMatcher = requiresAuthenticationRequestMatcher;
	}

	@Override
	public void afterPropertiesSet() {
		Assert.notNull(authenticationManager, "authenticationManager must be specified");
	}

	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
			throws IOException, ServletException {

		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) res;

		if (!requiresAuthentication(request, response)) {
		// 检查当前请求是否是一个用户名/密码登录表单请求,如果不是,则放行不做处理
			chain.doFilter(request, response);

			return;
		}

		if (logger.isDebugEnabled()) {
			logger.debug("Request is to process authentication");
		}

		Authentication authResult;

		try {
			// AuthenticationManger 执行认证
			authResult = attemptAuthentication(request, response);
			if (authResult == null) {
				// return immediately as subclass has indicated that it hasn't completed
				// authentication
				return;
			}
			// 执行session认证策略
			sessionStrategy.onAuthentication(authResult, request, response);
		}
		catch (InternalAuthenticationServiceException failed) {
			logger.error(
					"An internal error occurred while trying to authenticate the user.",
					failed);
					// 认证失败
			unsuccessfulAuthentication(request, response, failed);

			return;
		}
		catch (AuthenticationException failed) {
			// Authentication failed
			unsuccessfulAuthentication(request, response, failed);

			return;
		}

		// Authentication success
		if (continueChainBeforeSuccessfulAuthentication) {
			chain.doFilter(request, response);
		}
		// 认证成功
		successfulAuthentication(request, response, chain, authResult);
	}


	protected boolean requiresAuthentication(HttpServletRequest request,
			HttpServletResponse response) {
		return requiresAuthenticationRequestMatcher.matches(request);
	}

	public abstract Authentication attemptAuthentication(HttpServletRequest request,
			HttpServletResponse response) throws AuthenticationException, IOException,
			ServletException;


	protected void successfulAuthentication(HttpServletRequest request,
			HttpServletResponse response, FilterChain chain, Authentication authResult)
			throws IOException, ServletException {

		if (logger.isDebugEnabled()) {
			logger.debug("Authentication success. Updating SecurityContextHolder to contain: "
					+ authResult);
		}
		// 设置SecurityContext
		SecurityContextHolder.getContext().setAuthentication(authResult);

		// 若配置了rememberMe进行相应的记录
		rememberMeServices.loginSuccess(request, response, authResult);

		// Fire event
		if (this.eventPublisher != null) {
			eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(
					authResult, this.getClass()));
		}

		// 成功回调
		successHandler.onAuthenticationSuccess(request, response, authResult);
	}

	protected void unsuccessfulAuthentication(HttpServletRequest request,
			HttpServletResponse response, AuthenticationException failed)
			throws IOException, ServletException {
		SecurityContextHolder.clearContext();

		if (logger.isDebugEnabled()) {
			logger.debug("Authentication request failed: " + failed.toString(), failed);
			logger.debug("Updated SecurityContextHolder to contain null Authentication");
			logger.debug("Delegating to authentication failure handler " + failureHandler);
		}

		rememberMeServices.loginFail(request, response);

		failureHandler.onAuthenticationFailure(request, response, failed);
	}

	protected AuthenticationManager getAuthenticationManager() {
		return authenticationManager;
	}

	public void setAuthenticationManager(AuthenticationManager authenticationManager) {
		this.authenticationManager = authenticationManager;
	}

	public void setFilterProcessesUrl(String filterProcessesUrl) {
		setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(
				filterProcessesUrl));
	}

	public final void setRequiresAuthenticationRequestMatcher(
			RequestMatcher requestMatcher) {
		Assert.notNull(requestMatcher, "requestMatcher cannot be null");
		this.requiresAuthenticationRequestMatcher = requestMatcher;
	}

	public RememberMeServices getRememberMeServices() {
		return rememberMeServices;
	}

	public void setRememberMeServices(RememberMeServices rememberMeServices) {
		Assert.notNull(rememberMeServices, "rememberMeServices cannot be null");
		this.rememberMeServices = rememberMeServices;
	}


	public void setContinueChainBeforeSuccessfulAuthentication(
			boolean continueChainBeforeSuccessfulAuthentication) {
		this.continueChainBeforeSuccessfulAuthentication = continueChainBeforeSuccessfulAuthentication;
	}

	public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) {
		this.eventPublisher = eventPublisher;
	}

	public void setAuthenticationDetailsSource(
			AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource) {
		Assert.notNull(authenticationDetailsSource,
				"AuthenticationDetailsSource required");
		this.authenticationDetailsSource = authenticationDetailsSource;
	}

	public void setMessageSource(MessageSource messageSource) {
		this.messages = new MessageSourceAccessor(messageSource);
	}

	protected boolean getAllowSessionCreation() {
		return allowSessionCreation;
	}

	public void setAllowSessionCreation(boolean allowSessionCreation) {
		this.allowSessionCreation = allowSessionCreation;
	}

	public void setSessionAuthenticationStrategy(
			SessionAuthenticationStrategy sessionStrategy) {
		this.sessionStrategy = sessionStrategy;
	}

	/**
	 * Sets the strategy used to handle a successful authentication. By default a
	 * {@link SavedRequestAwareAuthenticationSuccessHandler} is used.
	 */
	public void setAuthenticationSuccessHandler(
			AuthenticationSuccessHandler successHandler) {
		Assert.notNull(successHandler, "successHandler cannot be null");
		this.successHandler = successHandler;
	}

	public void setAuthenticationFailureHandler(
			AuthenticationFailureHandler failureHandler) {
		Assert.notNull(failureHandler, "failureHandler cannot be null");
		this.failureHandler = failureHandler;
	}

	protected AuthenticationSuccessHandler getSuccessHandler() {
		return successHandler;
	}

	protected AuthenticationFailureHandler getFailureHandler() {
		return failureHandler;
	}
}

关于认证管理器部分,后面的文章会继续分析,但这不影响我们了解认证的大体过程,

从上面的代码结合注释可以知道,如果认证成功,则会 :

  1. 调用所设置的SessionAuthenticationStrategy会话认证策略;

  2. 经过完全认证的Authentication对象设置到SecurityContextHolder中的SecurityContext上;

  3. 如果请求要求了Remember Me,进行相应记录;

  4. 发布事件InteractiveAuthenticationSuccessEvent;

  5. 执行配置的successHandler;

授权

授权主要由AbstractSecurityInterceptor及其子类完成;

AbstractSecurityInterceptor 主要有两个实现类

  1. FilterSecurityInterceptor 基于servlet Filter技术,应用于Web请求的授权控制

  2. MethodSecurityInterceptor 基于AOP技术,应用于方法调用的授权控制

简单分析一下这三个类:

首先 FilterSecurityInterceptor:

...
public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		// 将请求上下文信息为一个 FilterInvocation 对象   
		FilterInvocation fi = new FilterInvocation(request, response, chain);
		// 调用该FilterInvocation执行安全认证
		invoke(fi);
	}
...

public void invoke(FilterInvocation fi) throws IOException, ServletException {
		if ((fi.getRequest() != null)
				&& (fi.getRequest().getAttribute(FILTER_APPLIED) != null)
				&& observeOncePerRequest) {
			// 如果被设置为在整个请求处理过程中只能执行一次 ,并且监测到已经执行过,直接放行,继续 filter chain 的执行
			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);
			}

			// 这里是进行必要的认证和授权检查,具体实现在父类AbstractSecurityInterceptor中
          	// 如果遇到相关异常则抛出异常,之后的过滤器链不会继续执行
			InterceptorStatusToken token = super.beforeInvocation(fi);

			try {
				// 通过上一步的安全检查,请求继续放行  
				fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
			}
			finally {
				super.finallyInvocation(token);
			}

			super.afterInvocation(token, null);
		}
	}
...

MethodSecurityInterceptor :

...
public Object invoke(MethodInvocation mi) throws Throwable {
		// 这里将传递进来的MethodInvocation对象,进行必要的认证和授权检查,具体实现也在父类AbstractSecurityInterceptor中
		InterceptorStatusToken token = super.beforeInvocation(mi);

		Object result;
		try {
			// 通过了上一步的安全检查则放行方法调用
			result = mi.proceed();
		}
		finally {
			super.finallyInvocation(token);
		}
		return super.afterInvocation(token, result);
	}
...

AbstractSecurityInterceptor:

...

protected InterceptorStatusToken beforeInvocation(Object object) {
		Assert.notNull(object, "Object was null");
		final boolean debug = logger.isDebugEnabled();

		// 类型校验
		if (!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: "
							+ getSecureObjectClass());
		}

		// 从安全配置中获取安全元数据,记录在 attributes中
		Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource()
				.getAttributes(object);

		if (attributes == null || attributes.isEmpty()) {
		// attributes 为空,说明该对象没有配置安全控制,可以公开访问
			if (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'");
			}

			if (debug) {
				logger.debug("Public object - authentication not attempted");
			}

			publishEvent(new PublicInvocationEvent(object));
			// 该资源没有设置安全,并且系统允许了公开访问,则返回 null,即不做安全检查
			return null; // no further work post-invocation
		}

		if (debug) {
			logger.debug("Secure object: " + object + "; Attributes: " + attributes);
		}

		if (SecurityContextHolder.getContext().getAuthentication() == null) {
			credentialsNotFound(messages.getMessage(
					"AbstractSecurityInterceptor.authenticationNotFound",
					"An Authentication object was not found in the SecurityContext"),
					object, attributes);
		}

		// 检查是否需要认证,如果需要,则执行认证并更行
		Authentication authenticated = authenticateIfRequired();

		// Attempt authorization
		try {
			// 用户通过了认证,基于当前用户信息,和目标对象的安全属性配置,进行相应的权限检查
			this.accessDecisionManager.decide(authenticated, object, attributes);
		}
		catch (AccessDeniedException accessDeniedException) {
		// 权限检查不通过则抛出AccessDeniedException异常
			publishEvent(new AuthorizationFailureEvent(object, attributes, authenticated,
					accessDeniedException));

			throw accessDeniedException;
		}

		if (debug) {
			logger.debug("Authorization successful");
		}

		if (publishAuthorizationSuccess) {
			publishEvent(new AuthorizedEvent(object, attributes, authenticated));
		}

		// Attempt to run as a different user
		Authentication runAs = this.runAsManager.buildRunAs(authenticated, object,
				attributes);

		if (runAs == null) {
			if (debug) {
				logger.debug("RunAsManager did not change Authentication object");
			}

			// no further work post-invocation
			// 注意这里第二个参数为 false, 表示请求处理完之后再次回到该filter时不需要在刷新安全认证token 
			return new InterceptorStatusToken(SecurityContextHolder.getContext(), false,
					attributes, object);
		}
		else {
			if (debug) {
				logger.debug("Switching to RunAs Authentication: " + runAs);
			}

			
			// 修改保存在SecurityContext中的Authentication
			SecurityContext origCtx = SecurityContextHolder.getContext();
			SecurityContextHolder.setContext(SecurityContextHolder.createEmptyContext());
			SecurityContextHolder.getContext().setAuthentication(runAs);

			// need to revert to token.Authenticated post-invocation
			 // 注意这里第二个参数为 true, 表示请求处理完之后再次回到该filter时需要在刷新安全认证token :
          // 恢复到 run-as 之前的安全认证token
			return new InterceptorStatusToken(origCtx, true, attributes, object);
		}
	}
...


private Authentication authenticateIfRequired() {
		Authentication authentication = SecurityContextHolder.getContext()
				.getAuthentication();

		// 判断身份认证是否完成或者是否需要每次重新认证
		if (authentication.isAuthenticated() && !alwaysReauthenticate) {
			if (logger.isDebugEnabled()) {
				logger.debug("Previously Authenticated: " + authentication);
			}

			return authentication;
		}

		// 身份认证
		authentication = authenticationManager.authenticate(authentication);

		// We don't authenticated.setAuthentication(true), because each provider should do
		// that
		if (logger.isDebugEnabled()) {
			logger.debug("Successfully Authenticated: " + authentication);
		}

		SecurityContextHolder.getContext().setAuthentication(authentication);

		return authentication;
	}

/**
	 * Cleans up the work of the AbstractSecurityInterceptor after the secure
	 * object invocation has been completed. This method should be invoked after the
	 * secure object invocation and before afterInvocation regardless of the secure object
	 * invocation returning successfully (i.e. it should be done in a finally block).
	 *
	 * @param token as returned by the {@link #beforeInvocation(Object)} method
	 */
	 //请求完毕后进行清理
	protected void finallyInvocation(InterceptorStatusToken token) {
		if (token != null && token.isContextHolderRefreshRequired()) {
			if (logger.isDebugEnabled()) {
				logger.debug("Reverting to original Authentication: "
						+ token.getSecurityContext().getAuthentication());
			}

			SecurityContextHolder.setContext(token.getSecurityContext());
		}
	}

	/**
	 * Completes the work of the AbstractSecurityInterceptor after the secure
	 * object invocation has been completed.
	 *
	 * @param token as returned by the {@link #beforeInvocation(Object)} method
	 * @param returnedObject any object returned from the secure object invocation (may be
	 * null)
	 * @return the object the secure object invocation should ultimately return to its
	 * caller (may be null)
	 */
	 // 返回值进行修改
	protected Object afterInvocation(InterceptorStatusToken token, Object returnedObject) {
		if (token == null) {
			// public object
			return returnedObject;
		}
		// 依旧需要清理
		finallyInvocation(token); // continue to clean in this method for passivity

		if (afterInvocationManager != null) {
			// Attempt after invocation handling
			try {
				returnedObject = afterInvocationManager.decide(token.getSecurityContext()
						.getAuthentication(), token.getSecureObject(), token
						.getAttributes(), returnedObject);
			}
			catch (AccessDeniedException accessDeniedException) {
				AuthorizationFailureEvent event = new AuthorizationFailureEvent(
						token.getSecureObject(), token.getAttributes(), token
								.getSecurityContext().getAuthentication(),
						accessDeniedException);
				publishEvent(event);

				throw accessDeniedException;
			}
		}

		return returnedObject;
	}

这就是认证与授权的大致过程,后面的文章将继续分析部分细节。

你可能感兴趣的:(spring,security,java,spring,spring,java)