第 18 章 digest认证

digest认证比form-login和http-basic更安全的一种认证方式,尤其适用于不能使用https协议的场景。它与http-basic一样,都是不基于session的无状态认证方式。

18.1. 配置digest验证

因为digest不包含在命名空间中,所以我们需要配置额外的过滤器和验证入口。
<beans:bean id="digestProcessingFilter" class="org.springframework.security.ui.digestauth.DigestProcessingFilter">
    <custom-filter position="BASIC_PROCESSING_FILTER" />
    <beans:property name="authenticationEntryPoint" ref="digestProcessingFilterEntryPoint"/>
    <beans:property name="userDetailsService"
        ref="org.springframework.security.userdetails.memory.InMemoryDaoImpl"/>
</beans:bean>
<beans:bean id="digestProcessingFilterEntryPoint"
    class="org.springframework.security.ui.digestauth.DigestProcessingFilterEntryPoint">
    <beans:property name="realmName" value="springsecurity"/>
    <beans:property name="key" value="changeIt"/>
</beans:bean>
        
然后记得删除auto-config="true",去除默认的form-login和http-basic认证,并添加对验证入口的引用。
<http auto-config="true" entry-point-ref="digestProcessingFilterEntryPoint">
    <intercept-url pattern="/admin.jsp" access="ROLE_ADMIN" />
    <intercept-url pattern="/" access="ROLE_USER" />
</http>
        
现在我们访问系统时,不会再进入之前的登录页面,而是会显示浏览器原生的登录对话框。
digest登录
图 18.1. digest登录

登录成功之后,我们可以在HTTP请求头部看到basic验证所需的属性Authorization。
HTTP请求头
图 18.2. HTTP请求头

最后需要注意的是,因为digest认证不使用session,所以无法与rememberMe功用。

18.2. 编程实现basic客户端

如果希望自己编写客户端进行digest认证,可以参考RFC 2617,它是对RFC 2069这个早期摘要式认证标准的更新。
在HTTP请求头中将包含这样一个Authorization,它包含了username, realm, nonce, uri, responseDigest, qop, nc和cnonce八个部分。其中nonce是digest认证的中心,它的组成结构如下所示:
base64(expirationTime + ":" + md5Hex(expirationTime + ":" + key))
        
1
其中expirationTime是nonce的过期时间,单位是毫秒。
2
key是放置nonce修改的私钥。
如果服务器生成的nonce已经过期(但是摘要还是有效),DigestProcessingFilterEntryPoint会发送一个"stale=true"头信息。 这告诉用户代理,这里不再需要打扰用户(像是密码和用户其他都是正确的),只是简单尝试使用一个新nonce。
实例在ch112。