Add swagger-ui auth hooks
Save authorization to local storage, refetch spec on auth, etc.master
parent
d41f0c5ac4
commit
a419eec071
|
|
@ -27,12 +27,14 @@
|
|||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3 (drf-yasg)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="immutable" level="application" />
|
||||
</component>
|
||||
<component name="TemplatesService">
|
||||
<option name="TEMPLATE_CONFIGURATION" value="Django" />
|
||||
<option name="TEMPLATE_FOLDERS">
|
||||
<list>
|
||||
<option value="$MODULE_DIR$/src/drf_yasg/templates" />
|
||||
<option value="$MODULE_DIR$/testproj/testproj/templates" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JavaScriptLibraryMappings">
|
||||
<file url="file://$PROJECT_DIR$" libraries="{immutable}" />
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -33,7 +33,7 @@ SWAGGER_DEFAULTS = {
|
|||
|
||||
'USE_SESSION_AUTH': True,
|
||||
'SECURITY_DEFINITIONS': {
|
||||
'basic': {
|
||||
'Basic': {
|
||||
'type': 'basic'
|
||||
}
|
||||
},
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
|
@ -1,36 +1,14 @@
|
|||
"use strict";
|
||||
var currentPath = window.location.protocol + "//" + window.location.host + window.location.pathname;
|
||||
var specURL = currentPath + '?format=openapi';
|
||||
|
||||
function patchSwaggerUi() {
|
||||
var authWrapper = document.querySelector('.auth-wrapper');
|
||||
var authorizeButton = document.querySelector('.auth-wrapper .authorize');
|
||||
var djangoSessionAuth = document.querySelector('#django-session-auth');
|
||||
if (!djangoSessionAuth) {
|
||||
console.log("WARNING: session auth disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
if (document.querySelector('.auth-wrapper #django-session-auth')) {
|
||||
console.log("WARNING: session auth already patched; skipping patchSwaggerUi()");
|
||||
return;
|
||||
}
|
||||
|
||||
authWrapper.insertBefore(djangoSessionAuth, authorizeButton);
|
||||
djangoSessionAuth.classList.remove("hidden");
|
||||
|
||||
var divider = document.createElement("div");
|
||||
divider.classList.add("divider");
|
||||
authWrapper.insertBefore(divider, authorizeButton);
|
||||
var defaultSpecUrl = currentPath + '?format=openapi';
|
||||
var savedAuth = Immutable.fromJS({});
|
||||
try {
|
||||
savedAuth = Immutable.fromJS(JSON.parse(localStorage.getItem("drf-yasg-auth")) || {});
|
||||
} catch (e) {
|
||||
localStorage.removeItem("drf-yasg-auth");
|
||||
}
|
||||
|
||||
function initSwaggerUi() {
|
||||
if (window.ui) {
|
||||
console.log("WARNING: skipping initSwaggerUi() because window.ui is already defined");
|
||||
return;
|
||||
}
|
||||
var swaggerConfig = {
|
||||
url: specURL,
|
||||
var swaggerUiConfig = {
|
||||
url: defaultSpecUrl,
|
||||
dom_id: '#swagger-ui',
|
||||
displayRequestDuration: true,
|
||||
presets: [
|
||||
|
|
@ -48,9 +26,42 @@ function initSwaggerUi() {
|
|||
if (csrftoken) {
|
||||
headers["X-CSRFToken"] = csrftoken.value;
|
||||
}
|
||||
return request;
|
||||
|
||||
if (request.loadSpec) {
|
||||
applyAuth(savedAuth, headers);
|
||||
}
|
||||
return request;
|
||||
},
|
||||
onComplete: function () {
|
||||
preauthorizeAny(savedAuth, window.ui);
|
||||
hookAuthActions(window.ui);
|
||||
},
|
||||
};
|
||||
|
||||
function patchSwaggerUi() {
|
||||
if (document.querySelector('.auth-wrapper #django-session-auth')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var authWrapper = document.querySelector('.auth-wrapper');
|
||||
var authorizeButton = document.querySelector('.auth-wrapper .authorize');
|
||||
var djangoSessionAuth = document.querySelector('#django-session-auth');
|
||||
|
||||
if (!djangoSessionAuth) {
|
||||
console.log("WARNING: session auth disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
djangoSessionAuth = djangoSessionAuth.cloneNode(true);
|
||||
authWrapper.insertBefore(djangoSessionAuth, authorizeButton);
|
||||
djangoSessionAuth.classList.remove("hidden");
|
||||
}
|
||||
|
||||
function initSwaggerUi() {
|
||||
if (window.ui) {
|
||||
console.log("WARNING: skipping initSwaggerUi() because window.ui is already defined");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
var swaggerSettings = JSON.parse(document.getElementById('swagger-settings').innerHTML);
|
||||
if (!('oauth2RedirectUrl' in swaggerSettings)) {
|
||||
|
|
@ -64,23 +75,82 @@ function initSwaggerUi() {
|
|||
console.log('swaggerSettings', swaggerSettings);
|
||||
for (var p in swaggerSettings) {
|
||||
if (swaggerSettings.hasOwnProperty(p)) {
|
||||
swaggerConfig[p] = swaggerSettings[p];
|
||||
swaggerUiConfig[p] = swaggerSettings[p];
|
||||
}
|
||||
}
|
||||
window.ui = SwaggerUIBundle(swaggerConfig);
|
||||
|
||||
var oauth2Config = JSON.parse(document.getElementById('oauth2-config').innerHTML);
|
||||
console.log('oauth2Config', oauth2Config);
|
||||
window.ui = SwaggerUIBundle(swaggerUiConfig);
|
||||
window.ui.initOAuth(oauth2Config);
|
||||
}
|
||||
|
||||
window.onload = function () {
|
||||
initSwaggerUi();
|
||||
};
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (document.querySelector('.auth-wrapper .authorize')) {
|
||||
function applyAuth(savedAuth, requestHeaders) {
|
||||
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) {
|
||||
requestHeaders["Authorization"] = "Basic " + btoa(username + ":" + password);
|
||||
}
|
||||
} else if (schemeType === "apiKey" && schemeName) {
|
||||
var key = savedAuth.get("value"), _in = savedAuth.getIn(["schema", "in"]);
|
||||
var paramName = savedAuth.getIn(["schema", "name"]);
|
||||
if (key && paramName && _in === "header") {
|
||||
requestHeaders[paramName] = key;
|
||||
}
|
||||
if (_in === "query") {
|
||||
console.warn("WARNING: cannot apply apiKey query parameter via interceptor");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function hookAuthActions(sui) {
|
||||
var originalAuthorize = sui.authActions.authorize;
|
||||
sui.authActions.authorize = function (authorization) {
|
||||
originalAuthorize(authorization);
|
||||
// authorization is map of scheme name to scheme object
|
||||
// need to use ImmutableJS because schema is already an ImmutableJS object
|
||||
var schemes = Immutable.fromJS(authorization);
|
||||
var auth = schemes.valueSeq().first();
|
||||
localStorage.setItem("drf-yasg-auth", JSON.stringify(auth.toJSON()));
|
||||
savedAuth = auth;
|
||||
sui.specActions.download();
|
||||
};
|
||||
|
||||
var originalLogout = sui.authActions.logout;
|
||||
sui.authActions.logout = function (authorization) {
|
||||
if (savedAuth.get("name") === authorization[0]) {
|
||||
localStorage.removeItem("drf-yasg-auth");
|
||||
savedAuth = Immutable.fromJS({});
|
||||
}
|
||||
originalLogout(authorization);
|
||||
};
|
||||
}
|
||||
|
||||
window.addEventListener('load', function () {
|
||||
initSwaggerUi();
|
||||
|
||||
if (document.querySelector('.auth-wrapper .authorize')) {
|
||||
patchSwaggerUi();
|
||||
}
|
||||
else {
|
||||
}
|
||||
else {
|
||||
insertionQ('.auth-wrapper .authorize').every(patchSwaggerUi);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
<script src="{% static 'drf-yasg/swagger-ui-dist/swagger-ui-bundle.js' %}"></script>
|
||||
<script src="{% static 'drf-yasg/swagger-ui-dist/swagger-ui-standalone-preset.js' %}"></script>
|
||||
<script src="{% static 'drf-yasg/insQ.min.js' %}"></script>
|
||||
<script src="{% static 'drf-yasg/immutable.js' %}"></script>
|
||||
<script src="{% static 'drf-yasg/swagger-ui-init.js' %}"></script>
|
||||
{% block extra_scripts %}
|
||||
{# -- Add any additional scripts here -- #}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ ROOT_URLCONF = 'testproj.urls'
|
|||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [],
|
||||
'DIRS': [os.path.join(BASE_DIR, 'testproj', 'templates')],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
|
|
@ -132,6 +132,9 @@ USE_TZ = True
|
|||
|
||||
STATIC_URL = '/static/'
|
||||
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
|
||||
STATICFILES_DIRS = [
|
||||
os.path.join(BASE_DIR, 'testproj', 'static'),
|
||||
]
|
||||
|
||||
# Testing
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ wget https://rebilly.github.io/ReDoc/releases/v1.x.x/redoc.min.js -O src/drf_yas
|
|||
|
||||
cp -r node_modules/swagger-ui-dist src/drf_yasg/static/drf-yasg/
|
||||
pushd src/drf_yasg/static/drf-yasg/swagger-ui-dist/ >/dev/null
|
||||
rm -f swagger-ui.js
|
||||
rm -f package.json .npmignore README.md
|
||||
rm -f index.html *.map
|
||||
popd >/dev/null
|
||||
|
|
|
|||
Loading…
Reference in New Issue