对于最新的稳定版本,请使用 Spring Security 6.3.1Spring中文文档

对于最新的稳定版本,请使用 Spring Security 6.3.1Spring中文文档

概述

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

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

在其他情况下,匿名身份验证很有用,例如,当审核拦截器查询以确定哪个主体负责给定操作时。 如果类知道 总是包含对象,而从不包含对象,则可以更可靠地创作类。SecurityContextHolderSecurityContextHolderAuthenticationnullSpring中文文档

配置

当您使用 HTTP 配置(在 Spring Security 3.0 中引入)时,会自动提供匿名身份验证支持。 您可以使用该元素自定义(或禁用)它。 除非您使用的是传统的 Bean 配置,否则您不需要配置此处描述的 Bean。<anonymous>Spring中文文档

三个类协同工作以提供匿名身份验证功能。 是适用于匿名主体的实例的实现,并存储实例。 有一个对应的 ,它被链接到 以便接受实例。 最后,an 在正常身份验证机制之后被链接,如果没有现有的身份验证机制,则自动将 an 添加到 an。 筛选器和身份验证提供程序定义如下:AnonymousAuthenticationTokenAuthenticationGrantedAuthorityAnonymousAuthenticationProviderProviderManagerAnonymousAuthenticationTokenAnonymousAuthenticationFilterAnonymousAuthenticationTokenSecurityContextHolderAuthenticationSpring中文文档

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

在筛选器和身份验证提供程序之间共享,以便前者创建的令牌被后者接受keySpring中文文档

在这里,使用该财产不应被视为提供任何真正的安全保障。 这只是一种簿记活动。 如果在身份验证客户端可以构造对象(例如使用 RMI 调用)的情况下共享包含 的对象,则恶意客户端可以提交它自己创建的对象(使用所选的用户名和权限列表)。 如果该令牌是可猜测的或可以被发现的,则该令牌将被匿名提供者接受。 这在正常使用中不是问题。但是,如果使用 RMI,则应使用省略匿名提供程序的自定义提供程序,而不是共享用于 HTTP 身份验证机制的提供程序。keyProviderManagerAnonymousAuthenticationProviderAuthenticationAnonymousAuthenticationTokenkeyProviderManagerSpring中文文档

以 的形式表示。 在 的属性的等号之后使用相同的语法。userAttributeusernameInTheAuthenticationToken,grantedAuthority[,grantedAuthority]userMapInMemoryDaoImplSpring中文文档

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

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

在这里,使用该财产不应被视为提供任何真正的安全保障。 这只是一种簿记活动。 如果在身份验证客户端可以构造对象(例如使用 RMI 调用)的情况下共享包含 的对象,则恶意客户端可以提交它自己创建的对象(使用所选的用户名和权限列表)。 如果该令牌是可猜测的或可以被发现的,则该令牌将被匿名提供者接受。 这在正常使用中不是问题。但是,如果使用 RMI,则应使用省略匿名提供程序的自定义提供程序,而不是共享用于 HTTP 身份验证机制的提供程序。keyProviderManagerAnonymousAuthenticationProviderAuthenticationAnonymousAuthenticationTokenkeyProviderManagerSpring中文文档

身份验证TrustResolver

对匿名身份验证的讨论是接口及其相应的实现。 此接口提供了一种方法,该方法允许感兴趣的类考虑这种特殊类型的身份验证状态。 在处理实例中使用此接口。 如果抛出 an 并且身份验证是匿名类型,则筛选器不会抛出 403(禁止)响应,而是启动 ,以便主体可以正确进行身份验证。 这是一个必要的区别。否则,主体将始终被视为“已通过身份验证”,并且永远不会有机会通过表单、基本、摘要或其他一些正常身份验证机制登录。AuthenticationTrustResolverAuthenticationTrustResolverImplisAnonymous(Authentication)ExceptionTranslationFilterAccessDeniedExceptionAccessDeniedExceptionAuthenticationEntryPointSpring中文文档

我们经常看到早期拦截器配置中的属性被替换为 ,这在定义访问控制时实际上是一回事。 这是 的使用示例,我们在授权一章中进行了介绍。 它使用 an 来处理此特定配置属性并向匿名用户授予访问权限。 这种方法更强大,因为它可以让你区分匿名用户、记住用户和完全经过身份验证的用户。 但是,如果您不需要此功能,则可以坚持使用 ,该功能由 Spring Security 的标准处理。ROLE_ANONYMOUSIS_AUTHENTICATED_ANONYMOUSLYAuthenticatedVoterAuthenticationTrustResolverAuthenticatedVoterROLE_ANONYMOUSRoleVoterSpring中文文档

使用 Spring MVC 获取匿名身份验证

Spring MVC 使用自己的参数解析器解析 Principal 类型的参数Spring中文文档

这意味着像这样的构造:Spring中文文档

@GetMapping("/")
public String method(Authentication authentication) {
	if (authentication instanceof AnonymousAuthenticationToken) {
		return "anonymous";
	} else {
		return "not anonymous";
	}
}
@GetMapping("/")
fun method(authentication: Authentication?): String {
    return if (authentication is AnonymousAuthenticationToken) {
        "anonymous"
    } else {
        "not anonymous"
    }
}

将始终返回“非匿名”,即使对于匿名请求也是如此。 原因是 Spring MVC 使用 解析参数,即当请求是匿名的时。HttpServletRequest#getPrincipalnullSpring中文文档

如果要获取匿名请求,请改用:Authentication@CurrentSecurityContextSpring中文文档

将 CurrentSecurityContext 用于匿名请求
@GetMapping("/")
public String method(@CurrentSecurityContext SecurityContext context) {
	return context.getAuthentication().getName();
}
@GetMapping("/")
fun method(@CurrentSecurityContext context : SecurityContext) : String =
		context!!.authentication!!.name