启舰分享Spring Security

spring security 核心 --authorizati

2018-07-23  本文已影响20人  _白小飞

所有的Authentication实现存储的列表GrantedAuthority对象.这些代表已被授予主要的的当局. GrantedAuthority对象是由authenticationManager 插入到Authentication 对象,然后读取 AccessDecisionManager做出判断.

也就是说是由,投保器进行投票,投完票之后,由决策器进行决策。(投票方案可以是一票通过,一票否决等等)。

GrantedAuthority是一个只有一个方法的接口

String getAuthority();
这个方法允许AccessDecisionManager 来判断得到一个精确的String表示的GrantedAuthority .通过返回一个表示作为一个String,一个GrantedAuthority 可以很容易的通过AccessDecisionManager 来read,如果一个GrantedAuthority 不能精确地表示为一个String,GrantedAuthority 将会被认为是"complex"和getAuthority() 必须返回为null.

"complex" GrantedAuthority的一个将一个应用于不同客户帐户号码的操作和权限阈值的列表的实现例子.代表这个复杂的GrantedAuthority 作为String将是相当困难的,作为一个结果,getauthority() 方法应该返回null.这将对任何accessDecisionManager 表明它需要明确的支持 GrantedAuthority实施以了解其内容.

Spring Security包括一个具体的GrantedAuthority 实施, grantedauthorityimpl .这允许用户指定的任何String转换成一种 GrantedAuthority .所有的 AuthenticationProvider 的包括与安全架构使用 grantedauthorityimpl`填充Authentication对象.

访问决策管理器

accessDecisionManager 被 abstractsecurityinterceptor 和负责制定最终的访问控制决策.AccessDecisionManager接口包含三种方法:

void decide(Authentication authentication, Object secureObject,
Collection<ConfigAttribute> attrs) throws AccessDeniedException;

boolean supports(ConfigAttribute attribute);

boolean supports(Class clazz);
AccessDecisionManager的decide方法传递了它所需要的所有相关信息,以作出授权决策.尤其,通过安全的“对象”,使这些参数包含在实际的安全对象调用中进行检查.例如,让我们假设安全对象是一个MethodInvocation 资料,这将是很容易实现MethodInvocation对于任何Customer论点.然后执行某种安全逻辑判断、来确保AccessDecisionManager 主允许对客户操作.如果访问被拒绝并抛出AccessDeniedException 我们的预期就实现了.

如果accessDecisionManager 可以处理通过 configattribute ,supports(ConfigAttribute)方法由AbstractSecurityInterceptor 在决定启动时候命名. supports(Class) 方法被安全拦截器实现,确保配置accessDecisionManager支持类型的安全对象的被拦截.

public interface AccessDecisionManager {
 
 
 
    /**
     * 通过传递的参数来决定用户是否有访问对应受保护对象的权限
     *
     * @param authentication 当前正在请求受包含对象的Authentication
     * @param object 受保护对象,其可以是一个MethodInvocation、JoinPoint或FilterInvocation。
     * @param configAttributes 与正在请求的受保护对象相关联的配置属性
     *
     */
 
    void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
 
        throws AccessDeniedException, InsufficientAuthenticationException;
 
 
 
    /**
     * 表示当前AccessDecisionManager是否支持对应的ConfigAttribute
 */
 
    boolean supports(ConfigAttribute attribute);
 
 
 
    /**
     * 表示当前AccessDecisionManager是否支持对应的受保护对象类型
     */
 
    boolean supports(Class<?> clazz);
 

decide()方法用于决定authentication是否符合受保护对象要求的configAttributes。supports(ConfigAttribute attribute)方法是用来判断AccessDecisionManager是否能够处理对应的ConfigAttribute的。supports(Class<?> clazz)方法用于判断配置的AccessDecisionManager是否支持对应的受保护对象类型。

2)投票系统
Spring Security已经内置了几个基于投票的AccessDecisionManager,当然如果需要你也可以实现自己的AccessDecisionManager。以下是Spring Security官方文档提供的一个图,其展示了与基于投票的AccessDecisionManager实现相关的类。还有比较重要的WebExpressionVoter

b7963b90-3877-3885-84f9-6d0054cb5eec.png

使用这种方式,一系列的AccessDecisionVoter将会被AccessDecisionManager用来对Authentication是否有权访问受保护对象进行投票,然后再根据投票结果来决定是否要抛出AccessDeniedException。AccessDecisionVoter是一个接口,其中定义有三个方法,具体结构如下所示。

public interface AccessDecisionVoter<S> {
 
 
 
    intACCESS_GRANTED = 1;
 
    intACCESS_ABSTAIN = 0;
 
    intACCESS_DENIED = -1;
 
 
 
    boolean supports(ConfigAttribute attribute);
 
 
 
    boolean supports(Class<?> clazz);
 
 
 
    int vote(Authentication authentication, S object, Collection<ConfigAttribute> attributes);
 
}

vote()方法的返回结果会是AccessDecisionVoter中定义的三个常量之一。ACCESS_GRANTED表示同意,ACCESS_DENIED表示拒绝,ACCESS_ABSTAIN表示弃权。如果一个AccessDecisionVoter不能判定当前Authentication是否拥有访问对应受保护对象的权限,则其vote()方法的返回值应当为弃权ACCESS_ABSTAIN。

   Spring Security内置了三个基于投票的AccessDecisionManager实现类,它们分别是AffirmativeBased、ConsensusBased和UnanimousBased。

   AffirmativeBased的逻辑是这样的:

   (1)只要有AccessDecisionVoter的投票为ACCESS_GRANTED则同意用户进行访问;

   (2)如果全部弃权也表示通过;

   (3)如果没有一个人投赞成票,但是有人投反对票,则将抛出AccessDeniedException。

   ConsensusBased的逻辑是这样的:

   (1)如果赞成票多于反对票则表示通过。

   (2)反过来,如果反对票多于赞成票则将抛出AccessDeniedException。

   (3)如果赞成票与反对票相同且不等于0,并且属性allowIfEqualGrantedDeniedDecisions的值为true,则表示通过,否则将抛出异常AccessDeniedException。参数allowIfEqualGrantedDeniedDecisions的值默认为true。

   (4)如果所有的AccessDecisionVoter都弃权了,则将视参数allowIfAllAbstainDecisions的值而定,如果该值为true则表示通过,否则将抛出异常AccessDeniedException。参数allowIfAllAbstainDecisions的值默认为false。

   UnanimousBased的逻辑与另外两种实现有点不一样,另外两种会一次性把受保护对象的配置属性全部传递给AccessDecisionVoter进行投票,而UnanimousBased会一次只传递一个ConfigAttribute给AccessDecisionVoter进行投票。这也就意味着如果我们的AccessDecisionVoter的逻辑是只要传递进来的ConfigAttribute中有一个能够匹配则投赞成票,但是放到UnanimousBased中其投票结果就不一定是赞成了。UnanimousBased的逻辑具体来说是这样的:

(1)如果受保护对象配置的某一个ConfigAttribute被任意的AccessDecisionVoter反对了,则将抛出AccessDeniedException。

   (2)如果没有反对票,但是有赞成票,则表示通过。

   (3)如果全部弃权了,则将视参数allowIfAllAbstainDecisions的值而定,true则通过,false则抛出AccessDeniedException。

投票者:

RoleVoter是Spring Security内置的一个AccessDecisionVoter,其会将ConfigAttribute简单的看作是一个角色名称,在投票的时如果拥有该角色即投赞成票。如果ConfigAttribute是以“ROLE_”开头的,则将使用RoleVoter进行投票。当用户拥有的权限中有一个或多个能匹配受保护对象配置的以“ROLE_”开头的ConfigAttribute时其将投赞成票;如果用户拥有的权限中没有一个能匹配受保护对象配置的以“ROLE_”开头的ConfigAttribute,则RoleVoter将投反对票;如果受保护对象配置的ConfigAttribute中没有以“ROLE_”开头的,则RoleVoter将弃权。

AuthenticatedVoter也是Spring Security内置的一个AccessDecisionVoter实现。其主要用来区分匿名用户、通过Remember-Me认证的用户和完全认证的用户。完全认证的用户是指由系统提供的登录入口进行成功登录认证的用户。

   AuthenticatedVoter可以处理的ConfigAttribute有IS_AUTHENTICATED_FULLY、IS_AUTHENTICATED_REMEMBERED和IS_AUTHENTICATED_ANONYMOUSLY。如果ConfigAttribute不在这三者范围之内,则AuthenticatedVoter将弃权。否则将视ConfigAttribute而定,如果ConfigAttribute为IS_AUTHENTICATED_ANONYMOUSLY,则不管用户是匿名的还是已经认证的都将投赞成票;如果是IS_AUTHENTICATED_REMEMBERED则仅当用户是由Remember-Me自动登录,或者是通过登录入口进行登录认证时才会投赞成票,否则将投反对票;而当ConfigAttribute为IS_AUTHENTICATED_FULLY时仅当用户是通过登录入口进行登录的才会投赞成票,否则将投反对票。

   AuthenticatedVoter是通过AuthenticationTrustResolver的isAnonymous()方法和isRememberMe()方法来判断SecurityContextHolder持有的Authentication是否为AnonymousAuthenticationToken或RememberMeAuthenticationToken的,即是否为IS_AUTHENTICATED_ANONYMOUSLY和IS_AUTHENTICATED_REMEMBERED。

授权的配置
常见的是使用表达式的配置
表达根对象的基类是securityexpressionroot.这提供了一些常见的表达式,可应用在网络和方法安全性.

Table 3. Common built-in expressions

表达 描述
hasRole([role]) 如果当前主体具有指定的角色,则返回true.默认情况下,如果提供的角色不从'ROLE_'这里提供,这将增加。这可以通过修改defaultroleprefix 在 defaultwebsecurityexpressionhandler配置.
hasAnyRole([role1,role2]) 如果当前的主体有任何提供的角色(给定的作为一个逗号分隔的字符串列表)的话,返回true,默认情况下,如果提供的角色不从 'ROLE_',这将增加。这可以通过修改defaultroleprefix 在 defaultwebsecurityexpressionhandler定制.
hasAuthority([authority]) 如果当前的主体具有指定的权限,则返回 true.
hasAnyAuthority([authority1,authority2]) 如果当前的主体有任何提供的角色(给定的作为一个逗号分隔的字符串列表)的话,返回true.
principal 允许直接访问表示当前用户的主对象
authentication 允许直接访问从SecurityContext得出当前的Authentication对象
permitAll 总是评估为true
denyAll 总是评估为false
isAnonymous() 如果当前的主体是一个匿名用户,则返回true.
isRememberMe() 如果当前的主体是一个匿名用户,则返回true
isAuthenticated() 如果用户不是匿名的,则返回 true
isFullyAuthenticated() 如果用户不是一个匿名的或是一个记住我的用户返回true
hasPermission(Object target, Object permission) 如果用户已访问给定权限的提供的目标,则返回true,例如hasPermission(domainObject, 'read')
hasPermission(Object targetId, String targetType, Object permission) 如果用户已访问给定权限的提供的目标,则返回true,例如hasPermission(1, 'com.example.domain.Message', 'read')

Web Security Expressions
使用表达式来保护个人网址,首先需要设置“use-expressions”属性的< http >为true.Spring Security预期的“访问”属性的< intercept-url >元素包含Spring EL表达式。一个布尔表达式应该评估,定义是否应该允许访问. 例如:

<http>
    <intercept-url pattern="/admin*"
        access="hasRole('admin') and hasIpAddress('192.168.1.0/24')"/>
    ...
</http>

在网络安全bean表达式
在Java配置

http
        .authorizeRequests()
                .antMatchers("/user/**").access("@webSecurity.check(authentication,request)")
                ...
上一篇下一篇

猜你喜欢

热点阅读