第 22 章 digest认证

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

22.1. 配置digest验证

因为digest不包含在命名空间中,所以我们需要配置额外的过滤器和验证入口。

<beans:bean id="digestProcessingFilter" class="org.springframework.security.web.authentication.www.DigestAuthenticationFilter" autowire="byType">
	<beans:property name="authenticationEntryPoint" ref="digestProcessingFilterEntryPoint"/>
</beans:bean>

<beans:bean id="digestProcessingFilterEntryPoint"
	class="org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint">
	<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" />
    <custom-filter position="BASIC_AUTH_FILTER" ref="digestProcessingFilter" />
</http>
        

现在我们访问系统时,不会再进入之前的登录页面,而是会显示浏览器原生的登录对话框。

digest登录

图 22.1. digest登录


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

HTTP请求头

图 22.2. HTTP请求头


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

22.2. 使用ajax实现digest认证

可以直接使用ajax来进行digest认证,完全不需要任何额外的配置,只需要在open的时候传入用户名和密码就可以完成认证。

oRequest.open("get", "index.jsp", false, "user", "user");
oRequest.setRequestHeader("Content-type", "text/xml; charset=utf-8");
oRequest.send("");
        

这样就完成的认证过程,之后再使用普通方式访问其他页面也没问题了。

22.3. 编程实现digest客户端

如果希望自己编写客户端进行digest认证,可以参考RFC 2617,它是对RFC 2069这个早期摘要式认证标准的更新。

在HTTP请求头中将包含这样一个Authorization,它包含了username, realm, nonce, uri, responseDigest, qop, nc和cnonce八个部分。其中nonce是digest认证的中心,它的组成结构如下所示:

base64(expirationTime1 + ":" + md5Hex(expirationTime + ":" + key2))
        

1

其中expirationTime是nonce的过期时间,单位是毫秒。

2

key是放置nonce修改的私钥。

如果服务器生成的nonce已经过期(但是摘要还是有效),DigestProcessingFilterEntryPoint会发送一个"stale=true"头信息。 这告诉用户代理,这里不再需要打扰用户(像是密码和用户其他都是正确的),只是简单尝试使用一个新nonce。

实例在ch112。