HTTP基本认证

1. 简介

在HTTP中,基本认证是一种用来允许Web浏览器或其他客户端程序在请求时提供用户名和口令形式的身份凭证的一种登录验证方式。


在发送之前是以用户名追加一个冒号然后串接上口令,并将得出的结果字符串再用Base64算法编码。例如,提供的用户名是Aladdin、口令是open sesame,则拼接后的结果就是Aladdin:open sesame,然后再将其用Base64编码,得到QWxhZGRpbjpvcGVuIHNlc2FtZQ==。最终将Base64编码的字符串发送出去,由接收者解码得到一个由冒号分隔的用户名和口令的字符串。


虽然对用户名和口令的Base64算法编码结果很难用肉眼识别解码,但它仍可以极为轻松地被计算机所解码,就像其容易编码一样。编码这一步骤的目的并不是安全与隐私,而是为将用户名和口令中的不兼容的字符转换为均与HTTP协议兼容的字符集。


2. Spring Security配置

Spring对其进行内置支持,所以配置超简单,<security:http-basic /> 覆盖自动配置就搞定了。

1
2
3
4
5
6
< security:http  auto-config = "true" >
         < security:intercept-url  pattern = "/hello"
             access = "ROLE_ADMIN"  />
         < security:intercept-url  pattern = "/**"  access = "ROLE_USER"  />
         < security:http-basic  />
     </ security:http >


3. 小结

HTTP Basic认证需要浏览器支持(当然绝大部分浏览器都支持),弹出的认证窗口是浏览器实现的而非应用提供的。由于密码几乎是以明文方式传送,所以极其不安全,生产环境一般不会使用这种认证。


HTTP摘要认证

1. 简介

HTTP摘要认证可以看做是HTTP基本认证的升级版,解决了HTTP基本认证最大的缺点,即将传送的密码加密,而且是使用不可逆的MD5加密算法。


2. Spring Security配置

HTTP摘要认证配置稍微复杂点,需要更改entry-point-ref,和增加custom-filter替换原来的HTTP基本认证Filter。

由于使用自定义Filter,所以不能同时使用auto-config。

对DigestAuthenticationFilter bean,我们可以通过passwordAlreadyEncoded属性指定密码是否已经加密,Spring Security Web库中有DigestAuthUtils类可以用来做HTTP 摘要加密,但该类对包外不可见,所以自己可以拷贝实现一个备用。    

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<? xml  version = "1.0"  encoding = "UTF-8" ?>
< beans  xmlns = "http://www.springframework.org/schema/beans"
     xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"  xmlns:security = "http://www.springframework.org/schema/security"
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
         http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd">
                                               
     < bean  id = "digestFilter"  class=
         "org.springframework.security.web.authentication.www.DigestAuthenticationFilter">
       < property  name = "userDetailsService"  ref = "userService" />
       < property  name = "authenticationEntryPoint"  ref = "digestEntryPoint" />
     </ bean >
     < bean  id = "digestEntryPoint"  class=
         "org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint">
       < property  name = "realmName"  value = "com.stevex.demo" />
       < property  name = "key"  value = "acegi" />  
       < property  name = "nonceValiditySeconds"  value = "30" />
     </ bean >
                                               
     < security:http  entry-point-ref = "digestEntryPoint" >
         < security:intercept-url  pattern = "/admin"
             access = "ROLE_ADMIN"  />
         < security:intercept-url  pattern = "/list"  access = "ROLE_USER"  />
         < security:logout  />
         < security:custom-filter  ref = "digestFilter"  position = "BASIC_AUTH_FILTER"  />
     </ security:http >
     < security:authentication-manager >
         < security:authentication-provider >
             < security:user-service  id = "userService" >
                 < security:user  authorities = "ROLE_USER"  name = "stevex"
                     password = "stevex"  />
                 < security:user  authorities = "ROLE_USER, ROLE_ADMIN"
                     name = "admin"  password = "admin"  />
             </ security:user-service >
         </ security:authentication-provider >
     </ security:authentication-manager >
</ beans >

HTTP摘要MD5密码生成实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public  class  DigestUtil {
     public  static  void  main(String[] args) {
         System.out.println(encodePasswordInA1Format( "stevex" , "com.stevex.demo" , "stevex" ));
     }
                                     
     static  String encodePasswordInA1Format(String username, String realm, String password) {
         String a1 = username +  ":"  + realm +  ":"  + password;
         return  md5Hex(a1);
     }
     static  String md5Hex(String data) {
         MessageDigest digest;
         try  {
             digest = MessageDigest.getInstance( "MD5" );
         catch  (NoSuchAlgorithmException e) {
             throw  new  IllegalStateException( "No MD5 algorithm available!" );
         }
         return  new  String(Hex.encode(digest.digest(data.getBytes())));
     }
}


3. 小结

摘要访问认证有意成为一个安全性的折衷,它意图代替非加密的HTTP基本认证,但是它没有被设计为替换强认证协议,实际使用也不多。

当然HTTP摘要认证也是需要浏览器支持的,弹出的验证窗口来自浏览器而非应用提供,经过测试,个人感觉Firefox支持比Chrome好。