1庞萍, 摘要
網(wǎng)站太多拧烦,各種用戶名/密碼實(shí)在記不住。所以我們逐漸接受了BAT賬號的授權(quán)登錄功能钝计。在以太坊DAPP應(yīng)用中恋博,也可以使用MetaMask實(shí)現(xiàn)授權(quán)后一鍵登錄功能。MetaMask是去中心化錢包私恬,授權(quán)信息不會如BAT中心一樣存在被收集利用的問題债沮。
本文從技術(shù)層面講清楚原理,并結(jié)合代碼說明如何實(shí)現(xiàn)本鸣。
2疫衩,授權(quán)一鍵式登錄的利弊分析
我們往往被自己的密碼難住,越來越抵制傳統(tǒng)的電子郵件/密碼注冊流程荣德。通過微信闷煤,QQ,支付寶涮瞻,F(xiàn)acebook鲤拿,Google或GitHub一鍵式社交登錄功能可以省去記住密碼或者密碼泄露的而風(fēng)險(xiǎn)。當(dāng)然饲宛,它也需要權(quán)衡利弊皆愉。
社交媒體登錄集成的優(yōu)點(diǎn):
- 沒有更麻煩的填表。
- 無需記住另一個(gè)用戶名/密碼對艇抠。
- 整個(gè)過程需要幾秒鐘而不是幾分鐘幕庐。
社交媒體登錄集成的缺點(diǎn):
- 由于用戶的信息是從外部提供商處加載的,因此這會對提供商如何使用所有這些個(gè)人數(shù)據(jù)產(chǎn)生巨大的隱私擔(dān)憂家淤。例如异剥,在撰寫本文時(shí),F(xiàn)acebook正面臨著數(shù)據(jù)隱私問題絮重。
加密貓(https://www.cryptokitties.co/)游戲中冤寿,用戶不需要輸入用戶名,密碼就可以建立自己的賬戶體系青伤,進(jìn)行登錄交易督怜。
本文介紹下這個(gè)方法的原理和代碼實(shí)現(xiàn),使用MetaMask擴(kuò)展的一鍵式加密安全登錄流程狠角,所有數(shù)據(jù)都存儲在我們自己的后端号杠。我們稱為“使用MetaMask登錄”。
一張價(jià)值千言萬語的圖片,這里是我們要構(gòu)建的登錄流程的演示:
看起來不錯(cuò)屉凯?讓我們開始吧!
3眼溶, 如何使用Metamask進(jìn)行一鍵式登錄流程
一鍵式登錄流程的基本思想是悠砚,通過使用私鑰對一段數(shù)據(jù)進(jìn)行簽名,可以很容易地通過加密方式證明帳戶的所有權(quán)堂飞。如果您設(shè)法簽署由我們的后端生成的精確數(shù)據(jù)灌旧,那么后端將認(rèn)為您是該錢包地址的所有者。因此绰筛,我們可以構(gòu)建基于消息簽名的身份驗(yàn)證機(jī)制节榜,并將用戶的錢包地址作為其標(biāo)識符。
如果它看起來不太清楚别智,那就沒問題了,因?yàn)槲覀儠鹨唤忉屗?/p>
請注意稼稿,雖然我們將使用連接到以太坊區(qū)塊鏈的工具(MetaMask薄榛,以太坊錢包地址),但此登錄過程實(shí)際上并不需要區(qū)塊鏈:它只需要其加密功能让歼。話雖如此敞恋,隨著MetaMask成為如此受歡迎的擴(kuò)展,現(xiàn)在似乎是介紹此登錄流程的好時(shí)機(jī)谋右。
4硬猫, MetaMask瀏覽器擴(kuò)展
如果您已經(jīng)知道MetaMask是什么,請?zhí)^本節(jié)改执。
MetaMask是一個(gè)瀏覽器插件啸蜜,可作為MetaMask Chrome擴(kuò)展或Firefox附加組件使用。它的核心是它作為以太坊錢包:通過安裝它辈挂,您將可以訪問一個(gè)獨(dú)特的以太坊錢包地址衬横,您可以使用它開始發(fā)送和接收以太幣或ERC20通證。
但MetaMask不僅僅是以太坊錢包终蒂。作為瀏覽器擴(kuò)展蜂林,它可以與您正在瀏覽的當(dāng)前網(wǎng)頁進(jìn)行交互。它通過在您訪問的每個(gè)網(wǎng)頁中注入一個(gè)名為web3.js的JavaScript庫來實(shí)現(xiàn)拇泣。注入后噪叙,web3
將通過window.web3
的JavaScript代碼為你訪問的每個(gè)網(wǎng)頁提供一個(gè)對象。要查看此對象霉翔,只需在Chrome或Firefox DevTools控制臺鍵入window.web3
(如果已安裝MetaMask)睁蕾,結(jié)果如下圖。
Web3.js是以太坊區(qū)塊鏈的JavaScript接口早龟。有以下功能:
- 獲取最新的區(qū)塊號(
web3.eth.getBlockNumber
) - 檢查MetaMask上的當(dāng)前活動帳戶(
web3.eth.coinbase
) - 獲取任何帳戶的余額(
web3.eth.getBalance
) - 發(fā)送交易(
web3.eth.sendTransaction
) - 使用當(dāng)前帳戶的私鑰對消息進(jìn)行簽名(
web3.personal.sign
) - ......還有點(diǎn)擊獲取更多接口說明
安裝MetaMask時(shí)惫霸,任何前端代碼都可以訪問所有這些功能猫缭,并與區(qū)塊鏈進(jìn)行交互。他們被稱為dapps或DApps(去中心化的應(yīng)用程序壹店,有時(shí)甚至寫成“?Apps”)猜丹。
與DApp開發(fā)相關(guān): 時(shí)間鎖定錢包:以太坊智能合約簡介
web3.js中的大多數(shù)函數(shù)都是讀函數(shù)(get block, get balance, etc.),web3
立即給出響應(yīng)硅卢。但是射窒,某些功能(如web3.eth.sendTransaction
和web3.personal.sign
)需要當(dāng)前帳戶使用其私鑰對某些數(shù)據(jù)進(jìn)行簽名。這些函數(shù)觸發(fā)MetaMask顯示確認(rèn)彈窗将塑,以仔細(xì)檢查用戶是否知道他或她正在簽名的內(nèi)容脉顿。
讓我們看看如何使用MetaMask。要進(jìn)行簡單測試点寥,請?jiān)贒evTools控制臺中粘貼以下行:
web3.personal.sign(web3.fromUtf8("你好艾疟,我是輝哥!!"), web3.eth.coinbase, console.log);
此命令表示:使用coinbase帳戶(即當(dāng)前帳戶)將我的消息(從utf8轉(zhuǎn)換為十六進(jìn)制)進(jìn)行簽名敢辩,并以打印作為回調(diào)函數(shù)打印出簽名蔽莱。輸入回車后,將出現(xiàn)MetaMask彈窗戚长,如果點(diǎn)擊簽名按鈕盗冷,將打印簽名的消息。
我們將web3.personal.sign
在登錄流程中使用同廉。
關(guān)于這一部分的最后一點(diǎn)說明:MetaMask將web3.js注入到您當(dāng)前的瀏覽器中仪糖,但實(shí)際上還有其他獨(dú)立的瀏覽器也會注入web3.js,例如Mist迫肖。但是锅劝,在我看來,MetaMask為普通用戶提供了探索dapps的最佳用戶體驗(yàn)和最簡單的轉(zhuǎn)換蟆湖。
4鸠天, 登錄流程如何工作
這是如何做到的呢?這部分內(nèi)容講說服你帐姻,證明這種方式是安全的稠集。所以為什么部分的介紹就比較短了。
如前面所述饥瓷,我們將忘記區(qū)塊鏈剥纷。我們有一個(gè)傳統(tǒng)的Web 2.0客戶端 - 服務(wù)器RESTful架構(gòu)。我們將做出一個(gè)假設(shè):訪問我們的前端網(wǎng)頁的所有用戶都安裝了MetaMask呢铆。有了這個(gè)假設(shè)晦鞋,我們將展示無密碼加密安全登錄流程的工作原理。
第1步:修改用戶模型(后端)
首先,我們的User
模型需要有兩個(gè)新的必填字段:publicAddress
和nonce
悠垛。此外线定,publicAddress
需要具有唯一性。你可以保持平常username
确买,email
和password
字段斤讥,特別是如果你想平行實(shí)現(xiàn)您MetaMask登錄電子郵件/密碼登錄,但它們是可選的湾趾。
如果用戶希望使用MetaMask登錄芭商,則注冊過程也會略有不同,因?yàn)樽詴r(shí)publicAddress
將是必填字段搀缠。不過請放心铛楣,用戶永遠(yuǎn)不需要手動輸入publicAddress
錢包地址,因?yàn)樗梢酝ㄟ^web3.eth.coinbase
變量來提取艺普。
第2步:生成隨機(jī)數(shù)(后端)
對于數(shù)據(jù)庫中的每個(gè)用戶簸州,在nonce
字段中生成隨機(jī)字符串。例如歧譬,nonce
可以是一個(gè)大的隨機(jī)整數(shù)勿侯。
第3步:用戶獲取他們的隨機(jī)數(shù)(前端)
在我們的前端JavaScript代碼中,假設(shè)存在MetaMask缴罗,我們可以訪問window.web3
。因此祭埂,我們可以通知web3.eth.coinbase
獲取當(dāng)前MetaMask帳戶的錢包地址面氓。
當(dāng)用戶單擊登錄按鈕時(shí),我們向后端發(fā)出API調(diào)用以檢索與其錢包地址關(guān)聯(lián)的隨機(jī)數(shù)蛆橡。像帶參數(shù)獲取例如GET /api/users?publicAddress=${publicAddress}
應(yīng)該做的事情那樣舌界。當(dāng)然,由于這是一個(gè)未經(jīng)身份驗(yàn)證的API調(diào)用泰演,因此后端應(yīng)配置為僅顯示此路由上的公共信息包括nonce
呻拌。
如果先前的請求未返回任何結(jié)果,則表示當(dāng)前錢包地址尚未注冊睦焕。我們需要先通過POST /users
傳遞publicAddress
請求消息體來創(chuàng)建一個(gè)新帳戶藐握。另一方面,如果有結(jié)果垃喊,那么我們存儲它的nonce
猾普。
第4步:用戶簽署Nonce(前端)
一旦前端接收nonce
到先前API調(diào)用的響應(yīng),它將運(yùn)行以下代碼:
web3.personal.sign(nonce, web3.eth.coinbase, callback);
這將提示MetaMask顯示用于簽名消息的確認(rèn)彈出窗口本谜。隨機(jī)數(shù)將顯示在此彈出窗口中初家,以便用戶知道她或他有沒有簽署某些惡意數(shù)據(jù)。
當(dāng)她或他接受簽名時(shí),將使用帶簽名的消息(稱為signature
)作為參數(shù)調(diào)用回調(diào)函數(shù)溜在。然后前端進(jìn)行另一個(gè)API調(diào)用POST /api/authentication
陌知,傳遞一個(gè)帶有signature
和publicAddress
的消息體。
第5步:簽名驗(yàn)證(后端)
當(dāng)后端收到POST /api/authentication
請求時(shí)掖肋,它首先根據(jù)請求消息體中publicAddress
獲取數(shù)據(jù)庫中的對應(yīng)用戶仆葡,特別是它相關(guān)的隨機(jī)數(shù)nonce
。
具有隨機(jī)數(shù)培遵,錢包地址和簽名后浙芙,后端可以加密地驗(yàn)證用戶已正確簽署了隨機(jī)數(shù)。如果確認(rèn)是這種情況籽腕,那么用戶已經(jīng)證明了擁有錢包地址的所有權(quán)嗡呼,我們可以考慮對她或他進(jìn)行身份驗(yàn)證。然后可以將JWT或會話標(biāo)識符返回到前端皇耗。
第6步:更改Nonce(后端)
為了防止用戶使用相同的簽名再次登錄(如果它被泄露)南窗,我們確保下次同一用戶想要登錄時(shí),她或他需要簽署一個(gè)新的nonce郎楼。這是通過nonce
為該用戶生成另一個(gè)隨機(jī)數(shù)并將其持久保存到數(shù)據(jù)庫來實(shí)現(xiàn)的万伤。
這就是我們管理nonce簽名無密碼登錄流程的方法。
5呜袁,為什么登錄流程有效
根據(jù)定義敌买,身份驗(yàn)證實(shí)際上只是帳戶所有權(quán)的證明。如果您使用錢包地址唯一地標(biāo)識您的帳戶阶界,那么證明您加密方式擁有該帳戶就非常簡單虹钮。
為了防止黑客獲取某個(gè)特定郵件及其簽名(但不是您的實(shí)際私鑰),我們會強(qiáng)制需要簽名的消息滿足以下條件:
- 由后端提供
- 定期改變
在我們的demo樣例中膘融,每次成功登錄后我們都改變了它芙粱,但也可以設(shè)想基于時(shí)間戳的機(jī)制。
6春畔, DEMO代碼實(shí)現(xiàn)
在本節(jié)中,我將逐一完成上述六個(gè)步驟岛都。我將展示一些代碼片段律姨,以便我們?nèi)绾螐念^開始構(gòu)建此登錄流,或者將其集成到現(xiàn)有的后端臼疫,而不需要太多努力线召。
為了本文的目的,我創(chuàng)建了一個(gè)小型演示應(yīng)用程序多矮。我正在使用的堆棧如下:
- Node.js缓淹,Express和SQLite(通過Sequelize ORM)在后端實(shí)現(xiàn)RESTful API哈打。它在成功驗(yàn)證時(shí)返回JWT。
- 在前端反應(yīng)單頁面應(yīng)用程序讯壶。
我嘗試使用盡可能少的庫料仗。我希望代碼足夠簡單,以便您可以輕松地將其移植到其他技術(shù)堆棧伏蚊。
訪問https://login-with-metamask.firebaseapp.com/可以獲得一個(gè)演示立轧,也可以參考步驟搭建自己的本地工程。
歡迎加入輝哥的知識星球躏吊,從中下載本案例代碼工程氛改,也可加專門微信群交流技術(shù)問題。
第1步:修改用戶模型(后端)
需要兩個(gè)字段:publicAddress
和nonce
比伏。我們初始化nonce
為隨機(jī)大數(shù)胜卤。每次成功登錄后都應(yīng)更改此號碼。我還在username
這里添加了一個(gè)可選字段赁项,用戶可以更改葛躏。
.\backend\src\models\user.model.js
const User = sequelize.define('User', {
nonce: {
allowNull: false,
type: Sequelize.INTEGER.UNSIGNED,
defaultValue: () => Math.floor(Math.random() * 1000000) // Initialize with a random nonce
},
publicAddress: {
allowNull: false,
type: Sequelize.STRING,
unique: true,
validate: { isLowercase: true }
},
username: {
type: Sequelize.STRING,
unique: true
}
});
為簡單起見,我將publicAddress
字段設(shè)置為小寫悠菜。更嚴(yán)格的檢查地址是否是有效的以太坊地址的方法參考鏈接:https://ethereum.stackexchange.com/questions/1374/how-can-i-check-if-an-ethereum-address-is-valid)舰攒。
第2步:生成隨機(jī)數(shù)(后端)
這是在defaultValue()
上面的模型定義中的函數(shù)中完成的。
第3步:用戶獲取他們的隨機(jī)數(shù)(前端)
下一步是在后端添加一些樣板代碼來處理User
模型上的CRUD方法悔醋,我們在這里不做摩窃。
切換到前端代碼,當(dāng)用戶單擊登錄按鈕時(shí)芬骄,我們的handleClick
處理程序執(zhí)行以下操作:
.\frontend\src\Login\Login.js
class Login extends Component {
handleClick = () => {
// --snip--
const publicAddress = web3.eth.coinbase.toLowerCase();
// Check if user with current publicAddress is already present on back end
fetch(`${process.env.REACT_APP_BACKEND_URL}/users?publicAddress=${publicAddress}`)
.then(response => response.json())
// If yes, retrieve it. If no, create it.
.then(
users => (users.length ? users[0] : this.handleSignup(publicAddress))
)
// --snip--
};
handleSignup = publicAddress =>
fetch(`${process.env.REACT_APP_BACKEND_URL}/users`, {
body: JSON.stringify({ publicAddress }),
headers: {
'Content-Type': 'application/json'
},
method: 'POST'
}).then(response => response.json());
}
在這里猾愿,我們正在檢索MetaMask活動帳戶web3.eth.coinbase
。然后我們檢查publicAddress
后端是否已經(jīng)存在德玫。如果用戶已經(jīng)存在,我們就獲取用戶信息椎麦。要么就是在handleSignup
方法中創(chuàng)建一個(gè)新帳戶宰僧。
第4步:用戶簽署Nonce(前端)
讓我們繼續(xù)我們的handleClick
方法。我們現(xiàn)在擁有一個(gè)由后端給出的用戶(無論是檢索還是新創(chuàng)建)观挎。特別是我們有他們的nonce
和publicAddress
琴儿。因此,我們準(zhǔn)備publicAddress
使用與此相關(guān)聯(lián)的私鑰對nonce進(jìn)行簽名web3.personal.sign
嘁捷。這是在handleSignMessage
函數(shù)中完成的造成。
請注意,web3.personal.sign
將字符串的十六進(jìn)制表示作為其第一個(gè)參數(shù)雄嚣。我們需要使用UTF-8編碼的字符串轉(zhuǎn)換為十六進(jìn)制格式web3.fromUtf8
晒屎。此外喘蟆,我決定簽署一個(gè)更加用戶友好的句子,而不是僅簽署nonce鼓鲁,因?yàn)樗鼘@示在MetaMask確認(rèn)彈出窗口中:I am signing my once-time nonce: ${nonce}
蕴轨。
class Login extends Component {
handleClick = () => {
// --snip--
fetch(`${process.env.REACT_APP_BACKEND_URL}/users?publicAddress=${publicAddress}`)
.then(response => response.json())
// If yes, retrieve it. If no, create it.
.then(
users => (users.length ? users[0] : this.handleSignup(publicAddress))
)
// Popup MetaMask confirmation modal to sign message
.then(this.handleSignMessage)
// Send signature to back end on the /auth route
.then(this.handleAuthenticate)
// --snip--
};
handleSignMessage = ({ publicAddress, nonce }) => {
return new Promise((resolve, reject) =>
web3.personal.sign(
web3.fromUtf8(`I am signing my one-time nonce: ${nonce}`),
publicAddress,
(err, signature) => {
if (err) return reject(err);
return resolve({ publicAddress, signature });
}
)
);
};
handleAuthenticate = ({ publicAddress, signature }) =>
fetch(`${process.env.REACT_APP_BACKEND_URL}/auth`, {
body: JSON.stringify({ publicAddress, signature }),
headers: {
'Content-Type': 'application/json'
},
method: 'POST'
}).then(response => response.json());
}
當(dāng)用戶成功簽署消息后,我們將轉(zhuǎn)到該handleAuthenticate
方法骇吭。我們只是向/auth
后端的路由發(fā)送請求橙弱,發(fā)送我們publicAddress
以及signature
用戶剛簽名的消息。
第5步:簽名驗(yàn)證(后端)
這是稍微復(fù)雜一點(diǎn)的部分燥狰。后端在/auth
包含一個(gè) publicAddress
和一個(gè)路由上接收請求簽名signature
棘脐,并且需要驗(yàn)證錢包地址publicAddress
是否已簽名正確的隨機(jī)數(shù)nonce
。
第一步是從數(shù)據(jù)庫中檢索用戶所說的publicAddress
; 只有一個(gè)因?yàn)槲覀?code>publicAddress在數(shù)據(jù)庫中定義為唯一字段龙致。然后蛀缝,我們將消息設(shè)置msg
為“I am signing my one-time nonce...”,與步驟4中的前端完全相同净当,使用此用戶的隨機(jī)數(shù)内斯。
下一個(gè)塊是驗(yàn)證本身。有一些加密涉及像啼。如果您喜歡研究俘闯,我建議您閱讀有關(guān)橢圓曲線簽名算法以獲得更多信息。
總結(jié)這部分的作用忽冻,對于給出的msg
(包含nonce
)和signature
信息真朗,ecrecover
函數(shù)輸出用于簽名msg
的錢包地址。如果它與我們請求消息體的publicAddress
一致僧诚,則證明了他們擁有publicAddress
的所有權(quán)遮婶。經(jīng)過這個(gè)過程,我們認(rèn)為他們經(jīng)過身份驗(yàn)證的湖笨。
User.findOne({ where: { publicAddress } })
// --snip--
.then(user => {
const msg = `I am signing my one-time nonce: ${user.nonce}`;
// We now are in possession of msg, publicAddress and signature. We
// can perform an elliptic curve signature verification with ecrecover
const msgBuffer = ethUtil.toBuffer(msg);
const msgHash = ethUtil.hashPersonalMessage(msgBuffer);
const signatureBuffer = ethUtil.toBuffer(signature);
const signatureParams = ethUtil.fromRpcSig(signatureBuffer);
const publicKey = ethUtil.ecrecover(
msgHash,
signatureParams.v,
signatureParams.r,
signatureParams.s
);
const addressBuffer = ethUtil.publicToAddress(publicKey);
const address = ethUtil.bufferToHex(addressBuffer);
// The signature verification is successful if the address found with
// ecrecover matches the initial publicAddress
if (address.toLowerCase() === publicAddress.toLowerCase()) {
return user;
} else {
return res
.status(401)
.send({ error: 'Signature verification failed' });
}
})
成功驗(yàn)證后旗扑,后端生成JWT并將其發(fā)送回客戶端。這是一種經(jīng)典的身份驗(yàn)證方案慈省,所以我不會在這里放置代碼臀防。
第6步:更改Nonce(后端)
出于安全原因,最后一步是更改nonce边败。在成功驗(yàn)證后的某處袱衷,添加以下代碼:
// --snip--
.then(user => {
user.nonce = Math.floor(Math.random() * 1000000);
return user.save();
})
// --snip--
7,今天就可以投入生產(chǎn)了
雖然區(qū)塊鏈可能有其缺陷并且仍處于早期階段笑窜,但我無法強(qiáng)調(diào)如何在今天的任何現(xiàn)有網(wǎng)站上實(shí)施此登錄流程的重要性致燥。以下是為什么此登錄流程優(yōu)先于電子郵件/密碼和社交登錄的參數(shù)列表:
- 提高安全性:公鑰加密的所有權(quán)證明可以說比通過電子郵件/密碼或第三方證明所有權(quán)更安全,因?yàn)镸etaMask在您的計(jì)算機(jī)本地存儲憑據(jù)排截,而不是在線服務(wù)器嫌蚤,這使得攻擊面較小辐益。
- 簡化的用戶體驗(yàn):這是一鍵式(也可能是雙擊)登錄流程,在幾秒鐘內(nèi)完成搬葬,無需輸入或記住任何密碼荷腊。
- 增加隱私:不需要電子郵件,也不涉及第三方急凰。
當(dāng)然女仰,MetaMask登錄流程可以很好地與其他傳統(tǒng)登錄方法并行使用。需要在每個(gè)帳戶與其擁有的錢包地址之間進(jìn)行映射抡锈。
但是這個(gè)登錄流程并不適合所有人:
-
用戶需要安裝MetaMask:如果沒有MetaMask或支持
web3
的瀏覽器疾忍,此登錄流程顯然無效。如果您的受眾對加密貨幣不感興趣床三,他們甚至?xí)紤]安裝MetaMask一罩。隨著最近的通證熱潮,讓我們希望我們正在走向Web 3.0互聯(lián)網(wǎng)撇簿。 - 需要在后端完成一些工作:正如我們所見聂渊,實(shí)現(xiàn)此登錄流程的簡單版本非常簡單。但是四瘫,要將其集成到現(xiàn)有的復(fù)雜系統(tǒng)中汉嗽,需要在接觸身份驗(yàn)證的所有區(qū)域進(jìn)行一些更改:注冊,數(shù)據(jù)庫找蜜,身份驗(yàn)證路由等饼暑。這尤其正確,因?yàn)槊總€(gè)帳戶都將與一個(gè)或多個(gè)錢包地址相關(guān)聯(lián)洗做。
- 它不適用于移動設(shè)備:看以下描述弓叛。
8, 移動設(shè)備的缺點(diǎn)
正如我們所見诚纸,這web3
是此登錄流程的先決條件撰筷。在桌面瀏覽器上,MetaMask會注入它畦徘。但是毕籽,移動瀏覽器沒有擴(kuò)展程序,因此此登錄流程無法在移動版Safari旧烧,Chrome或Firefox上開箱即用影钉。有一些獨(dú)立的移動瀏覽器注入了web3
基于MetaMask的瀏覽器画髓。在撰寫本文時(shí)掘剪,它們還處于早期階段,但如果您有興趣奈虾,請查看Cipher夺谁,Status和Toshi廉赔。“使用MetaMask登錄”適用于這些移動瀏覽器匾鸥。
關(guān)于移動應(yīng)用程序蜡塌,答案是肯定的,登錄流程有效勿负,但需要有很多準(zhǔn)備工作的作為基礎(chǔ)馏艾。作為基本準(zhǔn)備工作,您需要自己重建一個(gè)簡單的以太坊錢包奴愉。這包括錢包地址生成琅摩,種子文字恢復(fù)和安全私鑰存儲,以及web3.personal.sign
確認(rèn)彈出窗口锭硼。幸運(yùn)的是房资,有l(wèi)ibrary可以幫助您。人們關(guān)心的關(guān)鍵信息是安全的檀头,因?yàn)閼?yīng)用程序本身擁有私鑰轰异。在桌面瀏覽器上,我們將此任務(wù)委托給MetaMask暑始。
所以我認(rèn)為答案是否定的搭独,這個(gè)登錄流程今天不適用于移動設(shè)備。但它正朝著這個(gè)方向努力蒋荚,今天簡單的解決方案仍然是移動用戶的并行傳統(tǒng)登錄方法戳稽。
【輝哥備注】雖然主流的移動端瀏覽器APP還不支持MetaMask插件,但是包括TrustWallet, AlphaWallet等錢包自帶的DAPP瀏覽器支持支付功能期升,也就不需要MetaMask錢包用于支付了惊奇。手機(jī)端的一鍵登錄問題轉(zhuǎn)換為別的實(shí)現(xiàn)方案的問題。
9播赁, 環(huán)境搭建
1). 修改IP地址
輝哥采用Windows 環(huán)境下搭建Ubuntu Linux環(huán)境的方式颂郎,在Windows環(huán)境訪問目標(biāo)測試程序,所以需要修改前后端調(diào)用的IP地址為本地地址容为。就是http://192.168.0.103為Ubuntu服務(wù)器的IP地址乓序,如果調(diào)用前端也在linux下運(yùn)行則可使用http://127.0.0.1地址。
.\login-with-metamask-demo\frontend.env.development
REACT_APP_BACKEND_URL=http://192.168.0.103:8000/api
.\login-with-metamask-demo\frontend\src\registerServiceWorker.js
window.location.hostname === 'http://192.168.0.103' ||
修改后坎背,然后把完整的login-with-metamask-demo工程上傳至linux工作目錄下替劈。
2). 安裝依賴并運(yùn)行后端服務(wù)器
在新的命令窗口運(yùn)行以下命令,完成安裝和服務(wù)器運(yùn)行:
npm install -g yarn
yarn
yarn dev
安裝運(yùn)行成功的輸出內(nèi)容:
duncanwang@ubuntu:~/work/login-with-metamask-demo/backend$ yarn dev
yarn run v1.10.1
$ nodemon --exec babel-node src/
[nodemon] 1.17.2
[nodemon] to restart at any time, enter `rs`
[nodemon] watching: *.*
[nodemon] starting `babel-node src/`
sequelize deprecated String based operators are now deprecated. Please use Symbol based operators for better security, read more at http://docs.sequelizejs.com/manual/tutorial/querying.html#operators node_modules/sequelize/lib/sequelize.js:242:13
Express app listening on localhost:8000
^C
duncanwang@ubuntu:~/work/login-with-metamask-demo/backend$ ls
Dockerfile node_modules package.json src yarn.lock
duncanwang@ubuntu:~/work/login-with-metamask-demo/backend$ rm -r -f node_modules
duncanwang@ubuntu:~/work/login-with-metamask-demo/backend$ ls
Dockerfile package.json src yarn.lock
duncanwang@ubuntu:~/work/login-with-metamask-demo/backend$ npm install -g yarn
/home/duncanwang/.nvm/versions/node/v8.11.4/bin/yarn -> /home/duncanwang/.nvm/versions/node/v8.11.4/lib/node_modules/yarn/bin/yarn.js
/home/duncanwang/.nvm/versions/node/v8.11.4/bin/yarnpkg -> /home/duncanwang/.nvm/versions/node/v8.11.4/lib/node_modules/yarn/bin/yarn.js
+ yarn@1.10.1
updated 1 package in 4.201s
duncanwang@ubuntu:~/work/login-with-metamask-demo/backend$ yarn
yarn install v1.10.1
[1/4] Resolving packages...
[2/4] Fetching packages...
info fsevents@1.1.3: The platform "linux" is incompatible with this module.
info "fsevents@1.1.3" is an optional dependency and failed compatibility check. Excluding it from installation.
[3/4] Linking dependencies...
[4/4] Building fresh packages...
Done in 173.70s.
duncanwang@ubuntu:~/work/login-with-metamask-demo/backend$ yarn dev
yarn run v1.10.1
$ nodemon --exec babel-node src/
[nodemon] 1.17.2
[nodemon] to restart at any time, enter `rs`
[nodemon] watching: *.*
[nodemon] starting `babel-node src/`
sequelize deprecated String based operators are now deprecated. Please use Symbol based operators for better security, read more at http://docs.sequelizejs.com/manual/tutorial/querying.html#operators node_modules/sequelize/lib/sequelize.js:242:13
Express app listening on localhost:8000
3). 安裝依賴并運(yùn)行前端服務(wù)器
在前端程序根目錄下
yarn
yarn start
安裝運(yùn)行成功的輸出內(nèi)容:
duncanwang@ubuntu:~/work/login-with-metamask-demo/frontend$ yarn
yarn install v1.10.1
warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json.
[1/4] Resolving packages...
[2/4] Fetching packages...
info There appears to be trouble with your network connection. Retrying...
info There appears to be trouble with your network connection. Retrying...
info fsevents@1.1.3: The platform "linux" is incompatible with this module.
info "fsevents@1.1.3" is an optional dependency and failed compatibility check. Excluding it from installation.
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 266.85s.
duncanwang@ubuntu:~/work/login-with-metamask-demo/frontend$ yarn start
yarn run v1.10.1
$ react-scripts start
Starting the development server...
Compiled successfully!
You can now view frontend in the browser.
Local: http://localhost:3000/
On Your Network: http://192.168.0.103:3000/
Note that the development build is not optimized.
To create a production build, use yarn build.
4). 運(yùn)行客戶端程序并測試授權(quán)一鍵登錄
在Windows瀏覽器運(yùn)行客戶端程序得滤,點(diǎn)擊完成SIGN簽名授權(quán):
登錄后陨献,更新用戶的名字。
不需要輸入密碼懂更,完成了duncanwang和錢包地址0xD1F7922e8b78cBEB182250753ade8379d1E09949的關(guān)聯(lián)和一鍵登錄功能眨业。
10急膀,總結(jié)
我們在本文中介紹了一鍵式,加密安全的登錄流程龄捡,沒有涉及第三方卓嫂,稱為“使用MetaMask登錄”。我們解釋了后端生成的隨機(jī)數(shù)的數(shù)字簽名如何證明帳戶的所有權(quán)聘殖,從而提供身份驗(yàn)證晨雳。我們還探討了這種登錄機(jī)制與傳統(tǒng)電子郵件/密碼或社交登錄相比的權(quán)衡,無論是在桌面還是在移動設(shè)備上奸腺。
即使今天這樣的登錄流程的目標(biāo)受眾仍然很小悍募,我真誠地希望你們中的一些人感到鼓舞,在你自己的網(wǎng)絡(luò)應(yīng)用程序中提供與MetaMask一起登錄洋机,與傳統(tǒng)登錄流程并行坠宴。
本文由輝哥翻譯自《One-click Login with Blockchain: A MetaMask Tutorial》,并做適當(dāng)?shù)男薷囊员阒袊脩艨梢愿玫睦斫狻?/em>