Support multiple auth schemes

master
Cristi Vîjdea 2018-10-14 18:16:09 +03:00
parent 060fe1881a
commit e1aedab73f
1 changed files with 92 additions and 76 deletions

View File

@ -114,7 +114,7 @@ function initSwaggerUiConfig(swaggerSettings, oauth2Settings) {
var oldOnComplete = swaggerUiConfig.onComplete; var oldOnComplete = swaggerUiConfig.onComplete;
swaggerUiConfig.onComplete = function () { swaggerUiConfig.onComplete = function () {
if (persistAuth) { if (persistAuth) {
preauthorizeAny(savedAuth, window.ui); preauthorizeAll(savedAuth, window.ui);
} }
if (!hookedAuth) { if (!hookedAuth) {
@ -131,10 +131,7 @@ function initSwaggerUiConfig(swaggerSettings, oauth2Settings) {
swaggerUiConfig.requestInterceptor = function (request) { swaggerUiConfig.requestInterceptor = function (request) {
var headers = request.headers || {}; var headers = request.headers || {};
if (refetchWithAuth && request.loadSpec) { if (refetchWithAuth && request.loadSpec) {
var newUrl = applyAuth(savedAuth, request.url, headers) || request.url; request.url = applyAuth(savedAuth, request.url, headers) || request.url;
if (newUrl !== request.url) {
request.url = newUrl;
}
// need to manually remember requests for spec urls because // need to manually remember requests for spec urls because
// responseInterceptor has no reference to the request... // responseInterceptor has no reference to the request...
@ -150,7 +147,8 @@ function initSwaggerUiConfig(swaggerSettings, oauth2Settings) {
var oldResponseInterceptor = swaggerUiConfig.responseInterceptor; var oldResponseInterceptor = swaggerUiConfig.responseInterceptor;
swaggerUiConfig.responseInterceptor = function (response) { swaggerUiConfig.responseInterceptor = function (response) {
if (refetchWithAuth && specRequestsInFlight.indexOf(response.url) !== -1) { if (refetchWithAuth && specRequestsInFlight.indexOf(response.url) !== -1) {
// need setTimeout here because swagger-ui insists to updateUrl with the initial request url... // need setTimeout here because swagger-ui insists to call updateUrl
// with the initial request url after the response...
if (response.ok) { if (response.ok) {
setTimeout(function () { setTimeout(function () {
window.ui.specActions.updateUrl(response.url); window.ui.specActions.updateUrl(response.url);
@ -169,27 +167,6 @@ function initSwaggerUiConfig(swaggerSettings, oauth2Settings) {
} }
} }
/**
* Call sui.preauthorize### according to the type of savedAuth.
* @param savedAuth auth object saved from authActions.authorize
* @param sui SwaggerUI or SwaggerUIBundle instance
*/
function preauthorizeAny(savedAuth, sui) {
var schemeName = savedAuth.get("name"), schemeType = savedAuth.getIn(["schema", "type"]);
if (schemeType === "basic" && schemeName) {
var username = savedAuth.getIn(["value", "username"]);
var password = savedAuth.getIn(["value", "password"]);
if (username && password) {
sui.preauthorizeBasic(schemeName, username, password);
}
} else if (schemeType === "apiKey" && schemeName) {
var key = savedAuth.get("value");
if (key) {
sui.preauthorizeApiKey(schemeName, key);
}
}
}
function _usp(url, fn) { function _usp(url, fn) {
url = url.split('?'); url = url.split('?');
var usp = new URLSearchParams(url[1]); var usp = new URLSearchParams(url[1]);
@ -210,56 +187,90 @@ function removeQueryParam(url, key) {
}) })
} }
/**
* Call sui.preauthorize### for all authorizations in authorization.
* @param authorization authorization object {key => authScheme} saved from authActions.authorize
* @param sui SwaggerUI or SwaggerUIBundle instance
*/
function preauthorizeAll(authorization, sui) {
authorization.valueSeq().forEach(function (authScheme) {
var schemeName = authScheme.get("name"), schemeType = authScheme.getIn(["schema", "type"]);
if (schemeType === "basic" && schemeName) {
var username = authScheme.getIn(["value", "username"]);
var password = authScheme.getIn(["value", "password"]);
if (username && password) {
sui.preauthorizeBasic(schemeName, username, password);
}
} else if (schemeType === "apiKey" && schemeName) {
var key = authScheme.get("value");
if (key) {
sui.preauthorizeApiKey(schemeName, key);
}
} else {
// TODO: OAuth2
}
});
}
/** /**
* Manually apply auth headers from the given auth object. * Manually apply auth headers from the given auth object.
* @param {object} authScheme auth object saved from authActions.authorize * @param {object} authorization authorization object {key => authScheme} saved from authActions.authorize
* @param {string} requestUrl the request url * @param {string} requestUrl the request url
* @param {object} requestHeaders target headers * @param {object} requestHeaders target headers, modified in place by the function
* @return string new request url * @return string new request url
*/ */
function applyAuth(authScheme, requestUrl, requestHeaders) { function applyAuth(authorization, requestUrl, requestHeaders) {
requestHeaders = requestHeaders || {}; authorization.valueSeq().forEach(function (authScheme) {
var schemeName = authScheme.get("name"), schemeType = authScheme.getIn(["schema", "type"]); requestHeaders = requestHeaders || {};
if (schemeType === "basic" && schemeName) { var schemeName = authScheme.get("name"), schemeType = authScheme.getIn(["schema", "type"]);
var username = authScheme.getIn(["value", "username"]); if (schemeType === "basic" && schemeName) {
var password = authScheme.getIn(["value", "password"]); var username = authScheme.getIn(["value", "username"]);
if (username && password) { var password = authScheme.getIn(["value", "password"]);
requestHeaders["Authorization"] = "Basic " + btoa(username + ":" + password); if (username && password) {
} requestHeaders["Authorization"] = "Basic " + btoa(username + ":" + password);
} else if (schemeType === "apiKey" && schemeName) {
var _in = authScheme.getIn(["schema", "in"]), paramName = authScheme.getIn(["schema", "name"]);
var key = authScheme.get("value");
if (key && paramName) {
if (_in === "header") {
requestHeaders[paramName] = key;
} }
if (_in === "query") { } else if (schemeType === "apiKey" && schemeName) {
if (requestUrl) { var _in = authScheme.getIn(["schema", "in"]), paramName = authScheme.getIn(["schema", "name"]);
requestUrl = addQueryParam(requestUrl, paramName, key); var key = authScheme.get("value");
if (key && paramName) {
if (_in === "header") {
requestHeaders[paramName] = key;
} }
else { if (_in === "query") {
console.warn("WARNING: cannot apply apiKey query parameter via interceptor"); if (requestUrl) {
requestUrl = addQueryParam(requestUrl, paramName, key);
}
else {
console.warn("WARNING: cannot apply apiKey query parameter via interceptor");
}
} }
} }
} else {
// TODO: OAuth2
} }
} });
return requestUrl; return requestUrl;
} }
/** /**
* Remove the given authorization scheme from the url. * Remove the given authorization scheme from the url.
* @param {object} authScheme * @param {object} authorization authorization object {key => authScheme} containing schemes to deauthorize
* @param {string} requestUrl * @param {string} requestUrl request url
* @return string new request url
*/ */
function deauthUrl(authScheme, requestUrl) { function deauthUrl(authorization, requestUrl) {
var schemeType = authScheme.getIn(["schema", "type"]); authorization.valueSeq().forEach(function (authScheme) {
if (schemeType === "apiKey") { var schemeType = authScheme.getIn(["schema", "type"]);
var _in = authScheme.getIn(["schema", "in"]), paramName = authScheme.getIn(["schema", "name"]); if (schemeType === "apiKey") {
if (_in === "query" && requestUrl && paramName) { var _in = authScheme.getIn(["schema", "in"]), paramName = authScheme.getIn(["schema", "name"]);
requestUrl = removeQueryParam(requestUrl, paramName); if (_in === "query" && requestUrl && paramName) {
requestUrl = removeQueryParam(requestUrl, paramName);
}
} else {
// TODO: OAuth2?
} }
} });
return requestUrl; return requestUrl;
} }
@ -282,34 +293,39 @@ function hookAuthActions(sui, persistAuth, refetchWithAuth, refetchOnLogout) {
originalAuthorize(authorization); originalAuthorize(authorization);
// authorization is map of scheme name to scheme object // authorization is map of scheme name to scheme object
// need to use ImmutableJS because schema is already an ImmutableJS object // need to use ImmutableJS because schema is already an ImmutableJS object
var schemes = Immutable.fromJS(authorization); var newAuths = Immutable.fromJS(authorization);
savedAuth = schemes.valueSeq().first(); savedAuth = savedAuth.merge(newAuths);
if (persistAuth) {
localStorage.setItem("drf-yasg-auth", JSON.stringify(savedAuth.toJSON()));
}
if (refetchWithAuth) { if (refetchWithAuth) {
var url = sui.specSelectors.url(); var url = sui.specSelectors.url();
url = applyAuth(savedAuth, url) || url; url = applyAuth(savedAuth, url) || url;
sui.specActions.download(url); sui.specActions.download(url);
} }
if (persistAuth) {
localStorage.setItem("drf-yasg-auth", JSON.stringify(savedAuth.toJSON()));
}
}; };
var originalLogout = sui.authActions.logout; var originalLogout = sui.authActions.logout;
sui.authActions.logout = function (authorization) { sui.authActions.logout = function (authorization) {
if (savedAuth.get("name") === authorization[0]) { // stash logged out methods for use with deauthUrl
var oldAuth = savedAuth.set("value", null); var loggedOut = savedAuth.filter(function (val, key) {
savedAuth = Immutable.fromJS({}); return authorization.indexOf(key) !== -1;
if (persistAuth) { }).mapEntries(function (entry) {
localStorage.removeItem("drf-yasg-auth"); return [entry[0], entry[1].set("value", null)]
} });
// remove logged out methods from savedAuth
savedAuth = savedAuth.filter(function (val, key) {
return authorization.indexOf(key) === -1;
});
if (refetchWithAuth) { if (refetchWithAuth) {
var url = sui.specSelectors.url(); var url = sui.specSelectors.url();
url = deauthUrl(oldAuth, url) || url; url = deauthUrl(loggedOut, url) || url;
sui.specActions.download(url); sui.specActions.download(url);
} }
if (persistAuth) {
localStorage.setItem("drf-yasg-auth", JSON.stringify(savedAuth.toJSON()));
} }
originalLogout(authorization); originalLogout(authorization);
}; };