此版本仍在开发中,尚未被视为稳定版本。如需最新稳定版本,请使用 Spring Security 7.0.4spring-doc.cadn.net.cn

摘要认证

本节详细介绍了 Spring Security 如何通过 https://tools.ietf.org/html/rfc2617 提供对摘要认证(Digest Authentication)的支持。spring-doc.cadn.net.cn

你不应在现代应用程序中使用摘要认证(Digest Authentication),因为它被认为不安全。 最明显的问题在于,你必须以明文、加密格式或 MD5 格式存储密码。 所有这些存储格式都被认为是不安全的。 相反,你应该使用单向自适应密码哈希算法(如 bCrypt、PBKDF2、SCrypt 等)来存储凭证,而摘要认证并不支持此类算法。spring-doc.cadn.net.cn

摘要认证(Digest Authentication)试图解决基本认证(Basic authentication)的诸多弱点,特别是确保凭据永远不会以明文形式在网络上传输。 许多浏览器支持摘要认证spring-doc.cadn.net.cn

HTTP 摘要认证(Digest Authentication)所遵循的标准由 RFC 2617 定义,该标准更新了早期由 RFC 2069 规定的摘要认证标准。 大多数用户代理(user agent)都实现了 RFC 2617。 Spring Security 的摘要认证支持与 RFC 2617 中规定的“auth”保护质量(qop)兼容,同时也向后兼容 RFC 2069。 如果你需要使用未加密的 HTTP(即没有 TLS 或 HTTPS),并且希望尽可能提高认证过程的安全性,那么摘要认证曾被认为是一个更具吸引力的选择。 然而,每个人都应当使用 HTTPSspring-doc.cadn.net.cn

摘要认证(Digest Authentication)的核心是一个“nonce”。 这是服务器生成的一个值。 Spring Security 的 nonce 采用以下格式:spring-doc.cadn.net.cn

摘要语法
base64(expirationTime + ":" + md5Hex(expirationTime + ":" + key))
expirationTime:   The date and time when the nonce expires, expressed in milliseconds
key:              A private key to prevent modification of the nonce token

您需要确保使用 NoOpPasswordEncoder 来配置不安全的纯文本 密码存储。 (请参阅 Javadoc 中的 NoOpPasswordEncoder 类。) 以下提供了使用 Java 配置配置摘要认证的示例:spring-doc.cadn.net.cn

摘要认证
@Autowired
UserDetailsService userDetailsService;

DigestAuthenticationEntryPoint authenticationEntryPoint() {
	DigestAuthenticationEntryPoint result = new DigestAuthenticationEntryPoint();
	result.setRealmName("My App Realm");
	result.setKey("3028472b-da34-4501-bfd8-a355c42bdf92");
	return result;
}

DigestAuthenticationFilter digestAuthenticationFilter() {
	DigestAuthenticationFilter result = new DigestAuthenticationFilter();
	result.setUserDetailsService(userDetailsService);
	result.setAuthenticationEntryPoint(authenticationEntryPoint());
	return result;
}

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
	http
		// ...
		.exceptionHandling(e -> e.authenticationEntryPoint(authenticationEntryPoint()))
		.addFilter(digestAuthenticationFilter());
	return http.build();
}
<b:bean id="digestFilter"
        class="org.springframework.security.web.authentication.www.DigestAuthenticationFilter"
    p:userDetailsService-ref="jdbcDaoImpl"
    p:authenticationEntryPoint-ref="digestEntryPoint"
/>

<b:bean id="digestEntryPoint"
        class="org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint"
    p:realmName="My App Realm"
	p:key="3028472b-da34-4501-bfd8-a355c42bdf92"
/>

<http>
	<!-- ... -->
	<custom-filter ref="userFilter" position="DIGEST_AUTH_FILTER"/>
</http>