Spring Security 授权

1. 什么是授权

Spring Security 是为web提供解决方案的安全框架,每一个安全框架都主要做两件事,认证和授权,在之前的章节中,已经给大家介绍了认证,今天主要是介绍授权;其实授权就是在认证之后,检验用户是否具有访问某一资源的权限;简单的说:认证就是你能干些什么。

2.Spring Security授权原理

AccessDecisionManager
当用户访问我们的资源,最后会交给叫 FilterSecurityInterceptor 的过滤器判断是否有访问的权限;下面是该过滤器的核心代码

protected InterceptorStatusToken beforeInvocation(Object object) {
    
        // 获取访问URL所需权限
        Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource()
                .getAttributes(object);

    
        Authentication authenticated = authenticateIfRequired();

        // 通过accessDecisionManager鉴权
        try {
            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);
        }
    }

最后通过AccessDecisionManager 接口的 decide()方法用于决定authentication是否符合受保护对象要求的configAttributes ;AccessDecisionManager接口有三个实现类,每个实现类都维护着一组 AccessDecisionVoter ,它们之间采用投票机制;下面分别讲三个实现类:
AffirmativeBased: 一组AccessDecisionVoter 只要有一个投通过票,那么就通过。
ConsensusBased:在 一组AccessDecisionVoter中会比较通过票,和未通过票数,如果通过票数大于未通过票数则通过。
UnanimousBased:一组AccessDecisionVoter 只要有一个投未通过票,那么就未通过。

3.自定义授权

为了创建自己的授权管理器,我们可以通过集成AbstractAccessDecisionManager

public class MyAccessDecisionManager extends AbstractAccessDecisionManager {
	
	public void decide( Authentication authentication, Object object, 
			Collection<ConfigAttribute> configAttributes) 
		throws AccessDeniedException, InsufficientAuthenticationException{
		
		User user = (User)authentication.getPrincipal();
		logger.info("访问资源的用户为"+user.getUsername());
		
		//如果访问资源不需要任何权限则直接通过
		if( configAttributes == null ) {
			return ;
		}
		
		Iterator<ConfigAttribute> ite = configAttributes.iterator();
		//遍历configAttributes看用户是否有访问资源的权限
		while( ite.hasNext()){
			
			ConfigAttribute ca = ite.next();
			String needRole = ((SecurityConfig)ca).getAttribute();
			
			//ga 为用户所被赋予的权限。 needRole 为访问相应的资源应该具有的权限。
			for( GrantedAuthority ga: authentication.getAuthorities()){
				
				if(needRole.trim().equals(ga.getAuthority().trim())){
 
					return;
				}
				
			}
			
		}
		
		throw new AccessDeniedException("");
		
	}

由于AccessDecisionManager最终是被FilterSecurityInterceptor所调用,所以需要有我们自己的FilterSecurityInterceptor。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值