Digest Auth 摘要认证

Digest Auth 摘要认证

1.非常规方式

转载:https://blog.csdn.net/qq_25391785/article/details/86595529

    public static void postMethod(String url, String query) {
        try {

            CredentialsProvider credsProvider = new BasicCredentialsProvider();
            credsProvider.setCredentials(
                    new AuthScope("xx.xx.xx.xx", 80),//请求地址 + 端口号
                    new UsernamePasswordCredentials("xx", "xxxx"));// 用户名 + 密码 (用于验证)
            CloseableHttpClient httpclient = HttpClients.custom()
                    .setDefaultCredentialsProvider(credsProvider)
                    .build();
            HttpPost postMethod = new HttpPost(url);//请求详细地址(如:http://192.168.1.105:9000/MotorVehicles)
            StringEntity s = new StringEntity(query);//向后台传的json数据
            s.setContentEncoding("utf-8");//编码
            s.setContentType("application/json");//发送json数据需要设置contentType
            postMethod.setEntity(s);
            HttpResponse response = httpclient.execute(postMethod); //执行POST方法

            System.out.println("resCode = " + response.getStatusLine().getStatusCode()); //获取响应码

            System.out.println("result = " + EntityUtils.toString(response.getEntity(), "utf-8")); //获取响应内容

        } catch (Exception e) {
            System.out.println("推送失败:"+e);
        }

    }

2.常规认证方式

在这里插入图片描述
1.发送一个请求

    GET /auth/basic/ HTTP/1.1
    HOST: target

2.服务器返回401响应头,要求输入用户凭据

    HTTP/1.1 401 Unauthorized
    WWW-Authenticate: Digest realm="Digest Encrypt",nonce="nmeEHKLeBAA=aa6ac7ab3cae8f1b73b04e1e3048179777a174b3", opaque="0000000000000000",stale=false, algorithm=MD5, qop="auth"

3.输入凭据后再发送请求

    GET /auth/digest/ HTTP/1.1
    Accept: */*
    Authorization:  Digest username="LengWa", realm="Digest Encrypt",  qop="auth", algorithm="MD5", uri="/auth/digest/", nonce="nmeEHKLeBAA=aa6ac7ab3cae8f1b73b04e1e3048179777a174b3", nc=00000001, cnonce="6092d3a53e37bb44b3a6e0159974108b", opaque="0000000000000000", response="652b2f336aeb085d8dd9d887848c3314"

4.服务端验证通过后返回数据

代码工具类(本人的实际服务因第二次传的凭据不返回realm参数,遂在代码里将其写死):


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.asiainfo.req.DigestAuthReq;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Http Digest Request contains POST、GET、PUT
 * @author zhangdan
 * @date 2021-04-22
 */
@Slf4j
public class HttpRequestUtils {

    private static final Logger logger = LoggerFactory.getLogger(HttpRequestUtils.class);

    public static void main(String[] args) {

//        String param = "";
//        String username = "xxxx";
//        String password = "xxxx";


        postMethod("http://ip:80/api/howell/ver10/aiop_service/garbage_management/GarbageStations/Cameras/List","{\n" +
                "    \"PageIndex\":\"1\",\n" +
                "    \"PageSize\":\"99999\"\n" +
                "}");
        //System.out.println(s);
    }

    static int nc = 0;    //调用次数
    private static final String GET = "GET";
    private static final String POST = "POST";
    private static final String PUT = "PUT";
    private static final String DELETE = "DELETE";




