Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
    今天去中心化身份逐渐被广泛采用。用户的部分在线活动在链上是公开的,可通过加密钱包搜索到,用户在链上创造、贡献、赚取和拥有的东西,都反映了他们的喜好,也逐渐积累成该用户的身份和标识。  `# ^$ q9 O. G
" t* d/ `8 V. ]9 o- I6 O" ^% k
    当我们的用户厌倦了传统的电子邮件/密码注册流程时,他们会选择Google、GitHub等社交登录方式,这种方式虽然节约了用户的时间,但登录信息也会被第三方平台记录,也就是说我们用平台账号做了什么,平台都会一目了然,甚至还会对我们的行为进行分析、画像。那么有没有一种登录方式,它的所有信息都只保存在客户端和后端,并不牵扯三方平台授权,最大化的保证用户隐私呢?Web3.0给我们提供了一种选择:MetaMask。* x* c9 ^  `5 D3 c2 x% Y6 }

0 I: c/ l$ W( u3 s    MetaMask
+ }2 G8 U& _# ]( E    MetaMask是用于与以太坊区块链进行交互的软件加密货币钱包。MetaMask允许用户通过浏览器插件或移动应用程序访问其以太坊钱包,然后可以使用这些扩展程序与去中心化应用程序进行交互。当然了,首先需要拥有一个MetaMask钱包,进入https://chrome.google.com/websto ... oehlefnkodbefgpgknn $ W' D% Y6 ^  i
% t$ S( u0 f8 [) P1 O8 S
    安装metamask浏览器插件:  n" ~' k# n2 Y8 d2 f0 R" ]
* x6 p2 E- Y' I- A" Z8 \

/ \/ {: L  I3 y) }9 b6 P$ A  随后点开插件,创建账号,记录密码、钱包地址、以及助记词等信息。
+ m8 d5 y& j& G3 |; H! ?8 m
+ b% g- \( z1 n. ?$ X    安装好插件之后,我们就可以利用这个插件和网站应用做交互了。
' F5 _. m: G7 i
. H- P8 j0 Y, r1 q9 U# z    钱包登录流程
7 `% O, y" k3 ~% k    登录逻辑和传统的三方登录还是有差异的,传统三方登录一般是首先跳转三方平台进行授权操作,随后三方平台将code验证码返回给登录平台,登录平台再使用code请求三方平台换取token,再通过token请求用户账号信息,而钱包登录则是先在前端通过Web3.js浏览器插件中保存的私钥对钱包地址进行签名操作,随后将签名和钱包地址发送到后端,后端利用Web3的库用同样的算法进行验签操作,如果验签通过,则将钱包信息存入token,并且返回给前端。/ m3 u0 m+ q$ u  H

# a& `& y7 x5 N" M
4 O) X/ k1 W% e/ I2 ^0 @
5 w+ E6 c. R& N前端签名操作6 G0 d3 C9 w  }/ Z+ w4 m6 \
    首先需要下载前端的Web3.0操作库,https://docs.ethers.io/v4/,随后集成到登录页面中:
