HTTP Digest接入方式鉴权认证流程

HTTP Digest接入方式鉴权认证流程

一、摘要认证原理

  摘要认证与基础认证的工作原理很相似,用户先发出一个没有认证证书的请求,Web服务器回复一个带有WWW-Authenticate头的响应,指明访问所请求的资源需要证书。但是和基础认证发送以Base 64编码的用户名和密码不同,在摘要认证中服务器让客户选一个随机数(称作”nonce“),然后浏览器使用一个单向的加密函数生成一个消息摘要(message digest),该摘要是关于用户名、密码、给定的nonce值、HTTP方法,以及所请求的URL。

二、摘要认证流程

  客户端首次向服务器发送HTTP请求,服务器返回401(未授权)响应进行挑战。401消息的头里带有WWW-Authenticate消息头,其中包含挑战摘要的随机参数nonce。客户端收到401后,将用户名密码和挑战信息用MD5加密形成认证鉴权头,重新发送给服务器,服务器对认证鉴权头进行验证,如果认证成功则返回200 OK,并在响应的消息中返回下次认证的随机数nextnonce,客户端下次请求时,根据nextnonce生成鉴权头进行HTTP请求。
HTTP摘要认证流程图
服务器的401未授权挑战WWW-Authenticate消息头语法:

challenge =“Digest” digest-challenge
digest-challenge=1#( realm | [ domain ] | nonce |
[ opaque ] |[ stale ] | [ algorithm ] |
[ qop-options ] | [auth-param] )
domain =“domain" “=” <“> URI ( 1*SP URI ) <”>
URI =absoluteURI | abs_path
nonce =“nonce" “=” nonce-value
nonce-value =quoted-string
opaque =“opaque" “=” quoted-string
stale =“stale" “=” ( “true” | “false” )
algorithm =“algorithm" “=” ( “MD5” | “MD5-sess” |
token )
qop-options =“qop" “=” <“> 1#qop-value <”>
qop-value =“auth" | “auth-int” | token

参数说明:

  • realm:用户域。由服务端告知
  • qop:保护质量。auth:鉴权,不对消息体做完整性验证。auth-int:鉴权并需要对消息体做摘要,保证消息完整性。
  • nonce:摘要质询参数。401响应中唯一生成的字符串数据。采用十六进制数据。
  • opaque:会话标识。由服务器指定,客户端须在请求二中返回该数据。采用十六进制数据。

客户端的挑战响应消息Authorization头参数一下为String类型:

  • username:用户名。必填。
  • realm:用户域。由服务方告知
  • nonce:摘要质询参数。返回请求一响应中的参数nonce
  • uri:访问路径。请求的URI
  • qop:保护质量。auth:鉴权,不对消息体做完整性验证。auth-int:鉴权并需要对消息体做摘要,保证消息完整性。注册过程使用auth
  • nc:nonce计数参数。客户端请求的十六进制计数,以00000001开始,每次请求加1,目的是防止重放攻击。
  • cnonce:客户端nonce值。客户端用来鉴定服务器的摘要质询参数
  • response:响应值。对请求一中401响应的参数采用MD5算法做摘要计算的结果
  • opaque:会话标识。返回服务器原值

response参数的算法:

response=<“> < KD ( H(A1), unq(nonce-value) “:” nc-value “:”
unq(cnonce-value) “:” unq(qop-value) “:” H(A2) ) <”>
A1=unq(username-value) “:” unq(realm-value) “:” passwd
如果qop等于auth,A2=Method “:” digest-uri-value 如果qop等于auth-int,A2=Method
“:” digest-uri-value “:” H(entity-body) 其中: H(data)=MD5(data)。
KD(secret, data)=H(concat(secret, “:”, data))。 unq(X)代表去掉X前后的引号。
Method=GET或者POST。 entity-body代表HTTP请求的消息体。 passwd=key。

三、代码实现HTTP Digest接入方式鉴权认证

以下是初次接触摘要认证时的简要请求方法。
摘要认证过程也可用Springorg.springframework.web.client.RestTemplate实现,修改配置类中的RestTemplate生成方法。具体方法自行百度。

public static String sendPostRequest(String username,String password,String uri, String jsonParams){
        CloseableHttpClient httpClient = null;
        String result =null;
        String requestUrl=url+uri;
        try {
            CredentialsProvider credsProvider = new BasicCredentialsProvider();
            httpClient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
            //第一次请求
            HttpPost post = new HttpPost(requestUrl);
            // 构造消息头
            post.addHeader("Content-type","application/json; charset=utf-8");
            post.setHeader("Accept", "application/json");
            HttpResponse firstResponse = httpClient.execute(post);
            org.apache.http.HttpEntity firstEntity = null;
            firstEntity = firstResponse.getEntity();
            result = EntityUtils.toString(firstEntity, "UTF-8");

            Map<String,String> map =new HashMap<String,String>();

            StringEntity stringEntity = new StringEntity(jsonParams);

            //解析头部
            Header[] h=firstResponse.getHeaders("WWW-Authenticate");
            StringBuffer auth=new StringBuffer(h[0].toString());
            String realm=auth.substring(auth.indexOf("realm=")+6,auth.indexOf("qop=")-1);
            String qop=auth.substring(auth.indexOf("qop=")+4,auth.indexOf("nonce=")-1);
            String nonce=auth.substring(auth.indexOf("nonce=")+6,auth.indexOf("opaque=")-1);
            String opaque=auth.substring(auth.indexOf("opaque=")+7);
            String cnonce="00000001";
            String nc="00000001";
            String algorithm="MD5";
            String responseString;
            String params1=username+":"+realm+":"+password;
            String params2="POST:"+uri;
            String params3= SecureUtil.md5(params1)+":"+nonce+":"+nc+":"+cnonce+":"+qop+":"+SecureUtil.md5(params2);
            responseString=SecureUtil.md5(params3);
            StringBuilder sb=new StringBuilder();
            String Authorization ="Digest username=" + username +",realm="+ realm +",nonce=" + nonce +",uri=" + uri +
                    ",response=" + responseString + ",cnonce=" +cnonce + ",qop=" +qop+ ",nc="+nc;

            //第二次请求
            // 构造消息头
            post.setHeader("Authorization",Authorization);
            post.setEntity(stringEntity);
            HttpResponse secondResponse = httpClient.execute(post);
            org.apache.http.HttpEntity secondEntity = null;
            secondEntity = secondResponse.getEntity();

            result = EntityUtils.toString(secondEntity, "UTF-8");
            httpClient.close();
        } catch (Exception e) {
            log.error(e.getMessage());
        } finally {
            if (httpClient != null) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    log.error(e.getMessage());
                }
            }
        }
        return result;
    }
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值