    /**
     * 向指定URL发送POST方法的请求
     * @param url                                       发送请求的URL
     * @param param                                     请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
     * @param username                                  验证所需的用户名
     * @param password                                  验证所需的密码
     * @param json                                      请求json字符串
     * @param type                                      返回xml和json格式数据,默认xml,传入json返回json数据
     * @return URL 所代表远程资源的响应结果
     */
    public  static String sendPost(DigestAuthReq digestAuthReq) {
        StringBuilder result = new StringBuilder();
            String json= digestAuthReq.getJsonStr();
            String url= digestAuthReq.getUrl();
            String param= digestAuthReq.getParam();
            String username=digestAuthReq.getUsername();
            String password=digestAuthReq.getPassword();
            String type= digestAuthReq.getType();
            logger.info("json============="+json);
            BufferedReader in = null;
            try {
                //String wwwAuth = sendGet(url, param);       //发起一次授权请求
                String wwwAuth=sendPost(url, param);
                if (wwwAuth.startsWith("WWW-Authenticate:")) {
                    wwwAuth = wwwAuth.replaceFirst("WWW-Authenticate:", "");
                } else {
                    return wwwAuth;
                }
                nc ++;
                String urlNameString = url + (StringUtils.isNotEmpty(param) ? "?" + param : "");
                URL realUrl = new URL(urlNameString);
                // 打开和URL之间的连接
                HttpURLConnection connection = (HttpURLConnection)realUrl.openConnection();

                // 设置是否向connection输出,因为这个是post请求,参数要放在
                // http正文内,因此需要设为true
                connection.setDoOutput(true);
                // Read from the connection. Defaultis true.
                connection.setDoInput(true);
                // 默认是 GET方式
                connection.setRequestMethod(POST);
                // Post 请求不能使用缓存
                connection.setUseCaches(false);

                // 设置通用的请求属性
                setRequestProperty(connection, wwwAuth,realUrl, username, password, POST, type);

                if (!StringUtils.isEmpty(json)) {
                    byte[] writebytes =json.getBytes();
                    connection.setRequestProperty("Content-Length",String.valueOf(writebytes.length));
                    OutputStream outwritestream = connection.getOutputStream();
                    outwritestream.write(json.getBytes());
                    outwritestream.flush();
                    outwritestream.close();
                }
                if (connection.getResponseCode() == 200 || connection.getResponseCode() == 201) {
                    in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                    String line;
                    while ((line = in.readLine()) != null) {
                        result.append(line);
                    }
                } else {
                    String errResult = formatResultInfo(connection, type);
                    logger.info(errResult);
                    return errResult;
                }

                nc = 0;
            } catch (Exception e) {
                nc = 0;
                throw new RuntimeException(e);
            } finally {
                try {
                    if (in != null) in.close();
                } catch (Exception e2) {
                    e2.printStackTrace();
                }
            }


        return result.toString();
    }