3 h& }% J* U$ I& t
7 l. Q) K8 P7 j* a7 M
" x; ~  ?  T/ n- S% S) n" C
  1. <script src="{{ static_url("js/ethers-v4.min.js") }}"></script>
    3 V" Q' G# d- Q! ~! S* b) J
  2. <script src="{{ static_url("js/axios.js") }}"></script>
    9 B  S* g/ k4 [. E
  3. <script src="{{ static_url("js/vue.js") }}"></script>
复制代码
# T( E. n) r- K+ Y$ ~
- ?' a; h3 P2 ]4 o

% k! F3 c9 |! u& |7 c3 M这里我们基于Vue.js配合Axios使用。% |6 I! N# j5 ]- k" M7 o3 ~6 y
$ c/ o& u) A9 t* t2 }3 i! c! l
    接着声明登录激活方法:
) `- F  L9 e! E: }3 F+ k. M% Y3 f9 X5 }$ V' F: M8 O  {0 w. T
  1. sign_w3:function(){+ j6 O9 F3 l3 |0 R) t

  2. " q* s+ Q( d$ f, i
  3.                     that = this;
    , H" g0 C( {, A+ G. D- n$ [: o
  4.                     ethereum.enable().then(function () {- z( Z, W& s9 }5 W0 m

  5. " I2 F8 V3 D- M, x: S" A
  6.     this.provider = new ethers.providers.Web3Provider(web3.currentProvider);$ n; m4 b5 x7 O; f6 \! ~
  7. * n3 F# s7 d( j" y( b
  8.     this.provider.getNetwork().then(function (result) {
    , V$ Y' K8 f; B. `8 `$ a  Z
  9.         if (result['chainId'] != 1) {
    $ f! f7 n$ M4 ~' X! G
  10. ; p0 f* [! Y* d# \0 X5 ]
  11.             console.log("Switch to Mainnet!")
    ; {( A! v6 ]) f& o! b/ s" Y

  12. ! i; h7 n" T9 r- L
  13.         } else { // okay, confirmed we're on mainnet
    $ K5 h3 K7 j" K7 x6 ?, J

  14. $ B8 P8 R/ Y$ C3 r8 a! E" y
  15.             this.provider.listAccounts().then(function (result) {( _* g* D6 K# ?0 h3 l7 V: Q
  16.                 console.log(result);
    7 B/ _& k- E! k, R
  17.                 this.accountAddress = result[0]; // figure out the user's Eth address
    * H& l  M0 x2 C
  18.                 this.provider.getBalance(String(result[0])).then(function (balance) {
    9 n/ P! s* ?- X$ ~7 N
  19.                     var myBalance = (balance / ethers.constants.WeiPerEther).toFixed(4);2 P, G" ?7 ?0 d5 J1 o+ S+ ]' a
  20.                     console.log("Your Balance: " + myBalance);5 Y2 c. I! T: h( F; z
  21.                 });
      c9 L$ {. |% i5 e/ ?
  22. : m3 A6 z5 X* h; [! E; V5 c+ t
  23.                 // get a signer object so we can do things that need signing/ S- ~9 w" @! ^$ N/ Z
  24.                 this.signer = provider.getSigner();
    6 E: h' N7 A) f/ B8 I  e7 l4 d2 h

  25. + N3 i5 _) p" o8 L! s
  26.                 var rightnow = (Date.now()/1000).toFixed(0)- s8 \, ]' W: S( G' z  r* @9 M
  27.         var sortanow = rightnow-(rightnow%600)8 b5 p; {3 e# w2 r0 o0 K7 f. F

  28. / ?! G+ N4 f" t4 I
  29.         this.signer.signMessage("Signing in to "+document.domain+" at "+sortanow, accountAddress, "test password!")1 j3 F  A1 k) g7 L
  30.             .then((signature) => {               that.handleAuth(accountAddress,signature);
    ' W' F- H% L  h: N
  31.             });8 m* Y  i6 R! |! a# K, P: ^) D5 Z

  32. ; B9 N& i' L. I/ l
  33.                 console.log(this.signer);/ ^8 M4 P) {/ j# p6 T3 l
  34.             })
    ; e  M5 J2 q8 v8 v" A$ S
  35.         }
    ' ^! P) s& f( |: E% ~
  36.     })
    8 G4 b/ G/ M* c7 m: n
  37. })
    & @+ V3 x! S1 Q4 H4 B
  38. 7 T2 s3 B# H% w' a1 a  z8 |
  39.                 },
复制代码
通过使用signMessage方法返回签名,这里加签过程中使用基于时间戳的随机数防止未签名,当前端签名生成好之后,立刻异步请求后台接口:2 P$ E) ]" |7 r( p

& ]# p* J6 R; g4 |+ r8 I
  1. //检查验证
    . ~& t5 |8 Z: {$ _0 U( k
  2.                 handleAuth:function(accountAddress, signature){
    $ |/ v* U% g/ _: W+ z1 a' f" o

  3. 0 ^; I+ t# _: a
  4. $ p8 Q! i, {' R' ~' r
  5.                     this.myaxios("/checkw3/","post",{"public_address":accountAddress,"signature":signature}).then(data =>{
    " `1 @# T5 B1 `+ |0 w

  6. 7 k/ G2 w9 q; o
  7.                         if(data.errcode==0){& A4 K8 {. N( W+ A9 @9 }9 Z6 A
  8.                             alert("欢迎:"+data.public_address);! K) s! Y% Y  }. F
  9.                             localStorage.setItem("token",data.token);1 [2 o8 T2 k( x8 g
  10.                             localStorage.setItem("email",data.public_address);; A2 N) X$ [. z
  11.                             window.location.href = "/";. ~9 y7 k0 b! d* {- p# A3 z
  12.                         }else{
    + J* {! \3 `9 @! ~/ B$ b) Z
  13.                             alert("验证失败");
    + T3 G5 k+ J8 G8 @: X
  14.                         }5 C# l/ q$ x6 i
  15.                  });
    4 F7 ^, H' A, z; L) Z

  16. ) _8 m5 w; V3 r, Z6 g; g

  17. 9 g: h0 W* \0 M( n# h
  18. 9 I8 o$ Z1 X" P5 f! U8 v
  19.                 }
复制代码
这里将当前账户的钱包地址和签名传递给后端,如图所示:0 J! }) v6 V: G6 v" v+ \

9 W& ^- v* P; N8 }& b2 b6 T
; h* R0 Z( X' I* R; w9 @& \1 n8 v$ [5 ^# C5 ]

7 I5 r- \9 p" O" Y" y 随后创建异步视图方法:7 c* V, A: Y% A: N6 w
  1. from tornado.web import url$ L3 N- s* B9 o; K$ I
  2. import tornado.web3 U0 a* P8 B7 F6 @' ~* r
  3. from tornado import httpclient
    4 h* d7 _% c5 b- X4 b2 x7 A
  4. from .base import BaseHandler% z- {; c9 S: b
  5. from web3.auto import w3
    1 R) Y) W1 _' K+ m6 M5 i
  6. from eth_account.messages import defunct_hash_message
    # j( b6 w* e1 v1 M3 D& e" @2 _
  7. import time
    2 O) y8 I( w! ^2 a/ U" S2 f
  8. - O! H1 K! y' x! h* M6 _5 @
  9. class CheckW3(BaseHandler):
    + P5 ~9 h7 J% m: i8 H% \& ?

  10. " q4 q) u0 W0 L" s9 C! \
  11.     async def post(self):
    ( G% F( n1 B. Z- j3 r+ t5 E

  12.   e6 u$ N" m' H1 e& ~0 s
  13.         public_address = self.get_argument("public_address"): D6 _( f$ B) f8 ~1 P
  14.         signature = self.get_argument("signature")
    + D0 h+ L. c+ A3 W# R

  15. 0 [' W  y- L6 P* g' g
  16.         domain = self.request.host5 m5 R& f4 }" s8 J
  17.         if ":" in domain:
    1 i' g3 g8 v7 U) G0 V; _
  18.             domain = domain[0:domain.index(":")]% c$ D  G+ y1 w. o/ Q9 _6 u

  19. 8 d8 r0 H7 o: k4 O% I+ _8 T2 Z
  20.         now = int(time.time())3 ^7 d; u/ V# S% H/ }
  21.         sortanow = now-now%600
    6 Y) {/ x' X; P- @: b) k
  22.    
    ; Z0 h8 R: t. u& Y2 h+ g4 O
  23.         original_message = 'Signing in to {} at {}'.format(domain,sortanow)9 c, [# N# B' L2 [; Z) Z: I1 i" A
  24.         print("[+] checking: "+original_message)
    1 T2 s3 W! C. U. u0 y+ S
  25.         message_hash = defunct_hash_message(text=original_message)/ O& M3 [* C5 C% L1 [
  26.         signer = w3.eth.account.recoverHash(message_hash, signature=signature)
    1 c+ r2 X3 l  t# p) d  F

  27. 4 s1 [/ S* u8 `3 ]- X; T2 M
  28.         if signer == public_address:9 g: O6 E( J8 Q1 H2 H5 o4 m, ~
  29.             try:
    0 X" c8 }3 u% ~3 A4 @$ j
  30.                 user = await self.application.objects.get(User,email=public_address)
    3 y# x$ m: \  d! V" r( \# V
  31.             except Exception as e:8 i; M% @% `1 Y* M, K- k
  32.                 user = await self.application.objects.create(User,email=public_address,password=create_password("third"),role=1)5 O$ s- [1 U8 @: r7 Y6 G

  33. $ g6 S) _, @$ P. j+ M
  34.             myjwt = MyJwt()
    & k& M5 M# M6 z( A1 Q# O. }3 x+ _
  35.             token = myjwt.encode({"id":user.id})6 q$ U/ }' l6 E3 `. k  Z; ^
  36.             self.finish({"msg":"ok","errcode":0,"public_address":public_address,"token":token})
    : o/ Z1 }$ g* x; a0 D
  37.         else:
    ! z  Q$ l& p  P' r% p
  38.             self.finish({"msg":"could not authenticate signature","errcode":1})
复制代码

/ F0 ?0 X& |: L4 J) Z9 g   这里通过recoverHash方法对签名进行反编译操作,如果反编译后的钱包地址和前端传过来的钱包地址吻合,那么说明当前账户的身份验证通过:
( t6 _9 R5 t, n+ i) {9 Y* j
. _9 d$ m3 ~( ^% l6 H$ u6 v% U; Z2 B8 r) H/ Y4 O! G) [! p& ?

) U( G4 W% t+ I/ g
9 s+ m' I! F, g; v' [  x+ Z 当验签通过之后,利用钱包地址在后台创建账号,随后将钱包地址、token等信息返回给前端,前端将其保存在stroage中即可。; y3 q) u2 A! H8 C5 ~9 r5 v
2 [+ o# Q1 _  G: U1 L( f
    结语5 `- ^/ l1 d3 G

6 G# h- t$ B. N    没错,将至已至,未来已来,是时候将Web3.0区块链技术融入产品了,虽然有些固有的思维方式依然在人们的脑海挥之不去,但世界却在时不我待地变化着,正是:青山遮不住,毕竟东流去!项目开源在https://github.com/zcxey2911/Tornado6_Vuejs3_Edu - \% q4 {  g: G9 ?* C: F1 U
% i( @  W' p& U$ o- d

& u) |; d) v' Y+ ?" `- [- ^/ U
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

江左没浪 小学生
  • 粉丝

    18

  • 关注

    0

  • 主题

    7