Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
    今天去中心化身份逐渐被广泛采用。用户的部分在线活动在链上是公开的,可通过加密钱包搜索到,用户在链上创造、贡献、赚取和拥有的东西,都反映了他们的喜好,也逐渐积累成该用户的身份和标识。
) c1 o- e' g- v, |8 _4 I( x- W; @% x$ }0 i3 V; \/ C+ U+ P% Y
    当我们的用户厌倦了传统的电子邮件/密码注册流程时,他们会选择Google、GitHub等社交登录方式,这种方式虽然节约了用户的时间,但登录信息也会被第三方平台记录,也就是说我们用平台账号做了什么,平台都会一目了然,甚至还会对我们的行为进行分析、画像。那么有没有一种登录方式,它的所有信息都只保存在客户端和后端,并不牵扯三方平台授权,最大化的保证用户隐私呢?Web3.0给我们提供了一种选择:MetaMask。
) l' ?$ e1 n4 W5 l- N) x" d# U. M- D0 M# X1 U; A
    MetaMask
1 E8 ?) n/ W- s& N7 Q1 Y7 K    MetaMask是用于与以太坊区块链进行交互的软件加密货币钱包。MetaMask允许用户通过浏览器插件或移动应用程序访问其以太坊钱包,然后可以使用这些扩展程序与去中心化应用程序进行交互。当然了,首先需要拥有一个MetaMask钱包,进入https://chrome.google.com/websto ... oehlefnkodbefgpgknn
- |, v" j% N8 ~- H" l! W  `; A' L  L0 @0 \
    安装metamask浏览器插件:1 {. Q& T8 f2 I  c# _2 X+ X

2 u( s& b! L- d2 Z, F( _$ E! s- a* L: @) o' t2 p% E
  随后点开插件,创建账号,记录密码、钱包地址、以及助记词等信息。' b* T( ^: `& v, N

+ l2 o. i7 Z( M) r: x    安装好插件之后,我们就可以利用这个插件和网站应用做交互了。7 H+ C- Z" B, m# Y

% o/ y; _. O) @7 p4 j! q4 v6 Q    钱包登录流程
5 w7 P. A' h  k( B+ z$ p& ]$ {    登录逻辑和传统的三方登录还是有差异的,传统三方登录一般是首先跳转三方平台进行授权操作,随后三方平台将code验证码返回给登录平台,登录平台再使用code请求三方平台换取token,再通过token请求用户账号信息,而钱包登录则是先在前端通过Web3.js浏览器插件中保存的私钥对钱包地址进行签名操作,随后将签名和钱包地址发送到后端,后端利用Web3的库用同样的算法进行验签操作,如果验签通过,则将钱包信息存入token,并且返回给前端。2 `; y- X+ P0 _

) r# M  I5 N& j9 V4 n, d  g- E0 q" v  o, c0 A
3 j/ c* P: O. k# ?6 f9 }0 P
前端签名操作
# C$ `' z" b% b    首先需要下载前端的Web3.0操作库,https://docs.ethers.io/v4/,随后集成到登录页面中:
) H) u$ K% A; i: K% U0 h5 h# \: E
! e+ j4 ~: I/ T0 `( U  r- U6 J; a$ h6 w& J/ n- i
  1. <script src="{{ static_url("js/ethers-v4.min.js") }}"></script>7 s2 w* q6 Q1 z8 D1 @0 J* V
  2. <script src="{{ static_url("js/axios.js") }}"></script>
    " V" _( ~" \4 S+ G0 d
  3. <script src="{{ static_url("js/vue.js") }}"></script>
复制代码
$ S7 G7 a% {# f% q2 E

9 ^, l! k* a% `% q! L6 o* z" p: V" S- ?  ^0 y0 N8 C) ]: b
这里我们基于Vue.js配合Axios使用。; K  O4 D; J  [  x. J

" [+ c/ G  Y% t( @7 _7 G* g    接着声明登录激活方法:
* `& |8 z$ g3 _
3 U7 M8 D" Y4 b
  1. sign_w3:function(){. T+ \+ k% p4 T

  2. / t0 Z& G. L6 ~  o/ h3 r: u
  3.                     that = this;
    9 d5 n. v6 T# o, Y# ~% ^' c
  4.                     ethereum.enable().then(function () {/ Z0 P' ^/ I, Z& }

  5. ' f* i; X4 U: S8 B0 c( ^5 X
  6.     this.provider = new ethers.providers.Web3Provider(web3.currentProvider);6 u; q! O* I- E6 ]0 G1 U8 L7 E
  7. ! J' \& R6 R/ ^5 _: }$ q: G
  8.     this.provider.getNetwork().then(function (result) {
    ( e# p2 m% v* U) N" B
  9.         if (result['chainId'] != 1) {# X" b5 y! {2 w% ]

  10. 3 A; F' A* M1 ~, [
  11.             console.log("Switch to Mainnet!")" K! y9 R; [4 f( C: \8 q( u" z

  12. % J& n! J; E- [; h# R
  13.         } else { // okay, confirmed we're on mainnet
    ' Y) l+ @/ ^- h
  14. ' [* G6 i* i' x& B# B
  15.             this.provider.listAccounts().then(function (result) {$ d  m. U; z- W6 C) F
  16.                 console.log(result);
    ; Q; i' r$ h, t. f9 }2 ^' t
  17.                 this.accountAddress = result[0]; // figure out the user's Eth address
      D% g' R( C  l3 M7 H$ x8 }
  18.                 this.provider.getBalance(String(result[0])).then(function (balance) {( v- L$ g- a% F
  19.                     var myBalance = (balance / ethers.constants.WeiPerEther).toFixed(4);
    8 K& {1 R. ^: [( S3 Y5 Q
  20.                     console.log("Your Balance: " + myBalance);: g* K9 ]8 t: G7 [0 D. g$ E
  21.                 });
    ) u3 u' a& U7 c0 \
  22. % B: v  `3 X/ V, E
  23.                 // get a signer object so we can do things that need signing
    4 y" c* P$ ]* a7 |
  24.                 this.signer = provider.getSigner();  p. Q! b5 d8 H7 q/ h+ t
  25.   y# B7 W0 E8 q; L
  26.                 var rightnow = (Date.now()/1000).toFixed(0)$ z$ U  w# t  b$ x) [, u: P
  27.         var sortanow = rightnow-(rightnow%600)8 a, T( Y% q4 C% o7 U6 j
  28. & Q5 W6 u9 x, D# C! ?3 q' J
  29.         this.signer.signMessage("Signing in to "+document.domain+" at "+sortanow, accountAddress, "test password!")
    % r) r( |1 V+ o2 v
  30.             .then((signature) => {               that.handleAuth(accountAddress,signature);1 U7 o" b# k2 j( d* }/ f
  31.             });6 Q0 K1 C# p3 U0 i: h1 V. S
  32. % S1 w3 j$ ~$ T) g) z" X
  33.                 console.log(this.signer);& ^) \1 K, u4 ?* Q
  34.             })
    " c, }3 ~( q# R  d3 j& ?
  35.         }
    ! \' g$ N0 S6 m7 I$ K6 i/ D* Z
  36.     })
    - P3 I) I- V: v
  37. })
    - y( t' Q+ ?: K$ J! M7 t9 z. \6 b
  38. 8 i# C- h2 g' e* x
  39.                 },
