22. Anonymous Authentication

22.1 Overview

通常,采用“默认情况下拒绝”的做法被认为是一种良好的安全做法,您可以在其中明确指定允许的内容并禁止其他所有内容。定义未经身份验证的用户可以访问的内容的情况与此类似,尤其是对于 Web 应用程序。许多站点要求用户必须通过身份验证才能使用少数几个 URL(例如,主页和登录页面)。在这种情况下,最简单的是为这些特定的 URL 定义访问配置属性,而不是为每个受保护的资源定义访问配置属性。换句话说,有时最好说ROLE_SOMETHING是默认值,并且只允许该规则的某些 exception,例如登录,注销和应用程序的主页。您也可以从过滤器链中完全省略这些页面,从而绕过访问控制检查,但是由于其他原因,这可能是不希望的,尤其是对于经过身份验证的用户而言,这些页面的行为有所不同时。

这就是我们所说的匿名身份验证。请注意,“匿名身份验证”的用户和未经身份验证的用户之间没有 true 的概念差异。 Spring Security 的匿名身份验证只是为您提供了一种更便捷的方式来配置访问控制属性。例如,即使SecurityContextHolder中实际上存在一个匿名身份验证对象,对 Servlet API 调用的调用(例如getCallerPrincipal)仍将返回 null。

在其他情况下,匿名身份验证很有用,例如当审核拦截器查询SecurityContextHolder以确定哪个主体负责给定操作时。如果类知道SecurityContextHolder始终包含Authentication对象,而从不包含null,则可以更强大地编写类。

22.2 Configuration

使用 HTTP 配置 Spring Security 3.0 时会自动提供匿名身份验证支持,并且可以使用<anonymous>元素进行自定义(或禁用)匿名身份验证。除非您使用传统的 Bean 配置,否则无需配置此处描述的 Bean。

三个类共同提供了匿名身份验证功能。 AnonymousAuthenticationTokenAuthentication的实现,并存储适用于匿名主体的GrantedAuthority。有一个对应的AnonymousAuthenticationProvider,它链接到ProviderManager,因此AnonymousAuthenticationToken被接受。最后,有一个AnonymousAuthenticationFilter,它在常规身份验证机制之后被链接,如果那里没有现有的Authentication,则会自动将AnonymousAuthenticationToken添加到SecurityContextHolder。筛选器和身份验证提供程序的定义如下所示:

<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,因此前者[18]接受前者创建的令牌。 userAttributeusernameInTheAuthenticationToken,grantedAuthority[,grantedAuthority]的形式表示。这与InMemoryDaoImpluserMap属性的等号之后使用的语法相同。

如前所述,匿名身份验证的好处是所有 URI 模式都可以应用安全性。例如:

<bean id="filterSecurityInterceptor"
	class="org.springframework.security.web.access.intercept.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>

22.3 AuthenticationTrustResolver

AuthenticationTrustResolver接口及其相应的AuthenticationTrustResolverImpl实现完善了匿名身份验证讨论。此接口提供isAnonymous(Authentication)方法,该方法允许感兴趣的类将这种特殊类型的身份验证状态考虑在内。 ExceptionTranslationFilter在处理AccessDeniedException时使用此接口。如果抛出AccessDeniedException,并且身份验证是匿名类型,则代替引发 403(禁止)响应,过滤器将开始AuthenticationEntryPoint,以便委托人可以正确地进行身份验证。这是必要的区别,否则主体将始终被视为“已认证”,并且永远不会获得通过表单,基本,摘要或某些其他常规认证机制进行登录的机会。

您通常会在上述拦截器配置中看到ROLE_ANONYMOUS属性被IS_AUTHENTICATED_ANONYMOUSLY替换,这在定义访问控制时实际上是相同的。这是AuthenticatedVoter用法的示例,我们将在authorization chapter中看到。它使用AuthenticationTrustResolver处理此特定的配置属性,并将访问权限授予匿名用户。 AuthenticatedVoter方法更强大,因为它使您能够区分匿名用户,记住我的用户和经过完全认证的用户。如果您不需要此功能,则可以坚持使用ROLE_ANONYMOUS,它将由 Spring Security 的标准RoleVoter处理。


[18]使用key属性不应视为在此提供任何实际的安全性。这只是一个簿记练习。如果在可能进行身份验证的 Client 端构造Authentication对象(例如使用 RMI 调用)的情况下共享ProviderManager(其中包含AnonymousAuthenticationProvider),则恶意 Client 端可以提交自己创建的AnonymousAuthenticationToken(选择用户名和权限列表)。如果key是可猜测的或可以找到,则令牌将被匿名提供者接受。正常使用情况下这不是问题,但是如果您使用的是 RMI,则最好使用自定义的ProviderManager,它会省略匿名提供程序,而不是共享用于 HTTP 身份验证机制的提供程序。