场景:微服务系统中使用oauth2 的 Bearer 方式鉴权,对于from提交的数据,无法鉴权,百度的富文本编辑器 ueditor 中上传图片都是使用form 伪ajax提交,导致401
因为from提交无法设置header

解决方式:
1、修改百度富文本编辑器的源码ueditor.all.min.js,在调用上传图片方法的时候,加入额外参数
/**
* 获取服务器提交的额外参数列表
* @command serverparam
* @method queryCommandValue
* @param { String } cmd 命令字符串
* @example
* ```javascript
* editor.queryCommandValue( 'serverparam' ); //返回对象 {'key': 'value'}
* ```
*/
'serverparam': {
execCommand: function (cmd, key, value) {
if (key === undefined || key === null) { //不传参数,清空列表
serverParam = {};
} else if (utils.isString(key)) { //传入键值
if (value === undefined || value === null) {
delete serverParam[key];
} else {
serverParam[key] = value;
}
} else if (utils.isObject(key)) { //传入对象,覆盖列表项
utils.extend(serverParam, key, true);
} else if (utils.isFunction(key)) { //传入函数,添加列表项
utils.extend(serverParam, key(), true);
}
},
queryCommandValue: function () {
if(!serverParam){
serverParam={};
}
//修改的地方
var accessToken=JSON.parse(window.sessionStorage.getItem("pigx-access_token")).content;
var token = accessToken || '';
serverParam['_authorization']= token;
serverParam['_domain']= window.location.host;
console.log(serverParam)
return serverParam || {};
}
}
2、还有修改doAjax方法
function doAjax(url, ajaxOptions) {
var xhr = creatAjaxRequest(),
//是否超时
timeIsOut = false,
//默认参数
defaultAjaxOptions = {
method: "POST",
timeout: 5000,
async: true,
data: {},//需要传递对象的话只能覆盖
onsuccess: function () {
},
onerror: function () {
}
};
if (typeof url === "object") {
ajaxOptions = url;
url = ajaxOptions.url;
}
if (!xhr || !url) return;
var ajaxOpts = ajaxOptions ? utils.extend(defaultAjaxOptions, ajaxOptions) : defaultAjaxOptions;
var submitStr = json2str(ajaxOpts); // { name:"Jim",city:"Beijing" } --> "name=Jim&city=Beijing"
//如果用户直接通过data参数传递json对象过来,则也要将此json对象转化为字符串
if (!utils.isEmptyObject(ajaxOpts.data)) {
submitStr += (submitStr ? "&" : "") + json2str(ajaxOpts.data);
}
//超时检测
var timerID = setTimeout(function () {
if (xhr.readyState != 4) {
timeIsOut = true;
xhr.abort();
clearTimeout(timerID);
}
}, ajaxOpts.timeout);
var method = ajaxOpts.method.toUpperCase();
var str = url + (url.indexOf("?") == -1 ? "?" : "&") + (method == "POST" ? "" : submitStr + "&noCache=" + +new Date);
xhr.open(method, str, ajaxOpts.async);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (!timeIsOut && xhr.status == 200) {
ajaxOpts.onsuccess(xhr);
} else {
ajaxOpts.onerror(xhr);
}
}
};
//修改的地方
var accessToken=JSON.parse(window.sessionStorage.getItem("pigx-access_token")).content;
var token = accessToken || '';
xhr.setRequestHeader('Authorization', 'Bearer '+token);
xhr.setRequestHeader('X-DOMAIN', window.location.host);
if (method == "POST") {
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send(submitStr);
} else {
xhr.send(null);
}
}
3、修改复制的图片自动上传的方法
/**
* @description
* 1.拖放文件到编辑区域,自动上传并插入到选区
* 2.插入粘贴板的图片,自动上传并插入到选区
* @author Jinqn
* @date 2013-10-14
*/
UE.plugin.register('autoupload', function () {
function sendAndInsertFile(file, editor) {
var me = editor;
//模拟数据
var fieldName, urlPrefix, maxSize, allowFiles, actionUrl,
loadingHtml, errorHandler, successHandler,
filetype = /image\/\w+/i.test(file.type) ? 'image' : 'file',
loadingId = 'loading_' + (+new Date()).toString(36);
fieldName = me.getOpt(filetype + 'FieldName');
urlPrefix = me.getOpt(filetype + 'UrlPrefix');
maxSize = me.getOpt(filetype + 'MaxSize');
allowFiles = me.getOpt(filetype + 'AllowFiles');
actionUrl = me.getActionUrl(me.getOpt(filetype + 'ActionName'));
errorHandler = function (title) {
var loader = me.document.getElementById(loadingId);
loader && domUtils.remove(loader);
me.fireEvent('showmessage', {
'id': loadingId,
'content': title,
'type': 'error',
'timeout': 4000
});
};
if (filetype == 'image') {
loadingHtml = '<img class="loadingclass" id="' + loadingId + '" src="' +
me.options.themePath + me.options.theme +
'/images/spacer.gif" title="' + (me.getLang('autoupload.loading') || '') + '" >';
successHandler = function (data) {
var link = urlPrefix + data.url,
loader = me.document.getElementById(loadingId);
if (loader) {
loader.setAttribute('src', link);
loader.setAttribute('_src', link);
loader.setAttribute('title', data.title || '');
loader.setAttribute('alt', data.original || '');
loader.removeAttribute('id');
domUtils.removeClasses(loader, 'loadingclass');
}
};
} else {
loadingHtml = '<p>' +
'<img class="loadingclass" id="' + loadingId + '" src="' +
me.options.themePath + me.options.theme +
'/images/spacer.gif" title="' + (me.getLang('autoupload.loading') || '') + '" >' +
'</p>';
successHandler = function (data) {
var link = urlPrefix + data.url,
loader = me.document.getElementById(loadingId);
var rng = me.selection.getRange(),
bk = rng.createBookmark();
rng.selectNode(loader).select();
me.execCommand('insertfile', {'url': link});
rng.moveToBookmark(bk).select();
};
}
/* 插入loading的占位符 */
me.execCommand('inserthtml', loadingHtml);
/* 判断后端配置是否没有加载成功 */
if (!me.getOpt(filetype + 'ActionName')) {
errorHandler(me.getLang('autoupload.errorLoadConfig'));
return;
}
/* 判断文件大小是否超出限制 */
if (file.size > maxSize) {
errorHandler(me.getLang('autoupload.exceedSizeError'));
return;
}
/* 判断文件格式是否超出允许 */
var fileext = file.name ? file.name.substr(file.name.lastIndexOf('.')) : '';
if ((fileext && filetype != 'image') || (allowFiles && (allowFiles.join('') + '.').indexOf(fileext.toLowerCase() + '.') == -1)) {
errorHandler(me.getLang('autoupload.exceedTypeError'));
return;
}
/* 创建Ajax并提交 */
var xhr = new XMLHttpRequest(),
fd = new FormData(),
params = utils.serializeParam(me.queryCommandValue('serverparam')) || '',
url = utils.formatUrl(actionUrl + (actionUrl.indexOf('?') == -1 ? '?' : '&') + params);
fd.append(fieldName, file, file.name || ('blob.' + file.type.substr('image/'.length)));
fd.append('type', 'ajax');
xhr.open("post", url, true);
var accessToken=JSON.parse(window.sessionStorage.getItem("pigx-access_token")).content;
var token = accessToken || '';
xhr.setRequestHeader('Authorization', 'Bearer '+token);
xhr.setRequestHeader('X-DOMAIN', window.location.host);
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
xhr.addEventListener('load', function (e) {
try {
var json = (new Function("return " + utils.trim(e.target.response)))();
if (json.state == 'SUCCESS' && json.url) {
successHandler(json);
} else {
errorHandler(json.state);
}
} catch (er) {
errorHandler(me.getLang('autoupload.loadError'));
}
});
xhr.send(fd);
}
4、在后台的过滤器中进行处理,针对接收到的额外参数,
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//百度编辑器,上传图片时会使用form提交,无法设置header,so,修改如下代码
if(((HttpServletRequest) request).getRequestURI().contains("ueditorConfig") && StringUtils.isNotBlank(request.getParameter("_authorization")))
{
HttpHeaderRequestWrapper httpHeaderRequestWrapper = new HttpHeaderRequestWrapper((HttpServletRequest) request
, request.getParameter("_authorization")
,request.getParameter("_domain"));
//this.setDomain(httpHeaderRequestWrapper, (HttpServletResponse) response);
chain.doFilter(httpHeaderRequestWrapper, response);
}
else{
//this.setDomain((HttpServletRequest)request,(HttpServletResponse)response);
chain.doFilter(request,response);
}
//请求完成还原线程变量的值
log.info("还原线程变量中的值");
//HostThreadLocalConstant.getDomian().set("");
}
5、重写 getHeaders 方法
private static class HttpHeaderRequestWrapper extends HttpServletRequestWrapper{
private final String domain;
private final String authorization;
public HttpHeaderRequestWrapper(HttpServletRequest request,String authorization,String domain) {
super(request);
this.domain=domain;
this.authorization="Bearer "+authorization;
}
@Override
public String getHeader(String name) {
if (name!=null &&
name.equals("X-DOMAIN") &&
super.getHeader("X-DOMAIN")==null) {
return domain;
}else if (name!=null &&
name.equals("Authorization") &&
super.getHeader("Authorization")==null) {
return authorization;
}else {
return super.getHeader(name);
}
}
@Override
public Enumeration<String> getHeaders(String name) {
List<String> values = Collections.list(super.getHeaders(name));
if (name!=null && name.equals("Authorization") ) {
values.add(authorization);
}
return Collections.enumeration(values);
}
}
