当我们的用户厌倦了传统的电子邮件/密码注册流程时,他们会选择Google、GitHub等社交登录方式,这种方式虽然节约了用户的时间,但登录信息也会被第三方平台记录,也就是说我们用平台账号做了什么,平台都会一目了然,甚至还会对我们的行为进行分析、画像。那么有没有一种登录方式,它的所有信息都只保存在客户端和后端,并不牵扯三方平台授权,最大化的保证用户隐私呢?Web3.0给我们提供了一种选择:MetaMask。
MetaMask& U5 ]8 m9 K! C; c# v$ I
MetaMask是用于与以太坊区块链进行交互的软件加密货币钱包。MetaMask允许用户通过浏览器插件或移动应用程序访问其以太坊钱包,然后可以使用这些扩展程序与去中心化应用程序进行交互。当然了,首先需要拥有一个MetaMask钱包,进入https://chrome.google.com/websto ... oehlefnkodbefgpgknn
安装metamask浏览器插件:
随后点开插件,创建账号,记录密码、钱包地址、以及助记词等信息。
安装好插件之后,我们就可以利用这个插件和网站应用做交互了。
钱包登录流程
登录逻辑和传统的三方登录还是有差异的,传统三方登录一般是首先跳转三方平台进行授权操作,随后三方平台将code验证码返回给登录平台,登录平台再使用code请求三方平台换取token,再通过token请求用户账号信息,而钱包登录则是先在前端通过Web3.js浏览器插件中保存的私钥对钱包地址进行签名操作,随后将签名和钱包地址发送到后端,后端利用Web3的库用同样的算法进行验签操作,如果验签通过,则将钱包信息存入token,并且返回给前端。7 h2 v: P& i5 \+ h$ |/ ~1 W% ^! R
0 ]7 `1 o6 `: y' A# Q
前端签名操作
首先需要下载前端的Web3.0操作库,https://docs.ethers.io/v4/,随后集成到登录页面中:& Z( [; }) P( g& v
- <script src="{{ static_url("js/ethers-v4.min.js") }}"></script>$ E: g/ R$ C, o1 M! Y& `
- <script src="{{ static_url("js/axios.js") }}"></script>1 z' e. E! J! \0 ~* F7 B
- <script src="{{ static_url("js/vue.js") }}"></script>
$ y5 }, e6 ~! R l8 M
这里我们基于Vue.js配合Axios使用。* \- @2 Q/ l: W1 a. x
接着声明登录激活方法:
, m9 ?5 D) g5 E6 A- X
- sign_w3:function(){
- / Y- C! w0 \( ~0 S7 {0 n* H9 ^
- that = this;
- ethereum.enable().then(function () {4 ~% l9 z% |0 b3 k/ L
- this.provider = new ethers.providers.Web3Provider(web3.currentProvider);
- this.provider.getNetwork().then(function (result) {6 K, l. l6 R$ e1 [9 v6 S
- if (result['chainId'] != 1) {8 A* {" J' C2 T F; O
- 5 X! O9 [( ?% H( q1 m3 ]6 s
- console.log("Switch to Mainnet!")0 W( ^; P; y& k! f% E M0 f
- } else { // okay, confirmed we're on mainnet
- 7 |6 U+ B! L" ]" d" o
- this.provider.listAccounts().then(function (result) {
- console.log(result);
- this.accountAddress = result[0]; // figure out the user's Eth address
- this.provider.getBalance(String(result[0])).then(function (balance) {
- var myBalance = (balance / ethers.constants.WeiPerEther).toFixed(4);. I' |' ~$ l! G& l
- console.log("Your Balance: " + myBalance);
- });
- ( X* R7 B; V6 ~" m
- // get a signer object so we can do things that need signing
- this.signer = provider.getSigner();
- var rightnow = (Date.now()/1000).toFixed(0)
- var sortanow = rightnow-(rightnow%600)
- this.signer.signMessage("Signing in to "+document.domain+" at "+sortanow, accountAddress, "test password!")
- .then((signature) => { that.handleAuth(accountAddress,signature);& c/ J& b p; ?( G; W
- });
- console.log(this.signer);
- })
- }4 S! ^6 q- T J3 p$ J+ n: O
- })
- })
- },
/ R+ u: I0 @5 y1 G3 }! h; n
- //检查验证+ X; @1 o' D5 j
- handleAuth:function(accountAddress, signature){ o' a& b6 v+ _
- 0 w5 D/ v& Z6 q) U) e
- this.myaxios("/checkw3/","post",{"public_address":accountAddress,"signature":signature}).then(data =>{$ i6 T% C" {% M; z8 g0 \
- " O" |+ C3 U( D# }6 [" ~! g
- if(data.errcode==0){
- alert("欢迎:"+data.public_address);. x7 h8 S. _# \9 [
- localStorage.setItem("token",data.token);! W2 {1 z$ K. W/ V: e0 a
- localStorage.setItem("email",data.public_address);' M5 f# C2 e8 `& K
- window.location.href = "/";4 D {" K* n7 z& Z, |4 o
- }else{
- alert("验证失败");
- }
- });
- 2 B. U( p7 R! n& g3 C q
- 4 q, `: g: J |( E8 v1 ?+ B
- }
8 c5 ?4 \6 V( p' d$ |: w& o' X! p
2 B6 x x) J1 s& I
随后创建异步视图方法:8 ]% D: E& ]" O3 j, X
- from tornado.web import url3 X* k. a5 I/ p% X& }# F
- import tornado.web
- from tornado import httpclient: I4 g) x* _7 u8 f) J! t: M' O
- from .base import BaseHandler
- from web3.auto import w3
- from eth_account.messages import defunct_hash_message
- import time# k/ q$ z; \" S9 N! Z ^4 J' [
- class CheckW3(BaseHandler):0 ^ h) V" [3 S1 w
- ) L' t( j# _; G Y" M/ U* k
- async def post(self):
- public_address = self.get_argument("public_address")
- signature = self.get_argument("signature"), G" {% Y9 H; Q0 g
- , {! L2 L$ u; y. C3 v
- domain = self.request.host
- if ":" in domain:
- domain = domain[0:domain.index(":")]0 r) ~6 X! F# [5 [5 x7 F Q& ^' E% h
- now = int(time.time())
- sortanow = now-now%600
-
- original_message = 'Signing in to {} at {}'.format(domain,sortanow)
- print("[+] checking: "+original_message)) X( _3 ^; M, }! W% X1 E
- message_hash = defunct_hash_message(text=original_message): Z e; j+ D9 N+ V o7 u
- signer = w3.eth.account.recoverHash(message_hash, signature=signature)
- if signer == public_address: ~# H) Y% G; v' U3 r
- try:
- user = await self.application.objects.get(User,email=public_address)
- except Exception as e:0 L5 G6 S+ L$ m( x& r% _' k
- user = await self.application.objects.create(User,email=public_address,password=create_password("third"),role=1)9 B; @" z# u5 ^* n, s: c! g9 F) U
- myjwt = MyJwt()
- token = myjwt.encode({"id":user.id})
- self.finish({"msg":"ok","errcode":0,"public_address":public_address,"token":token})) I: I$ _6 I3 V2 l' v% t
- else:5 P! ?2 K" L3 T. e6 [9 O R7 k
- self.finish({"msg":"could not authenticate signature","errcode":1})
这里通过recoverHash方法对签名进行反编译操作,如果反编译后的钱包地址和前端传过来的钱包地址吻合,那么说明当前账户的身份验证通过:2 ~, ?3 R( ?6 w1 ^" C) A; _; W
; X: G; z8 i$ ?' ]5 u
2 f$ }1 j( V% F9 @: E9 a
当验签通过之后,利用钱包地址在后台创建账号,随后将钱包地址、token等信息返回给前端,前端将其保存在stroage中即可。
0 E* [4 k$ i" b7 ~- F
结语
没错,将至已至,未来已来,是时候将Web3.0区块链技术融入产品了,虽然有些固有的思维方式依然在人们的脑海挥之不去,但世界却在时不我待地变化着,正是:青山遮不住,毕竟东流去!项目开源在https://github.com/zcxey2911/Tornado6_Vuejs3_Edu % _, u8 X# b$ D& ?
4 ]: ]$ X, p0 ~5 @