Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
    今天去中心化身份逐渐被广泛采用。用户的部分在线活动在链上是公开的,可通过加密钱包搜索到,用户在链上创造、贡献、赚取和拥有的东西,都反映了他们的喜好,也逐渐积累成该用户的身份和标识。
' c4 v- ^* O- G- c3 s$ `0 ^' D! a- W2 K, i: ^5 b4 V8 s! e
    当我们的用户厌倦了传统的电子邮件/密码注册流程时,他们会选择Google、GitHub等社交登录方式,这种方式虽然节约了用户的时间,但登录信息也会被第三方平台记录,也就是说我们用平台账号做了什么,平台都会一目了然,甚至还会对我们的行为进行分析、画像。那么有没有一种登录方式,它的所有信息都只保存在客户端和后端,并不牵扯三方平台授权,最大化的保证用户隐私呢?Web3.0给我们提供了一种选择:MetaMask。
) U" s4 _( t- t* c
# Y1 s9 ~( I& V4 _3 U' }    MetaMask) X+ h4 N8 @/ [% B; H
    MetaMask是用于与以太坊区块链进行交互的软件加密货币钱包。MetaMask允许用户通过浏览器插件或移动应用程序访问其以太坊钱包,然后可以使用这些扩展程序与去中心化应用程序进行交互。当然了,首先需要拥有一个MetaMask钱包,进入https://chrome.google.com/websto ... oehlefnkodbefgpgknn
0 ^6 f; t( V: k; V
9 h" b' i$ e+ [) H# |" G    安装metamask浏览器插件:# [7 N7 {# a4 V0 K  k
, j+ @% d' ]2 J- ?+ l! _

# y$ I9 |3 @/ e2 d: Q  随后点开插件,创建账号,记录密码、钱包地址、以及助记词等信息。
# S6 y* b2 ]9 d" y' _6 N
4 F" u! p8 L; v. P- D- Z    安装好插件之后,我们就可以利用这个插件和网站应用做交互了。' e) x$ q7 P9 k1 T

4 v% \( w) `7 G' I) ~: d& j    钱包登录流程  `2 T+ K5 E1 y8 |% n2 {! B) s1 |
    登录逻辑和传统的三方登录还是有差异的,传统三方登录一般是首先跳转三方平台进行授权操作,随后三方平台将code验证码返回给登录平台,登录平台再使用code请求三方平台换取token,再通过token请求用户账号信息,而钱包登录则是先在前端通过Web3.js浏览器插件中保存的私钥对钱包地址进行签名操作,随后将签名和钱包地址发送到后端,后端利用Web3的库用同样的算法进行验签操作,如果验签通过,则将钱包信息存入token,并且返回给前端。! P1 G0 A2 s0 Z) H1 K8 m- e- h

6 m& ]: E% l$ T2 @0 O
- o# C4 C/ a9 x6 \4 o2 ]5 o6 y7 F' g" N+ b) v' ?5 ^
前端签名操作! Z& f; u" M# }5 D
    首先需要下载前端的Web3.0操作库,https://docs.ethers.io/v4/,随后集成到登录页面中:9 c5 y8 l' f' {& y8 u) h$ l) s/ A

# ?5 t8 K( U) B/ N6 M0 s' I+ K+ K5 Y3 E- J6 A2 F; {. T
  1. <script src="{{ static_url("js/ethers-v4.min.js") }}"></script>, i. `8 l8 E$ b( k1 j
  2. <script src="{{ static_url("js/axios.js") }}"></script># A! q5 K, m* A, E# V
  3. <script src="{{ static_url("js/vue.js") }}"></script>
复制代码

  `; y7 L: U, U; r* q5 |( A6 L- U7 m4 d1 ]6 @8 a

