对于最新的稳定版本,请使用 Spring Security 6.3.1! |
对于最新的稳定版本,请使用 Spring Security 6.3.1! |
概述
通常认为采用“默认拒绝”是一种良好的安全做法,在这种方式中,您可以明确指定允许的内容并禁止其他所有内容。
定义未经身份验证的用户可访问的内容是类似的情况,尤其是对于 Web 应用程序。
许多网站要求必须对用户进行身份验证,而不是几个 URL(例如主页和登录页面)。
在这种情况下,最简单的方法是为这些特定 URL 定义访问配置属性,而不是为每个受保护的资源定义访问配置属性。
换句话说,有时最好说默认情况下是必需的,并且只允许此规则的某些例外,例如应用程序的登录、注销和主页。
您也可以从筛选器链中完全省略这些页面,从而绕过访问控制检查,但这可能是不可取的,因为其他原因,特别是如果页面对于经过身份验证的用户的行为不同。ROLE_SOMETHING
这就是我们所说的匿名身份验证。
请注意,“匿名身份验证”的用户和未经身份验证的用户之间没有真正的概念区别。
Spring Security 的匿名身份验证只是为您提供了一种更方便的方式来配置访问控制属性。
对 servlet API 的调用(例如,即使 中实际上存在匿名身份验证对象)仍将返回 null。getCallerPrincipal
SecurityContextHolder
在其他情况下,匿名身份验证很有用,例如,当审核拦截器查询以确定哪个主体负责给定操作时。
如果类知道 always 包含对象,并且从不包含对象,则可以更可靠地创作类。SecurityContextHolder
SecurityContextHolder
Authentication
null
配置
使用HTTP配置Spring Security 3.0时,会自动提供匿名身份验证支持,并且可以使用该元素进行自定义(或禁用)。
除非您使用的是传统的 Bean 配置,否则您不需要配置此处描述的 Bean。<anonymous>
三个类共同提供匿名身份验证功能。 是 的实现,并存储适用于匿名主体的 s。
有一个对应的 ,它被链接到 中,以便 s 被接受。
最后,有一个 ,它被链接在正常的身份验证机制之后,如果没有现有的 ,它会自动将 an 添加到 中。
筛选器和身份验证提供程序的定义如下所示:AnonymousAuthenticationToken
Authentication
GrantedAuthority
AnonymousAuthenticationProvider
ProviderManager
AnonymousAuthenticationToken
AnonymousAuthenticationFilter
AnonymousAuthenticationToken
SecurityContextHolder
Authentication
<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
[1].
以 的形式表示。
这与 的属性的等号后使用的语法相同。userAttribute
usernameInTheAuthenticationToken,grantedAuthority[,grantedAuthority]
userMap
InMemoryDaoImpl
如前所述,匿名身份验证的好处是所有 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>
身份验证TrustResolver
对匿名身份验证的讨论是接口及其相应的实现。
此接口提供了一种方法,该方法允许感兴趣的类考虑这种特殊类型的身份验证状态。
在处理 s 时使用此接口。
如果抛出 an,并且身份验证是匿名类型,则筛选器将启动 ,而不是抛出 403 (禁止) 响应,以便主体可以正确进行身份验证。
这是一个必要的区别,否则主体将始终被视为“经过身份验证”,并且永远不会有机会通过表单、基本、摘要或其他一些正常的身份验证机制登录。AuthenticationTrustResolver
AuthenticationTrustResolverImpl
isAnonymous(Authentication)
ExceptionTranslationFilter
AccessDeniedException
AccessDeniedException
AuthenticationEntryPoint
在定义访问控制时,您经常会看到上述拦截器配置中的属性被替换为 ,这实际上是一回事。
这是我们将在授权章节中看到的用法示例。
它使用 an 来处理此特定配置属性并向匿名用户授予访问权限。
这种方法更强大,因为它允许您区分匿名用户、记住用户和完全身份验证的用户。
但是,如果您不需要此功能,则可以坚持使用 ,它将由 Spring Security 的标准处理。ROLE_ANONYMOUS
IS_AUTHENTICATED_ANONYMOUSLY
AuthenticatedVoter
AuthenticationTrustResolver
AuthenticatedVoter
ROLE_ANONYMOUS
RoleVoter
使用 Spring MVC 获取匿名身份验证
Spring MVC 使用自己的参数解析器解析 Principal
类型的参数。
这意味着像这样的构造:
-
Java
-
Kotlin
@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#getPrincipal
null
如果要获取匿名请求,请改用:Authentication
@CurrentSecurityContext
-
Java
-
Kotlin
@GetMapping("/")
public String method(@CurrentSecurityContext SecurityContext context) {
return context.getAuthentication().getName();
}
@GetMapping("/")
fun method(@CurrentSecurityContext context : SecurityContext) : String =
context!!.authentication!!.name
key
ProviderManager
AnonymousAuthenticationProvider
Authentication
AnonymousAuthenticationToken
key
ProviderManager