首页 > 解决方案 > 如何在角离子中使用摘要身份验证发送请求

问题描述

如何在 Angular ionic 中使用 Digest 身份验证发送请求。我已尝试使用以下代码请求服务器,但它不接受标头并弹出登录屏幕。谁能帮我找到使用离子角度发送摘要身份验证的正确方法。

this.headers = new Headers();
        this.headers.append('Content-Type', 'text/plain\r\n');
        this.headers.append('Authorization', 'Digest Auth'
        + ('username=admin')
        + ('password=Admin')
        + ('realm=172fbc06f747cfecc88c461e')
        + ('nonce=94f6b93716')
        + ('qop=auth')
        + ('nc=0000008a')
        + ('default_device=default'));
        var requestOptions = {
            method: 'GET',
            headers: this.headers,
            redirect: 'follow'
          };

        return this.http.get('/command/analy/analyx.cgi?AppControl=' + data ,requestOptions)
            .map(response => {
                reslt = response.ok;
                console.log("RESLT" + reslt)
                return reslt;
            })

代理

{
    "name": "ionic4-angular7-crud",
    "app_id": "",
    "type": "ionic-angular",
    "proxies": [
                 {
                    "path": "/command",
                    "proxyUrl": "http://192.168.10.109/command/"
                 }
                 ],
                 "integrations": {
         "cordova": {}
      }
    }

仍在 chrome 中,我收到 CROS 错误。谁能帮我解决这个问题

尝试禁用 chrome 网络安全,它没有显示 CROS 错误消息,但即使我直接调用 http,它也会转发到 HTTPS。

chrome.exe --user-data-dir="C:/Chrome 开发会话" --disable-web-security

标签: angularcordovaionic-frameworkionic3

解决方案


我想分享我找到的解决这个问题的解决方案。实际上,我试图完全像基本身份验证一样执行此操作,但摘要身份验证就像两步身份验证。需要打两次电话才能得到响应。在初始请求中,服务器将为我们提供 REALM、nonce 等,并且使用此令牌,我们需要使用 MD5(CryptoJS)对其进行哈希处理。请找到以下用于摘要身份验证的代码。

// 依赖于 CryptoJS MD5 哈希: // https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.js

