angular - 如何在角离子中使用摘要身份验证发送请求
问题描述
如何在 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
解决方案
我想分享我找到的解决这个问题的解决方案。实际上,我试图完全像基本身份验证一样执行此操作,但摘要身份验证就像两步身份验证。需要打两次电话才能得到响应。在初始请求中,服务器将为我们提供 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' }}
推荐阅读
- visual-studio - 检查工作的 C 编译器:“cl.exe - 已跳过”:Visual Studio 2019
- python - 如何按日期时间顺序对作为字符串格式的日期的列名进行排序
- regex - Ruby正则表达式从仅包含一个数字的字符串中提取一个数字并修剪逗号后的部分
- javascript - 使用 alt 属性搜索 img 表并显示整行
- javascript - bcrypt.js 怎么知道散列密码和明文密码是一样的呢?
- flutter - 如何在 Flutter Web 应用中进入全屏模式
- python - 如果您尝试操作当前正在操作的对象,S3 会抛出什么异常?
- javascript - 我无法删除我的编辑个人资料表单中的空间
- python - 如何在 pandas 数据框中创建一个列来验证是否发生了状态转换?
- pandas - 我可以使用数据框作为函数的输入吗?