当我们的用户厌倦了传统的电子邮件/密码注册流程时,他们会选择Google、GitHub等社交登录方式,这种方式虽然节约了用户的时间,但登录信息也会被第三方平台记录,也就是说我们用平台账号做了什么,平台都会一目了然,甚至还会对我们的行为进行分析、画像。那么有没有一种登录方式,它的所有信息都只保存在客户端和后端,并不牵扯三方平台授权,最大化的保证用户隐私呢?Web3.0给我们提供了一种选择:MetaMask。5 h- B! k( l% _; g
& \" j/ `0 \* \& b6 H0 H |+ B4 e
MetaMask
MetaMask是用于与以太坊区块链进行交互的软件加密货币钱包。MetaMask允许用户通过浏览器插件或移动应用程序访问其以太坊钱包,然后可以使用这些扩展程序与去中心化应用程序进行交互。当然了,首先需要拥有一个MetaMask钱包,进入https://chrome.google.com/websto ... oehlefnkodbefgpgknn 9 P, @3 V- t% K* {; }' G j! \
: D/ G% F/ m& U0 ?5 k' u
安装metamask浏览器插件:
随后点开插件,创建账号,记录密码、钱包地址、以及助记词等信息。
安装好插件之后,我们就可以利用这个插件和网站应用做交互了。' s' n9 F3 w) C2 r
钱包登录流程
登录逻辑和传统的三方登录还是有差异的,传统三方登录一般是首先跳转三方平台进行授权操作,随后三方平台将code验证码返回给登录平台,登录平台再使用code请求三方平台换取token,再通过token请求用户账号信息,而钱包登录则是先在前端通过Web3.js浏览器插件中保存的私钥对钱包地址进行签名操作,随后将签名和钱包地址发送到后端,后端利用Web3的库用同样的算法进行验签操作,如果验签通过,则将钱包信息存入token,并且返回给前端。2 E! @; s" [% y
' o. n1 W6 V; _! `. R0 x
+ c/ g7 F; Z7 l
前端签名操作$ ^! t# B6 I; l( F# A2 T- B
首先需要下载前端的Web3.0操作库,https://docs.ethers.io/v4/,随后集成到登录页面中:
9 k# Z3 }9 }5 ]
7 O& F2 ?- X# m' o
- <script src="{{ static_url("js/ethers-v4.min.js") }}"></script>" D- F/ b. [+ o8 j( ^- ~
- <script src="{{ static_url("js/axios.js") }}"></script>
- <script src="{{ static_url("js/vue.js") }}"></script>
这里我们基于Vue.js配合Axios使用。
接着声明登录激活方法:
- sign_w3:function(){/ X8 i7 K! |# H8 B
- that = this;; S( h# y: I1 o
- ethereum.enable().then(function () {7 O* d, ]7 V' j; m& t
- : ?+ z5 S/ p; k
- this.provider = new ethers.providers.Web3Provider(web3.currentProvider);
- 1 ~6 i% L! G! H2 p# V) F
- this.provider.getNetwork().then(function (result) {
- if (result['chainId'] != 1) {
- console.log("Switch to Mainnet!"), u$ M) S# h( F* e/ `& ?3 p
- % b2 A7 A9 a8 _3 ~( S
- } else { // okay, confirmed we're on mainnet
- + X* R( x3 q _5 |/ z" H
- this.provider.listAccounts().then(function (result) {
- console.log(result);' y% W" l, F% d. v; g0 u0 q
- 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);
- console.log("Your Balance: " + myBalance);
- });
- // get a signer object so we can do things that need signing4 P7 j+ z2 }) ~ Z
- this.signer = provider.getSigner();
- var rightnow = (Date.now()/1000).toFixed(0)( }% p0 d: E) d! V8 X5 Q/ b, [
- var sortanow = rightnow-(rightnow%600)
- this.signer.signMessage("Signing in to "+document.domain+" at "+sortanow, accountAddress, "test password!")
- .then((signature) => { that.handleAuth(accountAddress,signature);' ?6 |, ~5 O/ U! x" K- z
- });% _: L- c3 B* d, {& q* Y1 ^
- ( a; J/ S4 C# f3 U) o% n8 p
- console.log(this.signer);
- })
- }
- })
- })
- },
- //检查验证
- handleAuth:function(accountAddress, signature){7 j5 O% s) E' T- V, I
- # w1 K x, H' V) H% U: C! G; M& F
- 0 c# a" O( c2 H1 R {
- this.myaxios("/checkw3/","post",{"public_address":accountAddress,"signature":signature}).then(data =>{( e+ ]* c" M! s4 @* Z
- if(data.errcode==0){1 ]6 Z# e3 t# E6 t3 \
- alert("欢迎:"+data.public_address);/ `, { x2 K$ h
- localStorage.setItem("token",data.token);
- localStorage.setItem("email",data.public_address);$ j/ G7 K7 Q5 S* w! H: E! C5 Q9 N
- window.location.href = "/";4 `+ t' e8 C* Y: x( g( h2 S1 W
- }else{
- alert("验证失败");5 P! ~/ k: e" z( k" L
- }
- });: n6 `* c, v+ b" T
- }
. w1 v" E9 B0 A" H$ V+ v% J9 b
随后创建异步视图方法:
- from tornado.web import url( t M a; m2 J6 t7 z
- import tornado.web
- from tornado import httpclient/ f9 Z9 J" A. L! Q
- from .base import BaseHandler
- from web3.auto import w3
- from eth_account.messages import defunct_hash_message& F o& M _( k {+ A
- import time
- class CheckW3(BaseHandler): p; |9 [7 W# D& B3 o* y
- 9 d3 ^0 Q# R$ @7 R. M; F
- async def post(self):
- : g, M7 b" _7 c6 e9 E, J7 f7 q) A4 w
- public_address = self.get_argument("public_address")9 S# U1 r- s) S
- signature = self.get_argument("signature")
- 6 d, q. u5 p+ p$ W
- domain = self.request.host4 F, |! c o* _- V
- if ":" in domain:
- domain = domain[0:domain.index(":")]
- now = int(time.time())4 `' M8 q4 x1 D- q& g4 M
- sortanow = now-now%600
-
- original_message = 'Signing in to {} at {}'.format(domain,sortanow)
- print("[+] checking: "+original_message)6 i* ~6 H( |' l# r( I
- message_hash = defunct_hash_message(text=original_message)
- signer = w3.eth.account.recoverHash(message_hash, signature=signature)7 `. t+ O4 B$ S+ P8 ~
- if signer == public_address:4 R8 M/ _/ {: q# p! j
- try:6 {8 w$ E* |3 S' V! V. u: @5 C. A+ C
- user = await self.application.objects.get(User,email=public_address) A9 b5 X# c- e+ k/ l( y7 k5 x* a
- except Exception as e:
- user = await self.application.objects.create(User,email=public_address,password=create_password("third"),role=1)+ K6 }! i1 b* s. D V
- myjwt = MyJwt()
- token = myjwt.encode({"id":user.id})" a, B* p# ?/ `2 P2 N! Y
- self.finish({"msg":"ok","errcode":0,"public_address":public_address,"token":token})8 o, E; |+ b$ _5 j8 `) k; ^
- else:- b: p4 {. q$ X4 ?( J# _, [3 v
- self.finish({"msg":"could not authenticate signature","errcode":1})
这里通过recoverHash方法对签名进行反编译操作,如果反编译后的钱包地址和前端传过来的钱包地址吻合,那么说明当前账户的身份验证通过:. m/ [# [0 \) T6 P# T4 t+ Y- e
x3 |% b; D" C* q; }# i* H
- J; J% x$ ]; M3 } z
8 m/ c0 ]8 K0 ?( m& \+ M& L' M" B
当验签通过之后,利用钱包地址在后台创建账号,随后将钱包地址、token等信息返回给前端,前端将其保存在stroage中即可。" r8 J d: g: I" O4 K
结语
没错,将至已至,未来已来,是时候将Web3.0区块链技术融入产品了,虽然有些固有的思维方式依然在人们的脑海挥之不去,但世界却在时不我待地变化着,正是:青山遮不住,毕竟东流去!项目开源在https://github.com/zcxey2911/Tornado6_Vuejs3_Edu