Add swagger-ui auth hooks
Save authorization to local storage, refetch spec on auth, etc.
This commit is contained in:
1 parent
d41f0c5ac4
commit
a419eec071
9 files changed
+5103
-52
No files matched your search
Generated
+2
@@ -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>
|
||||
|
||||
Generated
+6
@@ -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
@@ -1,9 +0,0 @@
|
||||
(function webpackUniversalModuleDefinition(root,factory){if(typeof exports==="object"&&typeof module==="object")module.exports=factory();else if(typeof define==="function"&&define.amd)define([],factory);else if(typeof exports==="object")exports["SwaggerUICore"]=factory();else root["SwaggerUICore"]=factory()})(typeof self!=="undefined"?self:this,function(){return function(modules){var installedModules={};function __webpack_require__(moduleId){if(installedModules[moduleId]){return installedModules[moduleId].exports}var module=installedModules[moduleId]={i:moduleId,l:false,exports:{}};modules[moduleId].call(module.exports,module,module.exports,__webpack_require__);module.l=true;return module.exports}__webpack_require__.m=modules;__webpack_require__.c=installedModules;__webpack_require__.d=function(exports,name,getter){if(!__webpack_require__.o(exports,name)){Object.defineProperty(exports,name,{configurable:false,enumerable:true,get:getter})}};__webpack_require__.n=function(module){var getter=module&&module.__esModule?function getDefault(){return module["default"]}:function getModuleExports(){return module};__webpack_require__.d(getter,"a",getter);return getter};__webpack_require__.o=function(object,property){return Object.prototype.hasOwnProperty.call(object,property)};__webpack_require__.p="/dist";return __webpack_require__(__webpack_require__.s=287)}([function(module,exports){module.exports=require("react")},function(module,exports){module.exports=require("prop-types")},function(module,exports,__webpack_require__){"use strict";exports.__esModule=true;exports.default=function(instance,Constructor){if(!(instance instanceof Constructor)){throw new TypeError("Cannot call a class as a function")}}},function(module,exports,__webpack_require__){"use strict";exports.__esModule=true;var _defineProperty=__webpack_require__(179);var _defineProperty2=_interopRequireDefault(_defineProperty);function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}exports.default=function(){function defineProperties(target,props){for(var i=0;i<props.length;i++){var descriptor=props[i];descriptor.enumerable=descriptor.enumerable||false;descriptor.configurable=true;if("value"in descriptor)descriptor.writable=true;(0,_defineProperty2.default)(target,descriptor.key,descriptor)}}return function(Constructor,protoProps,staticProps){if(protoProps)defineProperties(Constructor.prototype,protoProps);if(staticProps)defineProperties(Constructor,staticProps);return Constructor}}()},function(module,exports,__webpack_require__){module.exports={default:__webpack_require__(530),__esModule:true}},function(module,exports,__webpack_require__){"use strict";exports.__esModule=true;var _typeof2=__webpack_require__(37);var _typeof3=_interopRequireDefault(_typeof2);function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}exports.default=function(self,call){if(!self){throw new ReferenceError("this hasn't been initialised - super() hasn't been called")}return call&&((typeof call==="undefined"?"undefined":(0,_typeof3.default)(call))==="object"||typeof call==="function")?call:self}},function(module,exports,__webpack_require__){"use strict";exports.__esModule=true;var _setPrototypeOf=__webpack_require__(532);var _setPrototypeOf2=_interopRequireDefault(_setPrototypeOf);var _create=__webpack_require__(536);var _create2=_interopRequireDefault(_create);var _typeof2=__webpack_require__(37);var _typeof3=_interopRequireDefault(_typeof2);function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}exports.default=function(subClass,superClass){if(typeof superClass!=="function"&&superClass!==null){throw new TypeError("Super expression must either be null or a function, not "+(typeof superClass==="undefined"?"undefined":(0,_typeof3.default)(superClass)))}subClass.prototype=(0,_create2.default)(superClass&&superClass.prototype,{constructor:{value:subClass,enumerable:false,writable:true,configurable:true}});if(superClass)_setPrototypeOf2.default?(0,_setPrototypeOf2.default)(subClass,superClass):subClass.__proto__=superClass}},function(module,exports){module.exports=require("immutable")},function(module,exports,__webpack_require__){"use strict";(function(Buffer){Object.defineProperty(exports,"__esModule",{value:true});exports.getCommonExtensions=exports.getExtensions=exports.escapeDeepLinkPath=exports.createDeepLinkPath=exports.shallowEqualKeys=exports.buildFormData=exports.sorters=exports.btoa=exports.serializeSearch=exports.parseSearch=exports.getSampleSchema=exports.validateParam=exports.validatePattern=exports.validateMinLength=exports.validateMaxLength=exports.validateGuid=exports.validateDateTime=exports.validateString=exports.validateBoolean=exports.validateFile=exports.validateInteger=exports.validateNumber=exports.validateMinimum=exports.validateMaximum=exports.propChecker=exports.memoize=exports.isImmutable=undefined;var _stringify=__webpack_require__(30);var _stringify2=_interopRequireDefault(_stringiLine truncated
|
||||
/*!
|
||||
* The buffer module from node.js, for the browser.
|
||||
*
|
||||
* @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
|
||||
* @license MIT
|
||||
*/
|
||||
var base64=__webpack_require__(383);var ieee754=__webpack_require__(384);var isArray=__webpack_require__(385);exports.Buffer=Buffer;exports.SlowBuffer=SlowBuffer;exports.INSPECT_MAX_BYTES=50;Buffer.TYPED_ARRAY_SUPPORT=global.TYPED_ARRAY_SUPPORT!==undefined?global.TYPED_ARRAY_SUPPORT:typedArraySupport();exports.kMaxLength=kMaxLength();function typedArraySupport(){try{var arr=new Uint8Array(1);arr.__proto__={__proto__:Uint8Array.prototype,foo:function(){return 42}};return arr.foo()===42&&typeof arr.subarray==="function"&&arr.subarray(1,1).byteLength===0}catch(e){return false}}function kMaxLength(){return Buffer.TYPED_ARRAY_SUPPORT?2147483647:1073741823}function createBuffer(that,length){if(kMaxLength()<length){throw new RangeError("Invalid typed array length")}if(Buffer.TYPED_ARRAY_SUPPORT){that=new Uint8Array(length);that.__proto__=Buffer.prototype}else{if(that===null){that=new Buffer(length)}that.length=length}return that}function Buffer(arg,encodingOrOffset,length){if(!Buffer.TYPED_ARRAY_SUPPORT&&!(this instanceof Buffer)){return new Buffer(arg,encodingOrOffset,length)}if(typeof arg==="number"){if(typeof encodingOrOffset==="string"){throw new Error("If encoding is specified then the first argument must be a string")}return allocUnsafe(this,arg)}return from(this,arg,encodingOrOffset,length)}Buffer.poolSize=8192;Buffer._augment=function(arr){arr.__proto__=Buffer.prototype;return arr};function from(that,value,encodingOrOffset,length){if(typeof value==="number"){throw new TypeError('"value" argument must not be a number')}if(typeof ArrayBuffer!=="undefined"&&value instanceof ArrayBuffer){return fromArrayBuffer(that,value,encodingOrOffset,length)}if(typeof value==="string"){return fromString(that,value,encodingOrOffset)}return fromObject(that,value)}Buffer.from=function(value,encodingOrOffset,length){return from(null,value,encodingOrOffset,length)};if(Buffer.TYPED_ARRAY_SUPPORT){Buffer.prototype.__proto__=Uint8Array.prototype;Buffer.__proto__=Uint8Array;if(typeof Symbol!=="undefined"&&Symbol.species&&Buffer[Symbol.species]===Buffer){Object.defineProperty(Buffer,Symbol.species,{value:null,configurable:true})}}function assertSize(size){if(typeof size!=="number"){throw new TypeError('"size" argument must be a number')}else if(size<0){throw new RangeError('"size" argument must not be negative')}}function alloc(that,size,fill,encoding){assertSize(size);if(size<=0){return createBuffer(that,size)}if(fill!==undefined){return typeof encoding==="string"?createBuffer(that,size).fill(fill,encoding):createBuffer(that,size).fill(fill)}return createBuffer(that,size)}Buffer.alloc=function(size,fill,encoding){return alloc(null,size,fill,encoding)};function allocUnsafe(that,size){assertSize(size);that=createBuffer(that,size<0?0:checked(size)|0);if(!Buffer.TYPED_ARRAY_SUPPORT){for(var i=0;i<size;++i){that[i]=0}}return that}Buffer.allocUnsafe=function(size){return allocUnsafe(null,size)};Buffer.allocUnsafeSlow=function(size){return allocUnsafe(null,size)};function fromString(that,string,encoding){if(typeof encoding!=="string"||encoding===""){encoding="utf8"}if(!Buffer.isEncoding(encoding)){throw new TypeError('"encoding" must be a valid string encoding')}var length=byteLength(string,encoding)|0;that=createBuffer(that,length);var actual=that.write(string,encoding);if(actual!==length){that=that.slice(0,actual)}return that}function fromArrayLike(that,array){var length=array.length<0?0:checked(array.length)|0;that=createBuffer(that,length);for(var i=0;i<length;i+=1){that[i]=array[i]&255}return that}function fromArrayBuffer(that,array,byteOffset,length){array.byteLength;if(byteOffset<0||array.byteLength<byteOffset){throw new RangeError("'offset' is out of bounds")}if(array.byteLength<byteOffset+(length||0)){throw new RangeError("'length' is out of bounds")}if(byteOffset===undefined&&length===undefined){array=new Uint8Array(array)}else if(length===undefined){array=new Uint8Array(array,byteOffset)}else{array=new Uint8Array(array,byteOffset,length)}if(Buffer.TYPED_ARRAY_SUPPORT){that=array;that.__proto__=Buffer.prototype}else{that=fromArrayLike(that,array)}return that}function fromObject(that,obj){if(Buffer.isBuffer(obj)){var len=checked(obj.length)|0;that=createBuffer(that,len);if(that.length===0){return that}obj.copy(that,0,0,len);return that}if(obj){if(typeof ArrayBuffer!=="undefined"&&obj.buffer instanceof ArrayBuffer||"length"in obj){if(typeof obj.length!=="number"||isnan(obj.length)){return createBuffer(that,0)}return fromArrayLike(that,obj)}if(obj.type==="Buffer"&&isArray(obj.data)){return fromArrayLike(that,obj.data)}}throw new TypeError("First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.")}function checked(length){if(length>=kMaxLength()){throw new RangeError("Attempt to allocate Buffer larger than maximum "+"size: 0x"+kMaxLength().toString(16)+" bytes")}return length|0}function SlowBuffer(length){if(+length!=length){length=0}return Buffer.alloc(+length)}Buffer.isBuffer=function isBuffer(b){returnLine truncated
|
||||
//# sourceMappingURL=swagger-ui.js.map
|
||||
@@ -1,27 +1,60 @@
|
||||
"use strict";
|
||||
var currentPath = window.location.protocol + "//" + window.location.host + window.location.pathname;
|
||||
var specURL = currentPath + '?format=openapi';
|
||||
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");
|
||||
}
|
||||
var swaggerUiConfig = {
|
||||
url: defaultSpecUrl,
|
||||
dom_id: '#swagger-ui',
|
||||
displayRequestDuration: true,
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIStandalonePreset
|
||||
],
|
||||
plugins: [
|
||||
SwaggerUIBundle.plugins.DownloadUrl
|
||||
],
|
||||
layout: "StandaloneLayout",
|
||||
filter: true,
|
||||
requestInterceptor: function (request) {
|
||||
var headers = request.headers || {};
|
||||
var csrftoken = document.querySelector("[name=csrfmiddlewaretoken]");
|
||||
if (csrftoken) {
|
||||
headers["X-CSRFToken"] = csrftoken.value;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (document.querySelector('.auth-wrapper #django-session-auth')) {
|
||||
console.log("WARNING: session auth already patched; skipping patchSwaggerUi()");
|
||||
return;
|
||||
}
|
||||
|
||||
djangoSessionAuth = djangoSessionAuth.cloneNode(true);
|
||||
authWrapper.insertBefore(djangoSessionAuth, authorizeButton);
|
||||
djangoSessionAuth.classList.remove("hidden");
|
||||
|
||||
var divider = document.createElement("div");
|
||||
divider.classList.add("divider");
|
||||
authWrapper.insertBefore(divider, authorizeButton);
|
||||
}
|
||||
|
||||
function initSwaggerUi() {
|
||||
@@ -29,28 +62,6 @@ function initSwaggerUi() {
|
||||
console.log("WARNING: skipping initSwaggerUi() because window.ui is already defined");
|
||||
return;
|
||||
}
|
||||
var swaggerConfig = {
|
||||
url: specURL,
|
||||
dom_id: '#swagger-ui',
|
||||
displayRequestDuration: true,
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIStandalonePreset
|
||||
],
|
||||
plugins: [
|
||||
SwaggerUIBundle.plugins.DownloadUrl
|
||||
],
|
||||
layout: "StandaloneLayout",
|
||||
filter: true,
|
||||
requestInterceptor: function (request) {
|
||||
var headers = request.headers || {};
|
||||
var csrftoken = document.querySelector("[name=csrfmiddlewaretoken]");
|
||||
if (csrftoken) {
|
||||
headers["X-CSRFToken"] = csrftoken.value;
|
||||
}
|
||||
return request;
|
||||
}
|
||||
};
|
||||
|
||||
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')) {
|
||||
patchSwaggerUi();
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
insertionQ('.auth-wrapper .authorize').every(patchSwaggerUi);
|
||||
|
||||
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 {
|
||||
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
|
||||
Reference in new issue
Block a user