Previous << Wallet Provider Spec
Next >> Introduction
Overview
Authorization関数とは、トランザクションにおいてどのFlowアカウントがどの署名者の役割を担うのか、また、提供されたアカウントからの署名をどう受け取るのかを、JS-SDKとFCLが把握できるようにする関数です。
How to Use an Authorization Function
承認関数とは、Flow JS-SDKやFCLの承認の代わりに使用できる関数です。承認とは、トランザクションの提案者、支払者、または承認者を指定する際に使用する概念です。承認とは、承認を表すデータ構造か、もしくは呼び出されるとAuthorization Functionと呼ばれる承認を返す関数のことです。このドキュメントでは、後者について説明します。
Authorization Functionの使用の仕方は、Authorization Functionをトランザクションの提案者、支払者、または承認者の認証として指定します。
fcl.currentUser().authorization
は、fcl.authz
にエイリアスされており、それ自体が認証関数です。これは、js-sdkに対し、現在のユーザーのFlowアカウントが署名者として使用されることを通知し、署名関数を提供し、アプリケーションがユーザーのウォレットから署名を要求できるようにします。
Example 1:
import * as fcl from "@onflow/fcl"
const myAuthorizationFunction = ... /* An Authorization Function */
const response = fcl.send([
fcl.transaction`transaction() { prepare(acct: &Account) {} execute { log("Hello, Flow!") } }`,
fcl.proposer(myAuthorizationFunction),
fcl.payer(myAuthorizationFunction),
fcl.authorizers([ myAuthorizationFunction ])
])
ビルダー関数であるfcl.proposer
、fcl.payer
、fcl.authorizations
はそれぞれ、Authorization Functionを消費し、それを、内部のAccountオブジェクト上のそれが作成するresolveフィールドとして、設定します。
Flow JS-SDKとFCLのresolveフェーズにおいて、resolveAccounts
が呼び出されると、各内部Accountオブジェクトのresolveフィールドが呼び出されます。つまり、それぞれ適切にAuthorization Functionが呼び出され、アカウントはauthorizationFunctionが返すデータ構造に解決します。これらのアカウントは、addr
、keyId
、tempId
の組み合わせに基づいて重複が排除され、address
keyId
の組み合わせごとに、1つの署名リクエストだけが発生するようにします。 resolveSignatures
が呼び出された時、各address
keyId
の組み合わせに対する署名関数が呼び出され、各署名者のロールに対して複合署名が返されます。
How to Create An Authorization Function
幸運なことに、Authorization Functionの作成は比較的容易です。
Authorization Functionは最低でも次の2つのことを行う必要があります。
- 誰が署名するのか:署名するアカウントと、署名に使用するキーの keyId を知ります
- どのように署名するのか:指定されたアカウントとキーによる署名を取得する方法を知ります
Authorization Functionにはアカウントの概念があります。アカウントは、トランザクションの署名者となり得るものを表します。アカウントには、誰が署名するのか、また、どのように署名するのかが含まれます。Authorization Functionには空のアカウントが渡され、アカウントを返す必要があります。Authorization Functionを作成する際の作業は、主に、署名したいアカウントが署名できるように、このアカウントに情報を入力することです。
例えば、アカウントと keyId が事前に分かっており、署名できる関数があったとします。
const ADDRESS = "0xba1132bc08f82fe2"
/* this account on testnet has three keys, we want the one with an index of 1 (has a weight of 1000) */
const KEY_ID = 1
const sign = msg => { /* ... returns signature (for the key above) for supplied message ... */ }
私達のAuthorization Functionは、これらを埋めていくことになります。
Example 2:
const authorizationFunction = async (account) => {
/* authorization function need to return an account */
return {
...account, /* bunch of defaults in here, we want to overload some of them though */
tempId: `${ADDRESS}-${KEY_ID}`, /* tempIds are more of an advanced topic, for 99% of the times where you know the address and keyId you will want it to be a unique string per that address and keyId */
addr: ADDRESS, /* the address of the signatory */
keyId: Number(KEY_ID), /* this is the keyId for the accounts registered key that will be used to sign, make extra sure this is a number and not a string */
signingFunction: async signable => {
/* Singing functions are passed a signable and need to return a composite signature
signable.message is a hex string of what needs to be signed. */
return {
addr: ADDRESS, /* needs to be the same as the account.addr */
keyId: Number(KEY_ID), /* needs to be the same as account.keyId, once again make sure its a number and not a string */
signature: sign(signable.message), /* this needs to be a hex string of the signature, where signable.message is the hex value that needs to be signed */
}
}
}
}
Async stuff
Authorization FunctionとアカウントのSigning Functionの両方が非同期であることも可能です。つまり、これらの関数の両方が、必要な情報をどこか他の場所から取って来れるということです。あなたの各ユーザーがuserId
を持っているとします。このuserId
から、Authorization Functionのアカウントに必要な、一致するアドレスとキーを返すAPIコールがあるとします。また、あなたのAPIが署名しても問題ないと判断した場合、署名対象(署名に必要な内容を含む)とuserId
がPOST通信された時に、複合署名を返す別のエンドポイントを持つことも可能ます(署名対象には、署名の判断に役立つさまざまな情報が含まれています)。このようなことができる認証関数は、次のような形になります。
Example 3:
const getAccount = (userId) => fetch(`/api/user/${userId}/account`).then(d => d.json())
const getSignature = (userId, signable) = fetch(`/api/user/${userId}/sign`, {
method: "POST",
headers: { "Content-Type": "application/json"},
body: JSON.stringify(signable),
})
function authz (userId) {
return async function authorizationFunction (account) {
const {addr, keyId} = await getAccount(userId)
return {
...account,
tempId: `${addr}-${keyId}`,
addr: addr,
keyId: Number(keyId),
signingFunction: signable => {
return getSignature(userId, signable)
}
}
}
}
上記のExample 3はExample 2と内容は同じですが、認証関数を実行している間に、指定されたユーザーIDに基づいた情報を収集しています。
How to create a Signing Function
署名関数の作成も比較的簡単です!
署名関数を作成するには、ペイロードを消費し、署名データ構造(signature data structure)を返す関数を指定します。
Example 4:
const signingFunction = ({
message, /* The encoded string which needs to be used to produce the signature. */
addr, /* The address of the Flow Account this signature is to be produced for. */
keyId, /* The keyId of the key which is to be used to produce the signature. */
roles: {
proposer, /* A Boolean representing if this signature to be produced for a proposer. */
authorizer, /* A Boolean representing if this signature to be produced for a authorizer. */
payer, /* A Boolean representing if this signature to be produced for a payer. */
},
voucher, /* The raw transactions information, can be used to create the message for additional safety and lack of trust in the supplied message. */
}) => {
return {
addr, /* The address of the Flow Account this signature was produced for. */
keyId, /* The keyId for which key was used to produce the signature. */
/* The hex encoded string representing the signature of the message. */
signature: produceSignature(message)
}
}
Last updated on Nov 26, 2024 by Chase Fleming
翻訳元
Previous << Wallet Provider Spec
Flow BlockchainのCadence version1.0ドキュメント (Authorization Function)