问题
I'm working on a Jenkins plugin and I'm now stuck at a point where I'm trying to get the return value of a method using a JavaScript proxy as described here.
I simply want to call this kotlin method:
@JavaScriptMethod
fun getMonitoredJobsAsJSON(): JSONArray = toJSON(getObjectMapper().writeValueAsString(getMonitoredJobs())) as JSONArray
From the jelly script using this:
<script>
var board = <st:bind value="${it}"/>
board.getMonitoredJobsAsJSON(function(data) {
//
})
</script>
This actually works when I disable CSRF protection on the Jenkins server but I obviously don't want to do that. With CSRF protection on I always get a no valid crumb found 403 error:
POST http://localhost:8080/$stapler/bound/36dc05fc-c12d-4182-a008-60bcf5c49307/getMonitoredJobsAsJSON 403 (No valid crumb was included in the request)
I know how to retrieve crumbs from the crumbIssuer
end point for interacting with the Jenkins rest api but I've found virtually no resources on how to make it work for stapler requests in plugins.
Also, when I inspect the requests, a crumb header is actually set in the request:
Thanks in advance for any help.
回答1:
Weeks later, I finally found a solution to this.
The problem was that for some reason, the name of the crumb header appended to the requests by default is actually wrong. It's Crumb
as shown in the screenshot in my question, but it actually should be Jenkins-Crumb
or .crumb
for older versions of Jenkins.
What I did was to find a way to retrieve a crumb and the correct header name from the server when the page is loading initially, and then append this crumb header using the correct name to any subsequent xhr requests.
I defined an entity for the crumbs:
class RemoteRequestCrumb {
@JsonIgnore private val crumbIssuer: CrumbIssuer? = Jenkins.getInstance()?.getCrumbIssuer()
val fieldName: String? = crumbIssuer?.crumbRequestField
val crumbValue: String? = crumbIssuer?.crumb
}
And then add this entity to the plugin as an attribute:
fun getRemoteRequestCrumb(): JSONObject = toJSON(
SerializationUtils.getObjectWriter().writeValueAsString(RemoteRequestCrumb())
) as JSONObject
Now you can request the crumb data from a jelly script as with any other plugin attribute: ${it.getRemoteRequestCrumb()}
.
The last step is actually appending the correct header to all XHR requests:
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;
}
}
来源:https://stackoverflow.com/questions/56983333/jenkins-stapler-requests-fail-with-no-valid-crumb