* d7 Z+ ?, U4 @( g9 l0 D0 Z这里我们基于Vue.js配合Axios使用。0 j8 N' B9 o) b7 y" Q

3 C$ j# Y% W# B/ N( T2 ]    接着声明登录激活方法:
/ x7 A1 [$ M  ^7 @/ N( x
. l8 I) a6 y3 ^0 g3 J, A1 q9 [
  1. sign_w3:function(){9 H3 i/ o! q9 i) a5 i

  2. : \4 G( R  m  i7 K1 \- k
  3.                     that = this;
    . h: d+ d: L$ \) O
  4.                     ethereum.enable().then(function () {# D* E9 l# g8 e- t; P

  5. 9 z" H$ L  d# u
  6.     this.provider = new ethers.providers.Web3Provider(web3.currentProvider);; c% ^% J" K5 T2 ~

  7. / A7 n- E1 O: y
  8.     this.provider.getNetwork().then(function (result) {
    9 `# w7 C& z6 m; P' l: W
  9.         if (result['chainId'] != 1) {  m+ Y7 P! \& r$ {9 a9 u6 H" t6 c$ F

  10. + W% @, i, j& ~' b' y5 \
  11.             console.log("Switch to Mainnet!")3 W- }" O/ H; h; N- Y+ H# v2 M0 @+ Z

  12. 8 N0 }4 h! A$ j6 W; Y! R
  13.         } else { // okay, confirmed we're on mainnet5 D/ k9 ~5 C% E! t( p+ e; c: d

  14. % {4 ~& `. u/ o% {
  15.             this.provider.listAccounts().then(function (result) {
    4 ^( D; h1 F: b- D* r
  16.                 console.log(result);0 u& W% E" n! b0 {2 s
  17.                 this.accountAddress = result[0]; // figure out the user's Eth address( l5 _9 B3 H) W6 o6 N. H) h
  18.                 this.provider.getBalance(String(result[0])).then(function (balance) {) l# C( b1 H) l( b; Q* b
  19.                     var myBalance = (balance / ethers.constants.WeiPerEther).toFixed(4);2 }: u# G/ R8 L3 P
  20.                     console.log("Your Balance: " + myBalance);
    6 F7 e4 l3 G' [9 ]" [! A
  21.                 });1 T$ e. C  W9 F: X; H' r' E
  22. 0 M1 V% j. W$ H* l2 Q3 A& g
  23.                 // get a signer object so we can do things that need signing9 j! v% @$ ^: P3 D8 T
  24.                 this.signer = provider.getSigner();
    $ c2 |6 i* n0 C2 q
  25. 7 h9 N* e* y% `% T. E7 F
  26.                 var rightnow = (Date.now()/1000).toFixed(0)
    : u+ N/ R: g9 M/ n% J6 [4 I
  27.         var sortanow = rightnow-(rightnow%600)% ]  B& Y$ o4 R) O+ d5 S6 _) e

  28. * U$ w! w. T% z% C, s  c1 s
  29.         this.signer.signMessage("Signing in to "+document.domain+" at "+sortanow, accountAddress, "test password!")
    # l9 c4 c+ R# T
  30.             .then((signature) => {               that.handleAuth(accountAddress,signature);
    . {  t% t  U- `' i) o
  31.             });1 |2 L; G" T' P9 b' r
  32. 9 E8 _) @( F6 f. X$ A
  33.                 console.log(this.signer);; w+ m, Z/ w% ?& B/ j
  34.             })
    # o  j- o6 H% v0 J/ A; J3 |
  35.         }
    ; E6 o! h( \4 v
  36.     })9 H7 N4 b" ]! c1 m: W$ B4 E9 |7 u
  37. })
    0 _* C. J+ z0 b7 [5 Y; m) d9 y
  38. 4 r1 T; E/ g; Z0 E! X5 _! e
  39.                 },