    /**
     * 向指定URL发送GET方法的请求
     * @param url                                       发送请求的URL
     * @param param                                     请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
     * @param username                                  验证所需的用户名
     * @param password                                  验证所需的密码
     * @param type                                      返回xml和json格式数据,默认xml,传入json返回json数据
     * @return URL 所代表远程资源的响应结果
     */
    public static String sendGet(String url, String param, String username, String password, String type) {

        StringBuilder result = new StringBuilder();
        BufferedReader in = null;
        try {
            String wwwAuth = sendGet(url, param);       //发起一次授权请求
            if (wwwAuth.startsWith("WWW-Authenticate:")) {
                wwwAuth = wwwAuth.replaceFirst("WWW-Authenticate:", "");
            } else {
                return wwwAuth;
            }
            nc ++;
            String urlNameString = url + (StringUtils.isNotEmpty(param) ? "?" + param : "");
            URL realUrl = new URL(urlNameString);
            // 打开和URL之间的连接
            HttpURLConnection connection = (HttpURLConnection)realUrl.openConnection();
            // 设置通用的请求属性
            setRequestProperty(connection, wwwAuth,realUrl, username, password, GET, type);
            // 建立实际的连接
            // connection.connect();
            in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
            nc = 0;
        } catch (Exception e) {
            nc = 0;
            throw new RuntimeException(e);
        } finally {
            try {
                if (in != null) in.close();
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        return result.toString();
    }

    /**
     * 生成授权信息
     * @param authorization                             上一次调用返回401的WWW-Authenticate数据
     * @param username                                  用户名
     * @param password                                  密码
     * @return                                          授权后的数据, 应放在http头的Authorization里
     * @throws IOException                              异常
     */
    private static String getAuthorization(String authorization, String uri, String username, String password, String method) throws IOException {

        uri = StringUtils.isEmpty(uri) ? "/" : uri;
        String temp = authorization.replaceFirst("Digest", "").trim().replace("MD5","\"MD5\"").replace("realm=\"\"","realm=\"/howell/ver10/data\"");
        String json = withdrawJson(authorization);

        JSONObject jsonObject = JSON.parseObject(json);
        String cnonce = Digests.generateSalt2(8);
        String ncstr = ("00000000" + nc).substring(Integer.toString(nc).length());     //认证的次数,第一次是1,第二次是2...
        String algorithm = jsonObject.getString("algorithm");
        String qop = jsonObject.getString("qop");
        String nonce = jsonObject.getString("nonce");
        String realm = jsonObject.getString("realm");
        if(StringUtils.isEmpty(realm)){
            realm="/howell/ver10/data";
        }

        String response = Digests.http_da_calc_HA1(username, realm, password,
                nonce, ncstr, cnonce, qop,
                method, uri, algorithm);

        //组成响应authorization
        authorization = "Digest username=\"" + username + "\"," + temp;
        authorization += ",uri=\"" + uri
                + "\",nc=\"" + ncstr
                + "\",cnonce=\"" + cnonce
                + "\",response=\"" + response+"\"";
        return authorization;
    }

    /**
     * 将返回的Authrization信息转成json
     * @param authorization                                     authorization info
     * @return                                                  返回authrization json格式数据 如:String json = "{ \"realm\": \"Wowza\", \" domain\": \"/\", \" nonce\": \"MTU1NzgxMTU1NzQ4MDo2NzI3MWYxZTZkYjBiMjQ2ZGRjYTQ3ZjNiOTM2YjJjZA==\", \" algorithm\": \"MD5\", \" qop\": \"auth\" }";
     */
    private static String withdrawJson(String authorization) {
        String temp = authorization.replaceFirst("Digest", "").trim().replaceAll("\"","");
        String[] split = temp.split(",");
        Map<String, String> map = new HashMap<>();
        Arrays.asList(split).forEach(c -> {
            String c1 = c.replaceFirst("=",":");
            String[] split1 = c1.split(":");
            if(split1[0].trim().equals("realm")){
                map.put(split1[0].trim(), "/howell/ver10/data");
            }else{
                map.put(split1[0].trim(), split1[1].trim());
            }

        });
        return JSONObject.toJSONString(map);
    }

    /**
     * 向指定URL发送GET方法的请求
     * @param url                                                   发送请求的URL
     * @param param                                                 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
     * @return URL                                                  所代表远程资源的响应结果
     */
    public static String sendGet(String url, String param) {
        StringBuilder result = new StringBuilder();
        BufferedReader in = null;
        try {

            String urlNameString = url + (StringUtils.isNotEmpty(param) ? "?" + param : "");
            URL realUrl = new URL(urlNameString);
            // 打开和URL之间的连接
            URLConnection connection = realUrl.openConnection();
            // 设置通用的请求属性
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent",
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");

            connection.connect();

            //返回401时需再次用用户名和密码请求
            //此情况返回服务器的 WWW-Authenticate 信息
            if (((HttpURLConnection) connection).getResponseCode() == 401) {
                Map<String, List<String>> map = connection.getHeaderFields();
                return "WWW-Authenticate:" + map.get("WWW-Authenticate").get(0);
            }

            in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
        } catch (Exception e) {
            throw new RuntimeException("get请求发送失败",e);
        }
        // 使用finally块来关闭输入流
        finally {
            try {
                System.out.println(result.toString());
                if (in != null) in.close();
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        System.out.println(result.toString());
        logger.info(result.toString());
        return result.toString();

    }


    /**
     * 向指定URL发送GET方法的请求
     * @param url                                                   发送请求的URL
     * @param param                                                 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
     * @return URL                                                  所代表远程资源的响应结果
     */
    public static String sendPost(String url, String parameters ) {
        String result = "";
        BufferedReader in = null;
        try {
            String ip = "124.71.147.146";
            Integer port = 80;
            String username="wujiaochang";
            String password="3EhcqnbnZ4QFJ9sk";
            int resCode = 404;
            CredentialsProvider credsProvider = new BasicCredentialsProvider();
            credsProvider.setCredentials(new AuthScope(ip, port), // 请求地址 + 端口号
                    new UsernamePasswordCredentials(username, password));// 用户名 + 密码 (用于验证)
            HttpClient httpclient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
            try {
                SSLContext sslContext = SSLContextBuilder.create().useProtocol(SSLConnectionSocketFactory.SSL).loadTrustMaterial((x, y) -> true).build();
                RequestConfig config = RequestConfig.custom().setConnectTimeout(5000).setSocketTimeout(5000).build();
                httpclient = HttpClientBuilder.create().setDefaultRequestConfig(config).setSSLContext(sslContext).setSSLHostnameVerifier((x, y) -> true).build();
            } catch (Exception e) {
                e.printStackTrace();
            }
            HttpPost postMethod = new HttpPost(url);// 请求详细地址(如:http://192.168.1.105:9000/MotorVehicles)
            //根据不通要求自己添加头
            //根据不通要求自己添加头
            postMethod.addHeader("Content-Type", "application/json");
            postMethod.addHeader("accept", "*/*");
            postMethod.addHeader("connection", "Keep-Alive");
            postMethod.addHeader("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");

            StringEntity s = new StringEntity(JSON.toJSONString(parameters));// 向后台传的json数据
            s.setContentEncoding("utf-8");// 编码
            postMethod.setEntity(s);
            HttpResponse response = httpclient.execute(postMethod); // 执行POST方法
            resCode = response.getStatusLine().getStatusCode();
            System.out.println("resCode = " + resCode); // 获取响应码
            result = EntityUtils.toString(response.getEntity(), "utf-8");
            log.info("result = " + result); // 获取响应内容

            if (resCode == 401) {
                return  "" +response.getHeaders("WWW-Authenticate")[0];
            }
        }
        // 使用finally块来关闭输入流
        catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println(result.toString());
        logger.info(result.toString());
        return result.toString();

    }
    /**
     * HTTP set request property
     *
     * @param connection                            HttpConnection
     * @param wwwAuth                               授权auth
     * @param realUrl                               实际url
     * @param username                              验证所需的用户名
     * @param password                              验证所需的密码
     * @param method                                请求方式
     * @param type                                  返回xml和json格式数据,默认xml,传入json返回json数据
     */
    private static void setRequestProperty(HttpURLConnection connection, String wwwAuth, URL realUrl, String username, String password, String method, String type)
            throws IOException {

        if (type != null && type.equals("json")) {
            // 返回json
            connection.setRequestProperty("X-Webbrowser-Authentication","Forbidden");
            connection.setRequestProperty("accept", "application/json;charset=UTF-8");
            connection.setRequestProperty("Content-Type","application/json;charset=UTF-8");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent",
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
        } else {
            // 返回xml
            if (!method.equals(GET)) {
                connection.setRequestProperty("X-Webbrowser-Authentication","Forbidden");
                connection.setRequestProperty("Content-Type","application/json;charset=UTF-8");
            }
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            // connection.setRequestProperty("Cache-Control", "no-cache");
            connection.setRequestProperty("user-agent",
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");

        }
        //授权信息
        String authentication = getAuthorization(wwwAuth, realUrl.getPath(), username, password, method);
        connection.setRequestProperty("Authorization", authentication);
    }

    /**
     * 格式化请求返回信息,支持json和xml格式
     * @param connection                                HttpConnection
     * @param type                                      指定返回数据格式,json、xml,默认xml
     * @return                                          返回数据
     */
    private static String formatResultInfo(HttpURLConnection connection, String type) throws IOException {
        String result = "";
        if (type != null && type.equals("json")) {
            result = String.format("{\"errCode\":%s, \"message\":%s}",connection.getResponseCode(),connection.getResponseMessage());
        } else {
            result = String.format(" <?xml version=\"1.0\" encoding=\"UTF-8\" ?> "
                    + " <wmsResponse>"
                    + " <errCode>%d</errCode>"
                    + " <message>%s</message>"
                    + " </wmsResponse>",connection.getResponseCode(),connection.getResponseMessage());
        }
        return result;
    }



}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值