匿名认证

12.1. 概述

通常考虑的一个好的安全事件是采取“deny-by-default”(默认拒绝所有请求的方式) 这种情况下,你可以明确指定允许哪些,然后拒绝其他所有操作。 定义未认证用户可以做些什么,也是一种简单情况,特别是对于web应用。 多数网站要求用户必须通过一些途径进行认证,不仅仅是一些URL(比如,首页和登陆页面)。 在这种情况下,更简单的定义访问配置属性,为这些特殊的URL,而不是把每个资源都当做被保护的资源。 不同的是,有时它最好被成为ROLE_SOMETHING,默认是这样要求的, 对于这种规定,只有几个例外,比如,登陆,注销,应用的首页。 你也可以从过滤器链中完全忽略他们,这样就可以通过安全控制的检测, 但是,对于其他原因这些不好的,特别是,这些页面的行为与已认证用户不同。

这就是为什么我们使用匿名认证的原因,注意这里没有一个真正的理论来区分 “匿名认证”的用户和未认证用户。spring security匿名认证只是给你一个 更方便的方式来配置你的权限控制属性,调用servlet API,比如getCallerPrincipal 比如,也会返回null,即使这里已经有一个匿名认证对象在SecurityContextHolder里的。

这里有一些其他匿名认证发挥作用的请抗,比如当一个审计拦截器查询 SecurityContextHolder来验证哪些主体用来处理给定的操作。 类可以更好的工作,如果它们知道SecurityContextHolder 里总是包含一个Authentication对象, 永远不会是null。

12.2. 配置

当使用spring security 3.0的HTTP配置时,就自动提供了对匿名认证的支持。 可以使用<anonymous>元素进行自定义(或禁用)。 你不需要在这里配置bean,除非使用了以前的bean配置方式。

Spring Security提供三个类来一起提供匿名认证功能。 AnonymousAuthenticationToken实现了Authentication,保存着GrantedAuthority[],用来处理匿名主体。 有一个对应的需要链入ProviderManagerAnonymousAuthenticationProvider,可以从中获得AnonymousAuthenticationTokens。 最后是AnonymousAuthenticationFilter,需要串链到普通认证机制后面,如果还没有存在的Authentication的话,它会自动向SecurityContextHolder添加一个AnonymousAuthenticationToken。 过滤器和认证提供器的配置如下:


<bean id="anonymousAuthFilter"
    class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter">
  <property name="key" value="foobar"/>
  <property name="userAttribute" value="anonymousUser,ROLE_ANONYMOUS"/>
</bean>

<bean id="anonymousAuthenticationProvider"
    class="org.springframework.security.authentication.AnonymousAuthenticationProvider">
  <property name="key" value="foobar"/>
</bean>
    

这个 key 会在过滤器和认证提供器之间共享, 这样创建的标记可以在以后用到。[12] userAttribute表达式的格式是usernameInTheAuthenticationToken,grantedAuthority[,grantedAuthority]。 这和InMemoryDaoImpluserMap属性的语法一样。

如上面所讲的,匿名认证的好处是,可以对所有的URL模式都进行安全配置。 比如:


<bean id="filterSecurityInterceptor"
    class="org.springframework.security.intercept.web.access.FilterSecurityInterceptor">
  <property name="authenticationManager" ref="authenticationManager"/>
  <property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/>
  <property name="securityMetadata">
    <security:filter-security-metadata-source>
      <security:intercept-url pattern='/index.jsp' access='ROLE_ANONYMOUS,ROLE_USER'/>
      <security:intercept-url pattern='/hello.htm' access='ROLE_ANONYMOUS,ROLE_USER'/>
      <security:intercept-url pattern='/logoff.jsp' access='ROLE_ANONYMOUS,ROLE_USER'/>
      <security:intercept-url pattern='/login.jsp' access='ROLE_ANONYMOUS,ROLE_USER'/>
      <security:intercept-url pattern='/**' access='ROLE_USER'/>
    </security:filter-security-metadata-source>
  </property>
</bean>
    

12.3. AuthenticationTrustResolver

简略对匿名认证的讨论,就是AuthenticationTrustResolver接口,它对应着AuthenticationTrustResolverImpl实现。 这个接口提供了一个isAnonymous(Authentication)方法,允许感兴趣的类评估认证的特殊状态类型。 在处理AccessDeniedException异常的时候,ExceptionTranslationFilter使用这个接口。 如果抛出了一个AccessDeniedException异常,而且认证是匿名类型,那么不会抛出403(禁止)响应,这个过滤器会展开AuthenticationEntryPoint,这样主体可以正确验证。 这是一个必要的区别,否则主体会一直被认为“需要“认证””,没有机会通过表单,摘要,或其他普通的认证机制登录。

你会经常看到ROLE_ANONYMOUS属性,在上面的拦截器配置中, 被替换成IS_AUTHENTICATED_ANONYMOUSLY, 这在定义权限控制时是完全相同的。 这时一个使用AuthenticatedVoter的例子,可以参考验证章节。 它使用一个AuthenticationTrustResolver 来处理这个特殊的配置属性,并给匿名用户授权。 AuthenticatedVoter的方式更强大,因为它允许你区别 匿名,rememberMe和完全认证用户。如果你不需要这些功能,你可以直接使用 ROLE_ANONYMOUS,这会被Spring Security的标准 RoleVoter处理。



[12] key参数应该没有提供任何真实的安全。 它仅仅用来做一个标志。如果你共享了一个ProviderManager 包含了一个AnonymousAuthenticationProvider,在一个场景中。 可能对于一个认证客户端,创建Authentication对象 (比如通过RMI调用),然后一个恶意的可能提交一个 AnonymousAuthenticationToken,它会创建自己 (选择用户名和权限队列)。如果key可以被猜出来,或可以被找到, 这个token就可能被匿名提供者获得。这不是一个通常使用中的问题,但是如果你使用RMI, 你最好使用一个自定义的ProviderManager,这可以避免匿名供应器 共享你使用的HTTP验证机制。