Hi 游客

更多精彩,请登录!

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

/ F5 o: r, b$ q8 E: G    MetaMask% ^2 J2 A* j7 N" h( E/ {; r$ N
    MetaMask是用于与以太坊区块链进行交互的软件加密货币钱包。MetaMask允许用户通过浏览器插件或移动应用程序访问其以太坊钱包,然后可以使用这些扩展程序与去中心化应用程序进行交互。当然了,首先需要拥有一个MetaMask钱包,进入https://chrome.google.com/websto ... oehlefnkodbefgpgknn
  Y8 u$ }% P/ g: q: o* t, |# a- B$ x7 ]/ i
    安装metamask浏览器插件:
( f( S' X0 Z$ j4 r/ ~+ V( ~/ V' d. }4 C% i

" G8 }2 r3 l9 u- m0 j  随后点开插件,创建账号,记录密码、钱包地址、以及助记词等信息。
7 }8 B* V: M  f, ^3 r, R  C& U0 k/ v. v  v! `) S# M
    安装好插件之后,我们就可以利用这个插件和网站应用做交互了。, T) r! z1 @* X9 S5 a% e
# X1 }2 }7 q; `0 p4 h  Z0 y- P, f
    钱包登录流程
7 i' l1 [: Y7 v; L1 u# }6 |    登录逻辑和传统的三方登录还是有差异的,传统三方登录一般是首先跳转三方平台进行授权操作,随后三方平台将code验证码返回给登录平台,登录平台再使用code请求三方平台换取token,再通过token请求用户账号信息,而钱包登录则是先在前端通过Web3.js浏览器插件中保存的私钥对钱包地址进行签名操作,随后将签名和钱包地址发送到后端,后端利用Web3的库用同样的算法进行验签操作,如果验签通过,则将钱包信息存入token,并且返回给前端。
6 }2 g7 w% t0 V! J% b6 f2 d5 B3 ]! p" I- {2 d2 P
$ S$ i& O5 @( ^) C  H
; d! `1 l7 _* i) e& Q5 |  k
前端签名操作4 s) P* \) a1 D; j0 |  N/ y
    首先需要下载前端的Web3.0操作库,https://docs.ethers.io/v4/,随后集成到登录页面中:# i* D9 G  U7 ~( D! w4 Q$ c6 u

/ l6 d0 R; A# t  D- m1 K" }' R# ]8 {% V
  1. <script src="{{ static_url("js/ethers-v4.min.js") }}"></script>9 z, _; Y- {! G2 y, [
  2. <script src="{{ static_url("js/axios.js") }}"></script>6 ^6 \& M; _0 ~2 l" G0 N
  3. <script src="{{ static_url("js/vue.js") }}"></script>
复制代码
' }+ Y+ M7 W; S" G

- ]& ], q: x/ I
6 a5 y9 \% v) }; K这里我们基于Vue.js配合Axios使用。
$ X, ^% m) _, R' T# o' O" S3 z! F+ }" e% ]
    接着声明登录激活方法:
3 D7 ]( m# b5 z9 Q3 A6 x9 P
2 f6 X' W+ d2 x! F- @! ]! `
  1. sign_w3:function(){
    , z$ d0 p3 D) J
  2. 8 `" c& u% m5 Z7 w* z# \+ T  `5 S5 A
  3.                     that = this;% k6 Z2 a4 e9 K: W' r8 A! Z
  4.                     ethereum.enable().then(function () {. ~& d6 q$ M: n8 A. s# J
  5. 6 {, _' m2 I9 E: l0 @* P, Q
  6.     this.provider = new ethers.providers.Web3Provider(web3.currentProvider);, s0 I4 H, V( l( n( I- I% n, t. H& i" I

  7. 2 [- z' R9 l, F: {5 ?( S. z8 `* a
  8.     this.provider.getNetwork().then(function (result) {. U1 X/ N( g. u
  9.         if (result['chainId'] != 1) {! w5 R) g% g' l& p- T* S
  10. ) H( X, h( D; u
  11.             console.log("Switch to Mainnet!")5 P6 F; V8 I7 D  l7 k

  12. 1 f- K: E  D0 \: ]' F+ I
  13.         } else { // okay, confirmed we're on mainnet
    1 v( z+ h% @( @3 l# _4 w/ W, V: j
  14. : M4 R" k$ d' y  s6 N
  15.             this.provider.listAccounts().then(function (result) {
    $ e' c4 T6 C. e5 G: k
  16.                 console.log(result);
    . H$ Q+ ?4 y3 n9 ^' B& t
  17.                 this.accountAddress = result[0]; // figure out the user's Eth address# ~, A  Z: ^* |4 _2 ^- A
  18.                 this.provider.getBalance(String(result[0])).then(function (balance) {% Z; }, Z- g, {/ }" m" Z  D- `
  19.                     var myBalance = (balance / ethers.constants.WeiPerEther).toFixed(4);+ U8 n6 R+ u5 U8 r
  20.                     console.log("Your Balance: " + myBalance);# k! c  u, G) i7 P" g
  21.                 });
    $ @  W( l. x7 X, M- U7 N

  22. # p$ f) o4 l" k
  23.                 // get a signer object so we can do things that need signing6 B  q4 K$ N6 s. o, K* E% c
  24.                 this.signer = provider.getSigner();5 H7 X( b1 b" n. C0 a2 E
  25. + |+ m" c4 L0 E% Z) y
  26.                 var rightnow = (Date.now()/1000).toFixed(0)% U2 r/ C( e- Q* ?
  27.         var sortanow = rightnow-(rightnow%600)! ]2 n  H1 ^6 p6 c3 B0 u7 y1 D
  28. $ j/ I& P* S9 ~) ~
  29.         this.signer.signMessage("Signing in to "+document.domain+" at "+sortanow, accountAddress, "test password!")
    - _8 g  {+ m9 P! C; l
  30.             .then((signature) => {               that.handleAuth(accountAddress,signature);7 H# e$ X, a) N
  31.             });0 t& ^  H. n2 R$ P& u# S
  32. 1 `6 b( b9 D/ r* }' _4 Z- c  i9 c
  33.                 console.log(this.signer);
    4 K" h1 E" H( M4 m; y
  34.             })
    8 p: ^3 k/ |; _2 K
  35.         }
    " W# C2 ?0 a, e" M# T* g. q
  36.     })- J( `6 A1 g0 G6 F' M6 {: F8 |
  37. })
      ?% C/ M' }2 B, f: b' z3 U) I

  38. 7 X* w5 \* f' y5 d
  39.                 },
复制代码
通过使用signMessage方法返回签名,这里加签过程中使用基于时间戳的随机数防止未签名,当前端签名生成好之后,立刻异步请求后台接口:  a- r) G- F# w( {9 d& v+ \

* k0 [" B8 J% H' Y  d: p
  1. //检查验证! A* Y# }# F& d& a
  2.                 handleAuth:function(accountAddress, signature){1 a. a/ k2 ~4 t. E# o5 R

  3. # F1 @1 v0 A2 d: X) V  |' l
  4. . E% ^+ Q4 q/ [' _. \# f
  5.                     this.myaxios("/checkw3/","post",{"public_address":accountAddress,"signature":signature}).then(data =>{% n5 @* q" F7 N4 i5 W/ t6 b: B
  6. % h! N" N, c' m5 A" R; g) N; x6 X4 H
  7.                         if(data.errcode==0){
    + M3 K; B3 G5 o+ p" e( {5 t. n
  8.                             alert("欢迎:"+data.public_address);
    " i2 H. @! g5 s% \0 X/ y  @1 V
  9.                             localStorage.setItem("token",data.token);
    & [: C8 R* t- l+ A% p
  10.                             localStorage.setItem("email",data.public_address);
    ! o, i+ F+ b0 x; _  w
  11.                             window.location.href = "/";+ \+ B4 L% M/ x  T  B+ O8 T1 A
  12.                         }else{! m+ v) ?+ Y4 D! n
  13.                             alert("验证失败");+ {9 r2 o$ g& r- W
  14.                         }
    ; r3 ?$ Z8 Q9 a2 }
  15.                  });
    6 @7 \6 }" z9 o' c: b3 C

  16. 2 I+ N7 f' L% s4 @1 j8 J- G1 H

  17. ) R  l3 T" `* E3 ^
  18. 8 H; G# r* f2 _5 x& K6 q, f
  19.                 }
复制代码
这里将当前账户的钱包地址和签名传递给后端,如图所示:
1 y( Y  Q& N. {; s8 X2 G
& l# U6 I$ m& L5 B) z3 V" Y
- T) N0 w) A$ {2 Y2 X
# p# f7 ~1 w0 q8 d  l1 F0 x, t- v) A4 R; f' @
随后创建异步视图方法:! g9 m  F1 w- s$ d/ b
  1. from tornado.web import url( q" v- I1 u3 r) \% n* \7 j
  2. import tornado.web, p! u- N$ @- Y) y# S) P
  3. from tornado import httpclient4 K  ~5 m5 s! R! ~7 g9 O! O
  4. from .base import BaseHandler
    8 N0 r( F9 }- r- D9 C" L8 J# W% e& c
  5. from web3.auto import w3
    6 d, }' F: U; K% x- c0 o* b: A' b
  6. from eth_account.messages import defunct_hash_message
    1 j9 @9 I1 K6 w7 h, d
  7. import time
    8 m: R2 D; l. q- E" `
  8. & C  C# `, Z! r7 E9 K; T3 m+ @
  9. class CheckW3(BaseHandler):
    ; V0 F/ h0 e8 Q* u
  10.   N3 `& W! X( Y. R# l0 N
  11.     async def post(self):
    2 z( j& D' g% O

  12. 1 n" [, w8 E4 p& M/ B% B1 f/ }
  13.         public_address = self.get_argument("public_address")& S% e( U" U% x& p5 g. m
  14.         signature = self.get_argument("signature")- n7 B) ~$ P( B# F, b$ v
  15. 2 F9 U% j1 \* n; Y
  16.         domain = self.request.host; l, c& o2 F5 }/ ]2 E
  17.         if ":" in domain:
    7 O5 @0 j6 b! o4 x
  18.             domain = domain[0:domain.index(":")]1 S2 S) i' }8 Y: g1 k/ S

  19. 2 Q+ m, P) B: E
  20.         now = int(time.time())# ]3 T& \: Z0 _3 H' F. E/ ^! V
  21.         sortanow = now-now%600
    ( W$ i, H# Y; M  r
  22.    
    ( A' X# j- E/ B3 G( i4 ~
  23.         original_message = 'Signing in to {} at {}'.format(domain,sortanow)! u: i1 i3 a4 Z
  24.         print("[+] checking: "+original_message)! K. t  U" {/ P* j
  25.         message_hash = defunct_hash_message(text=original_message): e3 t5 ]; P$ u  A- ?+ B2 x
  26.         signer = w3.eth.account.recoverHash(message_hash, signature=signature)
    / |1 M" c/ ]: p

  27. - I7 G5 M5 v0 p5 w  u
  28.         if signer == public_address:; U% a( ]. e' V
  29.             try:
    ' f! I, _- |6 N' y
  30.                 user = await self.application.objects.get(User,email=public_address), k+ c* f, x* ?' x/ h
  31.             except Exception as e:/ o1 k/ Z( W! b! d5 v2 \
  32.                 user = await self.application.objects.create(User,email=public_address,password=create_password("third"),role=1)
    # i% f8 \. U* t( G$ d- F' J7 E: w

  33. " m3 f# }5 j. F
  34.             myjwt = MyJwt()1 v; L8 H$ H2 K, z2 j$ J* U
  35.             token = myjwt.encode({"id":user.id})
    / S9 g( r% b& w# Z6 Z3 G! c  ]5 t
  36.             self.finish({"msg":"ok","errcode":0,"public_address":public_address,"token":token})
    ; Y6 L: l+ ^) D5 N
  37.         else:
    + ^; o; o+ K  q" M
  38.             self.finish({"msg":"could not authenticate signature","errcode":1})
复制代码
  o7 F* @+ V+ v2 R  y  v; ^
   这里通过recoverHash方法对签名进行反编译操作,如果反编译后的钱包地址和前端传过来的钱包地址吻合,那么说明当前账户的身份验证通过:
. b3 P2 i- Z# i
" k. c6 Q7 s( J
$ I, |3 [) T$ T; T% \
! @1 Z8 K! `3 L7 ~% b+ C0 @& q
& ]+ _7 j' J7 |" w0 i( H9 V9 G' z 当验签通过之后,利用钱包地址在后台创建账号,随后将钱包地址、token等信息返回给前端,前端将其保存在stroage中即可。
; o# ^2 R, v& R8 k1 ~$ y# Y) E9 ?6 ~6 a0 X/ x: _
    结语4 \0 }: Y% P# j$ {7 H  c

9 J2 u# m& l' g1 P, \    没错,将至已至,未来已来,是时候将Web3.0区块链技术融入产品了,虽然有些固有的思维方式依然在人们的脑海挥之不去,但世界却在时不我待地变化着,正是:青山遮不住,毕竟东流去!项目开源在https://github.com/zcxey2911/Tornado6_Vuejs3_Edu
$ z( i: |3 g5 D' m8 F! d9 N* h+ ]
5 @- q  `3 _0 x- @- {6 h
# C5 I# x" N+ j2 U+ n6 Z
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

江左没浪 小学生
  • 粉丝

    18

  • 关注

    0

  • 主题

    7