Jenkins 订书机请求失败,没有有效的碎屑
Jenkins stapler requests fail with no valid crumb
我正在开发一个 Jenkins 插件,但我现在遇到了一个问题,我正在尝试使用 JavaScript 代理获取方法的 return 值 JavaScript here.
我只想调用这个 kotlin 方法:
@JavaScriptMethod
fun getMonitoredJobsAsJSON(): JSONArray = toJSON(getObjectMapper().writeValueAsString(getMonitoredJobs())) as JSONArray
来自果冻脚本使用这个:
<script>
var board = <st:bind value="${it}"/>
board.getMonitoredJobsAsJSON(function(data) {
//
})
</script>
当我在 Jenkins 服务器上禁用 CSRF 保护时,这实际上有效,但我显然不想这样做。启用 CSRF 保护后,我总是会收到“未找到有效面包屑”403 错误:
POST http://localhost:8080/$stapler/bound/36dc05fc-c12d-4182-a008-60bcf5c49307/getMonitoredJobsAsJSON 403 (No valid crumb was included in the request)
我知道如何从 crumbIssuer
端点检索面包屑以与 Jenkins rest 交互 api 但我几乎没有找到关于如何使其适用于插件中订书机请求的资源.
此外,当我检查请求时,实际上在请求中设置了碎屑 header:
在此先感谢您的帮助。
几周后,我终于找到了解决办法。
问题在于,由于某种原因,默认情况下附加到请求的 crumb header 的名称实际上是错误的。如我问题中的屏幕截图所示,它是 Crumb
,但对于旧版本的 Jenkins,它实际上应该是 Jenkins-Crumb
或 .crumb
。
我所做的是找到一种方法来在页面最初加载时从服务器检索面包屑 和正确的 header 名称 ,然后附加此crumb header 对任何后续 xhr 请求使用正确的名称。
我为面包屑定义了一个实体:
class RemoteRequestCrumb {
@JsonIgnore private val crumbIssuer: CrumbIssuer? = Jenkins.getInstance()?.getCrumbIssuer()
val fieldName: String? = crumbIssuer?.crumbRequestField
val crumbValue: String? = crumbIssuer?.crumb
}
然后将此实体作为属性添加到插件中:
fun getRemoteRequestCrumb(): JSONObject = toJSON(
SerializationUtils.getObjectWriter().writeValueAsString(RemoteRequestCrumb())
) as JSONObject
现在您可以像使用任何其他插件属性一样从 jelly 脚本请求面包屑数据:${it.getRemoteRequestCrumb()}
。
最后一步实际上是将正确的 header 附加到所有 XHR 请求:
appendCrumbHeaderToAllRequests: function () {
let crumb = JSON.parse(this.remoteRequestCrumb);
let open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function() {
let mutatedPrototype = open.apply(this, arguments);
this.setRequestHeader(crumb.fieldName, crumb.crumbValue);
return mutatedPrototype;
}
}
我正在开发一个 Jenkins 插件,但我现在遇到了一个问题,我正在尝试使用 JavaScript 代理获取方法的 return 值 JavaScript here.
我只想调用这个 kotlin 方法:
@JavaScriptMethod
fun getMonitoredJobsAsJSON(): JSONArray = toJSON(getObjectMapper().writeValueAsString(getMonitoredJobs())) as JSONArray
来自果冻脚本使用这个:
<script>
var board = <st:bind value="${it}"/>
board.getMonitoredJobsAsJSON(function(data) {
//
})
</script>
当我在 Jenkins 服务器上禁用 CSRF 保护时,这实际上有效,但我显然不想这样做。启用 CSRF 保护后,我总是会收到“未找到有效面包屑”403 错误:
POST http://localhost:8080/$stapler/bound/36dc05fc-c12d-4182-a008-60bcf5c49307/getMonitoredJobsAsJSON 403 (No valid crumb was included in the request)
我知道如何从 crumbIssuer
端点检索面包屑以与 Jenkins rest 交互 api 但我几乎没有找到关于如何使其适用于插件中订书机请求的资源.
此外,当我检查请求时,实际上在请求中设置了碎屑 header:
在此先感谢您的帮助。
几周后,我终于找到了解决办法。
问题在于,由于某种原因,默认情况下附加到请求的 crumb header 的名称实际上是错误的。如我问题中的屏幕截图所示,它是 Crumb
,但对于旧版本的 Jenkins,它实际上应该是 Jenkins-Crumb
或 .crumb
。
我所做的是找到一种方法来在页面最初加载时从服务器检索面包屑 和正确的 header 名称 ,然后附加此crumb header 对任何后续 xhr 请求使用正确的名称。
我为面包屑定义了一个实体:
class RemoteRequestCrumb {
@JsonIgnore private val crumbIssuer: CrumbIssuer? = Jenkins.getInstance()?.getCrumbIssuer()
val fieldName: String? = crumbIssuer?.crumbRequestField
val crumbValue: String? = crumbIssuer?.crumb
}
然后将此实体作为属性添加到插件中:
fun getRemoteRequestCrumb(): JSONObject = toJSON(
SerializationUtils.getObjectWriter().writeValueAsString(RemoteRequestCrumb())
) as JSONObject
现在您可以像使用任何其他插件属性一样从 jelly 脚本请求面包屑数据:${it.getRemoteRequestCrumb()}
。
最后一步实际上是将正确的 header 附加到所有 XHR 请求:
appendCrumbHeaderToAllRequests: function () {
let crumb = JSON.parse(this.remoteRequestCrumb);
let open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function() {
let mutatedPrototype = open.apply(this, arguments);
this.setRequestHeader(crumb.fieldName, crumb.crumbValue);
return mutatedPrototype;
}
}