Spring Security API: AbstractSecurityInterceptor

AbstractSecurityInterceptor

Declared

package org.springframework.security.access.intercept;
public abstract class AbstractSecurityInterceptor 
implements InitializingBean,ApplicationEventPublisherAware, MessageSourceAware 

Class Jdoc

实现安全对象的安全拦截的抽象类。

AbstractSecurityInterceptor将确保安全拦截器能正确启动配置。它还将实现对安全对象调用的正确处理,即:

  1. 从SecurityContextHolder获取Authentication对象。
  2. 通过在SecurityMetadataSource中查找安全对象请求来确定请求是否与安全调用或公共调用相关。
  3. 对于安全的调用(有一个关于安全对象调用ConfigAttributes列表):
    1. 如果Authentication.isAuthenticated()返回false,或者alwaysReauthenticate属性是true,则通过配置的AuthenticationManager实现对请求做身份认证。通过身份认证时,将SecurityContextHolder中的Authentication对象替换为返回的值。
    2. 鉴权依赖于配置的AccessDecisionManager。
    3. 通过配置的RunAsManager执行任何run-as替换。
    4. 将控制权传递回具体的子类,该子类将实际继续执行对象。将返回一个InterceptorStatusToken,以便在子类完成对象的执行之后,它的finally子句可以确保重新调用AbstractSecurityInterceptor并使用finallyInvocation(InterceptorStatusToken)正确地清理。
    5. 具体子类将通过afterInvocation(InterceptorStatusToken, Object) 从新调用AbstractSecurityInterceptor。
    6. 如果RunAsManager替换了Authentication对象,则在调用AuthenticationManager后返回存在于SecurityContextHolder中的对象。
    7. 如果定义了AfterInvocationManager,则调用InvocationManager并允许它替换要返回给调用方的对象。
  4. 对于公共调用(没有ConfigAttributes的安全对象调用):
    1. 如上所述,在安全对象被处理后,返回InterceptorStatusToken,然后重新提交给AbstractSecurityInterceptor。当afterInvocation(InterceptorStatusToken, Object)被调用时,AbstractSecurityInterceptor不会做任何事情。
  5. 控制权被再次返给具体的子类,随对象一起返回给调用方,然后,子类将该结果或异常返回给原始调用方。

beforeInvocation

Declared

protected InterceptorStatusToken beforeInvocation(Object object)

Method Code

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());
    }

    // 在SecurityMetadataSource中查找权限配置。
    Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource()
            .getAttributes(object);
            
    // 如果没有查到权限配置信息,表示当前请求的链接为公共调用
    if (attributes == null || attributes.isEmpty()) {
        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));

        return null; // no further work post-invocation
    }

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

    // 判断SecurityContext中有无Authentication对象,即是否已经有经过认证的账户信息(匿名访问会生成匿名访问账户)
    if (SecurityContextHolder.getContext().getAuthentication() == null) {
        credentialsNotFound(messages.getMessage(
                "AbstractSecurityInterceptor.authenticationNotFound",
                "An Authentication object was not found in the SecurityContext"),
                object, attributes);
    }

    // 如果Authentication.isauthenticated()返回false或属性alwaysReauthenticate已设置为true,则检查当前身份验证令牌并将其传递给AuthenticationManager。
    Authentication authenticated = authenticateIfRequired();

    // Attempt authorization
    // 尝试鉴权
    try {
        // 通过AccessDecisionManager鉴权
        this.accessDecisionManager.decide(authenticated, object, attributes);
    }
    catch (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
        // 无需替换,不做任何后续动作
        return new InterceptorStatusToken(SecurityContextHolder.getContext(), false,
                attributes, object);
    }
    else {
        if (debug) {
            logger.debug("Switching to RunAs Authentication: " + runAs);
        }
        
        // 替换为另一个用户
        SecurityContext origCtx = SecurityContextHolder.getContext();
        SecurityContextHolder.setContext(SecurityContextHolder.createEmptyContext());
        SecurityContextHolder.getContext().setAuthentication(runAs);

        // need to revert to token.Authenticated post-invocation
        return new InterceptorStatusToken(origCtx, true, attributes, object);
    }
}

finallyInvocation

Declared

protected void finallyInvocation(InterceptorStatusToken token)

Method Jdoc

安全对象调用完成后,清理AbstractSecurityInterceptor的工作。无论安全对象调用是否成功返回(即它应该在finally块中完成),都应该在安全对象调用之后和调用后调用之前调用此方法。

Method Code

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());
    }
}

afterInvocation

Declared

protected Object afterInvocation(InterceptorStatusToken token, Object returnedObject)

Method Jdoc

完成安全对象调用之后,完成AbstractSecurityInterceptor的工作。

Method Code

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;
}

getSecureObjectClass

Declared

public abstract Class<?> getSecureObjectClass();

Method Jdoc

指示子类将呈现给抽象父类以进行处理的安全对象的类型。这用于确保连接到AbstractSecurityInterceptor的协作者都支持指定的安全对象类。

authenticateIfRequired

Declared

private Authentication authenticateIfRequired() 

Method Jdoc

如果Authentication.isauthenticated()返回false或属性alwaysReauthenticate已设置为true,则检查当前身份验证令牌并将其传递给AuthenticationManager。

Method Code

private Authentication authenticateIfRequired() {
    // 从SecurityContext中取得Authentication对象
    Authentication authentication = SecurityContextHolder.getContext()
            .getAuthentication();
    // 如果Authentication.isauthenticated()返回true且属性alwaysReauthenticate已设置为false,则直接返回SecurityContext中的Authentication对象
    if (authentication.isAuthenticated() && !alwaysReauthenticate) {
        if (logger.isDebugEnabled()) {
            logger.debug("Previously Authenticated: " + authentication);
        }

        return authentication;
    }

    // 通过配置的AuthenticationManager实现对请求做身份认证。
    authentication = authenticationManager.authenticate(authentication);

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

    // 将经过认证的Authentication写回SecurityContext
    SecurityContextHolder.getContext().setAuthentication(authentication);

    return authentication;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值