admin管理员组文章数量:1386760
$(window).on('unload', function() {
db.flipCounter.get(gon.slug, function(obj) {
var payload = {
slug: gon.slug,
localFlipCount: obj.fc,
time: Date.now()
}
navigator.sendBeacon('/analytics', csrfProtect(payload))
})
})
function csrfProtect(payload) {
var param = $("meta[name=csrf-param]").attr("content")
var token = $("meta[name=csrf-token]").attr("content")
if (param && token) payload[param] = token
return new Blob([JSON.stringify(payload)], { type: "application/x-www-form-urlencoded; charset=utf-8" })
}
In the code above I wish to hit POST to the '/analytics' url with the payload. I get the following error(warning) upon… attempting to fire a request:
Promise.js:840 Unhandled rejection: TypeError: Cannot create property 'authenticity_token' on string '{"slug":"test-page-by-marvin-danig","localFlipCount":1,"time":1524241435403}'
Hm.
…firing a request, I get:
Processing by BooksController#analytics as */*
Parameters: {"{\"slug\":\"test-book-by-marvin-danig\",\"localFlipCount\":1,\"time\":1524243279653,\"param\":\"8rzDx/TNL8YeU1/NWgWSk6gB/UvmbB9Ip VajDCgfDUv5Q4pjh7x0GUG1il1jDJajtJyHf84Xv5Pt14fiCnA9w"=>"=\"}"}
Can't verify CSRF token authenticity.
exception
ActionController::InvalidAuthenticityToken
UPDATE: The issue isn't resolved still. Here's where I am at right now:
I have the following GET & POST routes open on my routes.rb
:
# Analytics (flipCounter)
get 'auth_token', to: 'analytics#auth_token'
post 'receptor', to: 'analytics#receptor', as: :receptor
These obviously map to the analytics_controller
like so:
class AnalyticsController < ApplicationController
respond_to :js
def auth_token
session[:_csrf_token] = form_authenticity_token
end
def receptor
logger.debug "Check book slug first: #{params}"
begin
book = Book.friendly.find(params[:slug])
rescue ActiveRecord::RecordNotFound => e
book = nil
end
if book.exists?
book.flipcount += params[:flipcount].to_i
end
end
private
end
Alongside the auth_token
method, I got an auth_token.json.erb
template that is shipped per following:
{ "authenticity_token": "<%= session[:_csrf_token] %>" }
And the client side javascript (poor draft) goes the following way:
// When state of book changes to `not_flipping`:
flipCount += 1
const o = { slug: gon.slug, fc: flipCount }
// IndexedDb initiated elsewhere.
db.transaction('rw', db.flipCounter, function(e) {
db.flipCounter.put(o)
}).then(function(e) {
const URL = '/auth_token' // First fetch the authenticity_token!
fetch(URL, {
method: 'GET'
}).then(function(res) {
return res.json()
}).then(function(token) {
return postBookData(token)
}).catch(err => console.log(err))
}).catch(function(e) {
console.log(e)
})
function postBookData(token) {
db.flipCounter.get(gon.slug, function(obj) {
// var payload = new FormData()
// payload.append('slug', gon.slug)
// payload.append('localFlipCount', obj.fc)
// payload.append('authenticity_token', token.authenticity_token)
// payload.append('type', 'application/x-www-form-urlencoded;')
// payload.append('charset=utf-8', 'ok')
// payload.append('X-CSRF-Token', token.authenticity_token)
//var payload = { 'slug': gon.slug }
let body = {
slug: gon.slug,
flipcount: obj.fc,
time: Date.now()
}
let headers = {
type: 'application/x-www-form-urlencoded; charset=utf-8',
'X-CSRF-Token': token.authenticity_token
}
let blob = new Blob([JSON.stringify(body)], headers);
let url = '/receptor'
navigator.sendBeacon(url, blob);
}).then(function() {
flipCount = 0
var o = { slug: gon.slug, fc: flipCount }
}).catch(err => console.log(err))
}
The request object fired by the navigator.sendBeacon
isn't correct because the X-CSRF-Token
isn't set and I obviously get the following error on the server side:
Started POST "/receptor" for 127.0.0.1 at 2018-04-26 09:00:33 -0400
Processing by AnalyticsController#receptor as */*
Parameters: {"{\"slug\":\"bookiza-documentation-by-marvin-danig\",\"fc\":1}"=>nil}
Can't verify CSRF token authenticity.
exception
ActionController::InvalidAuthenticityToken
Rendering public/500.html
Rendered public/500.html (1.0ms)
Completed 500 Internal Server Error in 337ms (Views: 335.8ms | ActiveRecord: 0.0ms)
Has anyone implemented a navigator.sendBeacon
scenario on a Rails app over a pletely offlined page using service workers?
$(window).on('unload', function() {
db.flipCounter.get(gon.slug, function(obj) {
var payload = {
slug: gon.slug,
localFlipCount: obj.fc,
time: Date.now()
}
navigator.sendBeacon('/analytics', csrfProtect(payload))
})
})
function csrfProtect(payload) {
var param = $("meta[name=csrf-param]").attr("content")
var token = $("meta[name=csrf-token]").attr("content")
if (param && token) payload[param] = token
return new Blob([JSON.stringify(payload)], { type: "application/x-www-form-urlencoded; charset=utf-8" })
}
In the code above I wish to hit POST to the '/analytics' url with the payload. I get the following error(warning) upon… attempting to fire a request:
Promise.js:840 Unhandled rejection: TypeError: Cannot create property 'authenticity_token' on string '{"slug":"test-page-by-marvin-danig","localFlipCount":1,"time":1524241435403}'
Hm.
…firing a request, I get:
Processing by BooksController#analytics as */*
Parameters: {"{\"slug\":\"test-book-by-marvin-danig\",\"localFlipCount\":1,\"time\":1524243279653,\"param\":\"8rzDx/TNL8YeU1/NWgWSk6gB/UvmbB9Ip VajDCgfDUv5Q4pjh7x0GUG1il1jDJajtJyHf84Xv5Pt14fiCnA9w"=>"=\"}"}
Can't verify CSRF token authenticity.
exception
ActionController::InvalidAuthenticityToken
UPDATE: The issue isn't resolved still. Here's where I am at right now:
I have the following GET & POST routes open on my routes.rb
:
# Analytics (flipCounter)
get 'auth_token', to: 'analytics#auth_token'
post 'receptor', to: 'analytics#receptor', as: :receptor
These obviously map to the analytics_controller
like so:
class AnalyticsController < ApplicationController
respond_to :js
def auth_token
session[:_csrf_token] = form_authenticity_token
end
def receptor
logger.debug "Check book slug first: #{params}"
begin
book = Book.friendly.find(params[:slug])
rescue ActiveRecord::RecordNotFound => e
book = nil
end
if book.exists?
book.flipcount += params[:flipcount].to_i
end
end
private
end
Alongside the auth_token
method, I got an auth_token.json.erb
template that is shipped per following:
{ "authenticity_token": "<%= session[:_csrf_token] %>" }
And the client side javascript (poor draft) goes the following way:
// When state of book changes to `not_flipping`:
flipCount += 1
const o = { slug: gon.slug, fc: flipCount }
// IndexedDb initiated elsewhere.
db.transaction('rw', db.flipCounter, function(e) {
db.flipCounter.put(o)
}).then(function(e) {
const URL = '/auth_token' // First fetch the authenticity_token!
fetch(URL, {
method: 'GET'
}).then(function(res) {
return res.json()
}).then(function(token) {
return postBookData(token)
}).catch(err => console.log(err))
}).catch(function(e) {
console.log(e)
})
function postBookData(token) {
db.flipCounter.get(gon.slug, function(obj) {
// var payload = new FormData()
// payload.append('slug', gon.slug)
// payload.append('localFlipCount', obj.fc)
// payload.append('authenticity_token', token.authenticity_token)
// payload.append('type', 'application/x-www-form-urlencoded;')
// payload.append('charset=utf-8', 'ok')
// payload.append('X-CSRF-Token', token.authenticity_token)
//var payload = { 'slug': gon.slug }
let body = {
slug: gon.slug,
flipcount: obj.fc,
time: Date.now()
}
let headers = {
type: 'application/x-www-form-urlencoded; charset=utf-8',
'X-CSRF-Token': token.authenticity_token
}
let blob = new Blob([JSON.stringify(body)], headers);
let url = '/receptor'
navigator.sendBeacon(url, blob);
}).then(function() {
flipCount = 0
var o = { slug: gon.slug, fc: flipCount }
}).catch(err => console.log(err))
}
The request object fired by the navigator.sendBeacon
isn't correct because the X-CSRF-Token
isn't set and I obviously get the following error on the server side:
Started POST "/receptor" for 127.0.0.1 at 2018-04-26 09:00:33 -0400
Processing by AnalyticsController#receptor as */*
Parameters: {"{\"slug\":\"bookiza-documentation-by-marvin-danig\",\"fc\":1}"=>nil}
Can't verify CSRF token authenticity.
exception
ActionController::InvalidAuthenticityToken
Rendering public/500.html
Rendered public/500.html (1.0ms)
Completed 500 Internal Server Error in 337ms (Views: 335.8ms | ActiveRecord: 0.0ms)
Has anyone implemented a navigator.sendBeacon
scenario on a Rails app over a pletely offlined page using service workers?
3 Answers
Reset to default 7Just caught this snag, the js end of my solution is as follows:
window.addEventListener("unload", function() {
var url = "/your_metrics_path",
data = new FormData(),
token = $('meta[name="csrf-token"]').attr('content');
// add your data
data.append("foo", "bar");
// add the auth token
data.append("authenticity_token", token);
// off she goes
navigator.sendBeacon(url, data);
});
Hope this helps.
You're on the right track, and I've successfully done this, grabbing the CSRF token from the DOM and using it in the JavaScript request. Here is an example of what a normal Rails form is sending in the params:
Started PATCH "/titles/25104" for 127.0.0.1 at 2018-04-20 14:19:11 -0700
Processing by TitlesController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"N97wNps0PMEBcqEsza8gNV741uPZNmltPgJHeeBNmTF0rc2KCaePBlZeCxId+su1sdAYMsgyd/78u9S/mdmprw==" }
It looks like you just need to get things into the right hash structure, and you should be on your way. I think you need to adjust some keys.
I just learned that it isn't possible to customize the request method, provide custom request headers, or change other processing properties of the request and response when using a Beacon request. See the W3C Editor's Draft for Beacons here.
Use the fetch api instead.
本文标签: javascriptHandling CSRF authenticity token for navigatorsendBeacon requests in railsStack Overflow
版权声明:本文标题:javascript - Handling CSRF authenticity token for navigator.sendBeacon requests in rails - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744540867a2611603.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论