复制代码
通过使用signMessage方法返回签名,这里加签过程中使用基于时间戳的随机数防止未签名,当前端签名生成好之后,立刻异步请求后台接口:
* n; ]- _* v) I8 c
; S; n6 X6 j6 v* }
  1. //检查验证5 A) q) w2 s9 e0 F! N$ \/ H, W( L
  2.                 handleAuth:function(accountAddress, signature){6 ^7 E3 g3 ~" M, |, j' r' I
  3. ' c) N7 Q2 o3 R
  4. . y0 @: }5 ]! I# x! H" k8 x
  5.                     this.myaxios("/checkw3/","post",{"public_address":accountAddress,"signature":signature}).then(data =>{
    ! P9 A$ D0 V0 _" M
  6. * y1 f. L$ R; A1 f6 g# f
  7.                         if(data.errcode==0){
    / i& D! z% k# u4 J3 z: ]
  8.                             alert("欢迎:"+data.public_address);
    1 V# i5 T. p1 w% h; l1 W' m9 ^
  9.                             localStorage.setItem("token",data.token);* D" n/ S3 R& X. O4 [- O
  10.                             localStorage.setItem("email",data.public_address);" l! \6 z; X0 N: V0 L* ?; Z, Q0 J# E
  11.                             window.location.href = "/";& I( }, {; a" y. E" @' j/ [- v) [
  12.                         }else{# r: k! U' @" t8 Q1 X" g
  13.                             alert("验证失败");
    4 F$ }0 I4 D9 c
  14.                         }
    6 L0 @  b! j$ i
  15.                  });/ I  M5 |3 l* B

  16. , E; B( I1 \' X% o% t$ B7 {# Y
  17. ! ^) T! R# i; q$ l

  18. * j, L1 X+ W* q" x
  19.                 }
复制代码
这里将当前账户的钱包地址和签名传递给后端,如图所示:5 ~8 x4 Z5 D4 N5 ~0 W- H
; F7 h+ M# a. g! w  V

