3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Playframework+axiosによるPOSTするときの注意点(CSRFTokenとlist)

Posted at

PlayFramework(twirl)によるform

PlayFrameworkにはtwirlというテンプレートエンジンが用意されている。

hoge.scala.html
@helper.form(action="/hoge/huga",Symbol("id")->"form1") {
@CSRF.formfield
@helper.inputText(nankanoForm("nanika"),Symbol("id")->"text1",Symbol("placeholder")->"field")
<input type="submit">
}

このようなテンプレートからレンダリングされたhtmlでsubmitすれば入力したデータが
GET/POSTされ用意したnankanoformのcase classなどで受け取ることが出来るが、
クライアント側でajaxリクエストを行うといくつか問題が発生する。

CSRF対策(POST時)

PlayframeworkではCSRFfilterを有効にするとRequestにCSRFTokenが設定されてないものは不正リクエストとして弾く。

上記テンプレートのように@CSRF.formfield
@helper.formのブロック内部に追加することでCSRFfilterの認証を通すことができる。
しかし単純にformの値を取ってきてPOSTをすると、
CSRFTokenが見つからないためにリクエストエラーになってしまう。

PlayFrameworkではFormDataとしてcsrfTokenを含めるという方法を取っている。
上記のテンプレートをレンダリングした結果としてhoge.htmlがクライアント側で表示される。

hoge.html
<form action="hoge/huga" method=POST id="form1">
<input name="csrfToken" value="123...">
<input type="text" name="nanika" id="text1" placeholder="field">
<input type="submit">
</form>

このform内のcsrfTokenの値を取得してPOSTする。


const params = new URLSearchParams()

const csrfToken= document.getElementsByName("csrfToken")[0].value
const text = document.getElementById("text1").value

params.append("csrfToken",csrfToken)
params.append("text1",text)

axios.post("/hoge/huga",params)

一応こういう感じにcsrfTokenに対応させる形で送ると普通にsubmitしたのと同じようにリクエストが通る(もっといい書き方がある気もする)。

上記の方法を取らなくてもapplication.confにsession.sameSite = "lax"と設定してCSRFfilterをfalseにしたり、
routesを以下のようにしてもいいと思う。

+nocsrf
POST /hoge/huga 

他にもplay.filters.csrf.header.bypassHeadersに色々設定して認証を回避したりもできる。
https://www.playframework.com/documentation/2.8.x/ScalaCsrf

listのPOST

formの定義時にlist(number)という風にするとList[Int]みたいな感じで受け取れる。
例えばboxes -> list(number)みたいな感じにするとhtmlではname=boxes[]でinput要素が生成される。
これをPOSTする際には下記のようにする必要がある。


Array.from(document.getElementsByName("boxes[]"))
     .filter(e => e.checked)
     .map(e => e.value)
     .forEach(v => params.append("boxes[]",v))

配列としてappendするのではなく、各要素の値をappendしなければformのcase classへの変換が上手くいかないので注意。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?