复制代码
通过使用signMessage方法返回签名,这里加签过程中使用基于时间戳的随机数防止未签名,当前端签名生成好之后,立刻异步请求后台接口:
3 a, J- v+ Z6 B/ e0 Y) D* V7 s/ ?: G7 d3 P( \" q  o
  1. //检查验证3 w- c* V/ X# B
  2.                 handleAuth:function(accountAddress, signature){
    ) N8 j: s' E4 h
  3. ( O, m  k4 ?6 {- x8 v

  4. & K2 T1 M. V/ _! e6 b' X% Y
  5.                     this.myaxios("/checkw3/","post",{"public_address":accountAddress,"signature":signature}).then(data =>{1 \8 q9 N+ q) {5 G1 t$ j: j. a2 a
  6. . w% [( C6 d2 e2 @$ H
  7.                         if(data.errcode==0){
    0 w- L8 q7 d0 f0 v
  8.                             alert("欢迎:"+data.public_address);1 T5 ^) r+ k% ~/ e" u* f$ S9 L1 Y- \
  9.                             localStorage.setItem("token",data.token);
    % Q3 o, U: K# n3 }) ~
  10.                             localStorage.setItem("email",data.public_address);- P, _1 r/ @9 ?$ z* i
  11.                             window.location.href = "/";
    . U- `2 B8 ^3 h0 `" u$ F% t5 T
  12.                         }else{
    7 d. b5 \+ \7 k" {( l: I
  13.                             alert("验证失败");2 F: T. V$ C9 Z# O# Q. w
  14.                         }. k6 V: d' X9 ^: w( L
  15.                  });) ?* D+ I& }# f! n: Q

  16. 2 `( y+ P$ \: K+ X! z- i, u! r5 N
  17.   U  n* b: n3 {4 \) W5 A
  18. 3 E; {7 W9 U/ N- F- _% C+ M' t
  19.                 }
复制代码
这里将当前账户的钱包地址和签名传递给后端,如图所示:
' _: y, b5 A4 P# P' E' j+ I
3 O' @2 @/ u: y9 b* y) B
# a: u  X6 N7 Q. w0 L8 V2 p6 f3 i. u) f& O+ Q" v& q; J

  f8 a) U' Y. c; J; W 随后创建异步视图方法:
8 M4 P% v. Z7 y* j% [3 t
  1. from tornado.web import url
    ! d; H* X# W# z5 R; h, A% g) L
  2. import tornado.web' M* J) t% v7 j( V
  3. from tornado import httpclient. \. z' g$ f, _7 B8 S$ U
  4. from .base import BaseHandler
    % P/ Y, H2 r+ G
  5. from web3.auto import w32 u7 @$ V! R2 Q( M! Q! \
  6. from eth_account.messages import defunct_hash_message
    : }+ K7 Z% }. Q  f  U2 s0 ^
  7. import time
      P+ k* A* s+ @; o; o. c
  8. 5 }# I; o# Q' G9 N
  9. class CheckW3(BaseHandler):
    & K/ ]$ u8 I4 |& [( E5 B, k+ n* @
  10. ; x; q& a5 L6 g7 N* H1 B, n( D' v
  11.     async def post(self):
    6 Y. g  t8 ^2 s

  12. 6 L5 f7 v, t+ h1 Z0 E
  13.         public_address = self.get_argument("public_address"): e. ?/ L, i* W9 j
  14.         signature = self.get_argument("signature")) }9 U: z& K1 p

  15. 4 ]. i9 T5 \: r3 Z
  16.         domain = self.request.host
    ! @/ O5 Z; L8 z* S. ?# V! |
  17.         if ":" in domain:
    : f$ Z$ T* l0 z  `8 }
  18.             domain = domain[0:domain.index(":")]
    3 z8 d6 S' m4 H. X

  19. / ^3 o' Q/ y8 O: R! X3 }" d
  20.         now = int(time.time())
    % z$ x5 B" \! W
  21.         sortanow = now-now%600
    ) T) S- }4 {' k/ D
  22.    
    + t' \. m7 v' i8 @+ E
  23.         original_message = 'Signing in to {} at {}'.format(domain,sortanow)9 p% T' T- X* W* d3 j
  24.         print("[+] checking: "+original_message)- [/ p1 |. z  K: I+ c7 l* ]
  25.         message_hash = defunct_hash_message(text=original_message)# X7 ]# y1 J$ Y4 B9 a! N
  26.         signer = w3.eth.account.recoverHash(message_hash, signature=signature)( B' L9 s0 c8 S! \' }

  27. ! \8 v5 _  C7 s2 Z4 w
  28.         if signer == public_address:
    % W6 S5 m' \1 h% k. v
  29.             try:9 f- x: L9 h6 C; }  c$ W* t! a; ^
  30.                 user = await self.application.objects.get(User,email=public_address)2 B- a: l/ w( w4 a' h
  31.             except Exception as e:
    1 s- a/ `& ^) |2 q* ]7 X/ I9 T# `$ v
  32.                 user = await self.application.objects.create(User,email=public_address,password=create_password("third"),role=1)
    ) k' D) _& ^- L: ~5 c/ l

  33. + _1 n) P* f' v$ f
  34.             myjwt = MyJwt()0 m" o: m0 S9 r* ~7 J7 S
  35.             token = myjwt.encode({"id":user.id})
    ) M7 C9 h! V9 q# Y6 ~
  36.             self.finish({"msg":"ok","errcode":0,"public_address":public_address,"token":token})
    * f, u4 L5 S% H. v
  37.         else:) K6 v1 O. U4 ?( [. }4 f% j( }4 A6 U
  38.             self.finish({"msg":"could not authenticate signature","errcode":1})
复制代码

5 D+ x" Z( N( E* q( y   这里通过recoverHash方法对签名进行反编译操作,如果反编译后的钱包地址和前端传过来的钱包地址吻合,那么说明当前账户的身份验证通过:
! X  `% J" y0 y' N* p& A8 L: L: l( X) q7 T$ n  ]  P+ m1 Z

0 R: g# R0 J0 f) C$ w; F) `$ W: {. H: W* `- N( c
* O. R6 ?6 E3 y: f* X. Y$ Q
当验签通过之后,利用钱包地址在后台创建账号,随后将钱包地址、token等信息返回给前端,前端将其保存在stroage中即可。+ o2 z/ w# B( M4 G/ q

3 Q4 B  Y  H( ?* ?6 m8 i5 \# x/ E    结语, a/ f& J6 b: T4 O% x

4 G% W1 c* l+ r: g2 L8 i    没错,将至已至,未来已来,是时候将Web3.0区块链技术融入产品了,虽然有些固有的思维方式依然在人们的脑海挥之不去,但世界却在时不我待地变化着,正是:青山遮不住,毕竟东流去!项目开源在https://github.com/zcxey2911/Tornado6_Vuejs3_Edu / z7 j/ f4 J* W. b0 A

! ~1 Y8 n7 k0 X0 e; Z0 f3 N4 @. [) N4 S# w; ]( l, G9 r
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

江左没浪 小学生
  • 粉丝

    18

  • 关注

    0

  • 主题

    7