var digestAuthRequest = function (method, url, username, password) {
var self = this;

 if (typeof CryptoJS === 'undefined' && typeof require === 'function') {
    var CryptoJS = require('crypto-js');
 }

this.scheme = null; // we just echo the scheme, to allow for 'Digest', 'X-Digest', 'JDigest' etc
this.nonce = null; // server issued nonce
this.realm = null; // server issued realm
this.qop = null; // "quality of protection" - '' or 'auth' or 'auth-int'
this.response = null; // hashed response to server challenge
this.opaque = null; // hashed response to server challenge
this.nc = 1; // nonce count - increments with each request used with the same nonce
this.cnonce = null; // client nonce

// settings
this.timeout = 10000; // timeout
this.loggingOn = true; // toggle console logging

// determine if a post, so that request will send data
this.post = false;
if (method.toLowerCase() === 'post' || method.toLowerCase() === 'put') {
    this.post = true;
}

// start here
// successFn - will be passed JSON data
// errorFn - will be passed error status code
// data - optional, for POSTS
this.request = function (successFn, errorFn, data) {
    // posts data as JSON if there is any
    if (data) {
        self.data = JSON.stringify(data);
    }
    self.successFn = successFn;
    self.errorFn = errorFn;
    console.log('self.nonce' + self.nonce);
    if (!self.nonce) {
        self.makeUnauthenticatedRequest(self.data);
    } else {
        self.makeAuthenticatedRequest();
    }
}
this.makeUnauthenticatedRequest = function (data) {
    self.firstRequest = new XMLHttpRequest();
    self.firstRequest.open(method, url, true);
    self.firstRequest.timeout = self.timeout;
    // if we are posting, add appropriate headers
    if (self.post) {
        self.firstRequest.setRequestHeader('Content-type', 'application/json');
    }

    self.firstRequest.onreadystatechange = function () {
        console.log("self.firstRequest.readyState" + self.firstRequest.readyState);
        // 2: received headers,  3: loading, 4: done
        if (self.firstRequest.readyState === 2) {
            var responseHeaders = self.firstRequest.getAllResponseHeaders();

            ResponseHeader = responseHeaders.split('\n');
            //responseHeaders = responseHeaders.split('\n');
            // get authenticate header
            var digestHeaders;
            console.log('digestHeaders 0 ' + digestHeaders + ResponseHeader.length);
            for (var i = 0; i < ResponseHeader.length; i++) {
                if (ResponseHeader[i].match('www-authenticate') != null) {
                    digestHeaders = ResponseHeader[i];
                }
            }
            if (digestHeaders != null) {
                // parse auth header and get digest auth keys
                digestHeaders = digestHeaders.slice(digestHeaders.indexOf(':') + 1, -1);
                digestHeaders = digestHeaders.split(',');
                self.scheme = digestHeaders[0].split(/\s/)[1];
                for (var i = 0; i < digestHeaders.length; i++) {
                    var equalIndex = digestHeaders[i].indexOf('='),
                        key = digestHeaders[i].substring(0, equalIndex),
                        val = digestHeaders[i].substring(equalIndex + 1);
                    val = val.replace(/['"]+/g, '');
                    // find realm
                    if (key.match(/realm/i) != null) {
                        self.realm = val;
                    }
                    // find nonce
                    if (key.match(/nonce/i) != null) {
                        self.nonce = val;
                    }
                    // find opaque
                    if (key.match(/opaque/i) != null) {
                        self.opaque = val;
                    }
                    // find QOP
                    if (key.match(/qop/i) != null) {
                        self.qop = val;
                    }
                }
                // client generated keys
                self.cnonce = self.generateCnonce();
                self.nc++;
                // if logging, show headers received:
                self.log('received headers:');
                self.log('  realm: ' + self.realm);
                self.log('  nonce: ' + self.nonce);
                self.log('  opaque: ' + self.opaque);
                self.log('  qop: ' + self.qop);
                // now we can make an authenticated request
                self.makeAuthenticatedRequest();
            }
        }
        if (self.firstRequest.readyState === 4) {
            if (self.firstRequest.status === 200) {
                self.log('Authentication not required for ' + url);
                if (self.firstRequest.responseText !== 'undefined') {
                    if (self.firstRequest.responseText.length > 0) {
                        // If JSON, parse and return object
                        if (self.isJson(self.firstRequest.responseText)) {
                            self.successFn(JSON.parse(self.firstRequest.responseText));
                        } else {
                            self.successFn(self.firstRequest.responseText);
                        }
                    }
                } else {
                    self.successFn();
                }
            }
        }
    }
    // send
    if (self.post) {
        // in case digest auth not required
        self.firstRequest.send(self.data);
    } else {
        self.firstRequest.send();
    }
    self.log('Unauthenticated request to +++ ' + url);

    // handle error
    self.firstRequest.onerror = function () {
        if (self.firstRequest.status !== 401) {
            self.log('Error (' + self.firstRequest.status + ') on unauthenticated request to ' + url);
            self.errorFn(self.firstRequest.status);
        }
    }
}
this.makeAuthenticatedRequest = function () {
    self.response = self.formulateResponse();
    self.authenticatedRequest = new XMLHttpRequest();
    self.authenticatedRequest.open(method, url, true);
    self.authenticatedRequest.timeout = self.timeout;
    var digestAuthHeader = self.scheme + ' ' +
        'username="' + username + '", ' +
        'realm="' + self.realm + '", ' +
        'nonce="' + self.nonce + '", ' +
        'uri="' + url + '", ' +
        'response="' + self.response + '", ' +
        'opaque="' + self.opaque + '", ' +
        'qop=' + self.qop + ', ' +
        'nc=' + ('00000000' + self.nc).slice(-8) + ', ' +
        'cnonce="' + self.cnonce + '"';
    self.authenticatedRequest.setRequestHeader('Authorization', digestAuthHeader);
    self.log('digest auth header response to be sent:');
    self.log(digestAuthHeader);
    // if we are posting, add appropriate headers
    if (self.post) {
        self.authenticatedRequest.setRequestHeader('Content-type', 'application/json');
    }
    self.authenticatedRequest.onload = function () {
        // success
        if (self.authenticatedRequest.status >= 200 && self.authenticatedRequest.status < 400) {
            // increment nonce count
            self.nc++;
            // return data
            if (self.authenticatedRequest.responseText !== 'undefined' && self.authenticatedRequest.responseText.length > 0) {
                // If JSON, parse and return object
                if (self.isJson(self.authenticatedRequest.responseText)) {
                    self.successFn(JSON.parse(self.authenticatedRequest.responseText));
                } else {
                    self.successFn(self.authenticatedRequest.responseText);
                }
            } else {
                self.successFn();
            }
        }
        // failure
        else {
            self.nonce = null;
            self.errorFn(self.authenticatedRequest.status);
        }
    }
    // handle errors
    self.authenticatedRequest.onerror = function () {
        self.log('Error (' + self.authenticatedRequest.status + ') on authenticated request to ' + url);
        self.nonce = null;
        self.errorFn(self.authenticatedRequest.status);
    };
    // send
    if (self.post) {
        self.authenticatedRequest.send(self.data);
    } else {
        self.authenticatedRequest.send();
    }
    self.log('Authenticated request to ' + url);
}
// hash response based on server challenge
this.formulateResponse = function () {
    console.log('self.realm ' + self.realm);
    var HA1 = CryptoJS.MD5(username + ':' + self.realm + ':' + password).toString();
    var HA2 = CryptoJS.MD5(method + ':' + url).toString();
    var response = CryptoJS.MD5(HA1 + ':' +
        self.nonce + ':' +
        ('00000000' + self.nc).slice(-8) + ':' +
        self.cnonce + ':' +
        self.qop + ':' +
        HA2).toString();
    return response;
}
// generate 16 char client nonce
this.generateCnonce = function () {
    var characters = 'abcdef0123456789';
    var token = '';
    for (var i = 0; i < 16; i++) {
        var randNum = Math.round(Math.random() * characters.length);
        token += characters.substr(randNum, 1);
    }
    return token;
}
this.abort = function () {
    self.log('[digestAuthRequest] Aborted request to ' + url);
    if (self.firstRequest != null) {
        if (self.firstRequest.readyState != 4) self.firstRequest.abort();
    }
    if (self.authenticatedRequest != null) {
        if (self.authenticatedRequest.readyState != 4) self.authenticatedRequest.abort();
    }
}
this.isJson = function (str) {
    try {
        JSON.parse(str);
    } catch (e) {
        return false;
    }
    return true;
}
this.log = function (str) {
    if (self.loggingOn) {
        console.log('[digestAuthRequest] ' + str);
    }
}
this.version = function () { return '0.8.0' }}

推荐阅读