5 y3 H7 o' K+ L5 o: j
- L' }* `. K# P7 z+ t3 ~9 s- z* ^1 A0 I# E' C' ?2 K4 a0 v3 g4 h
随后创建异步视图方法:1 |" p! |" }% K
  1. from tornado.web import url9 G/ ~; m1 r2 o* l
  2. import tornado.web0 A, n) s! o+ B! v$ }
  3. from tornado import httpclient
    7 {. }- t4 k( ^
  4. from .base import BaseHandler
    : J6 j9 a" M% L% W
  5. from web3.auto import w3( G! D! t4 ~+ K; M: |, L
  6. from eth_account.messages import defunct_hash_message, Z+ d; _) \' S. O$ q' H3 q
  7. import time+ ], x9 y+ h0 [6 q4 G

  8. & ~; u" o( o, j& f2 Q" `/ O
  9. class CheckW3(BaseHandler):
    . r3 u5 C* L$ X% |1 a
  10. ) w$ s+ y" T9 t9 g% [
  11.     async def post(self):. k7 g" X! P7 j( u

  12. - x1 T1 d- s8 e+ b
  13.         public_address = self.get_argument("public_address")# q" h$ h8 b5 Y+ D3 c$ @
  14.         signature = self.get_argument("signature")5 E# }0 ]) L* b4 M9 N$ O3 ?$ \
  15. . G- B/ |' W! I1 T  t/ E3 z
  16.         domain = self.request.host% J" Q, Q% L0 M; a) J" J5 l: T
  17.         if ":" in domain:! T6 r$ H8 G/ y* m) E
  18.             domain = domain[0:domain.index(":")]
    3 c4 R0 f: Q6 i6 e9 Q
  19. . [5 c- ]! p2 C0 C# ?1 Q5 _
  20.         now = int(time.time())
    6 Y8 g, ?9 [' E
  21.         sortanow = now-now%600
    " o8 a2 j# v9 _$ w5 h# V( m
  22.      s, K1 b1 j  @. k$ c+ W8 q
  23.         original_message = 'Signing in to {} at {}'.format(domain,sortanow)% S; ~! H+ \- b6 l5 D4 ^+ `) q
  24.         print("[+] checking: "+original_message)
    5 n8 c3 y8 N, n+ F2 b) I) [, C
  25.         message_hash = defunct_hash_message(text=original_message)
    ; N# M" I2 s  W$ I/ l
  26.         signer = w3.eth.account.recoverHash(message_hash, signature=signature)- P9 r4 Z( f! |, G3 d  i0 c6 I

  27. & l8 A& W3 L* j' e: U' I
  28.         if signer == public_address:
    % h$ L* g: X" K
  29.             try:% n( I9 ?* `2 o  R2 o
  30.                 user = await self.application.objects.get(User,email=public_address)
    # X4 ]. O& }! }2 G) t9 U+ |
  31.             except Exception as e:
    , _4 r  D7 p6 v4 W; Y! Z6 L: e
  32.                 user = await self.application.objects.create(User,email=public_address,password=create_password("third"),role=1)7 R% K* u, x# ]  H7 D! Q

  33.   H, ?% z# w0 x+ d7 N6 X- {
  34.             myjwt = MyJwt()
    ( M4 O' U: O$ q. ~& Z
  35.             token = myjwt.encode({"id":user.id})! B5 f8 u/ O, x
  36.             self.finish({"msg":"ok","errcode":0,"public_address":public_address,"token":token})! }# g1 ?" h2 N
  37.         else:3 `; f8 N7 J0 w3 R1 o- ~
  38.             self.finish({"msg":"could not authenticate signature","errcode":1})
复制代码

7 m" |4 j( j! W; q   这里通过recoverHash方法对签名进行反编译操作,如果反编译后的钱包地址和前端传过来的钱包地址吻合,那么说明当前账户的身份验证通过:7 }( O4 ^$ F/ v

8 {, ?+ j& k& R. J0 G% c# ^. ^1 v) R6 [0 t7 z+ f4 T2 _
3 B  e& Z" n: ^' n# h

0 K& U! k7 m5 L' j 当验签通过之后,利用钱包地址在后台创建账号,随后将钱包地址、token等信息返回给前端,前端将其保存在stroage中即可。
8 L# ^% T% o- S' @9 V4 x
5 o! Y, e: ?, J5 |0 M+ o    结语0 |! u, C) u( k/ H' }
) H0 F6 ]8 }0 {7 m5 @
    没错,将至已至,未来已来,是时候将Web3.0区块链技术融入产品了,虽然有些固有的思维方式依然在人们的脑海挥之不去,但世界却在时不我待地变化着,正是:青山遮不住,毕竟东流去!项目开源在https://github.com/zcxey2911/Tornado6_Vuejs3_Edu 9 s' E4 s: ?: o) r7 C
4 q7 O) a- m; C, m8 x

$ S; `9 F, ?) L: H2 Z4 w
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

江左没浪 小学生
  • 粉丝

    18

  • 关注

    0

  • 主题

    7