Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
    今天去中心化身份逐渐被广泛采用。用户的部分在线活动在链上是公开的,可通过加密钱包搜索到,用户在链上创造、贡献、赚取和拥有的东西,都反映了他们的喜好,也逐渐积累成该用户的身份和标识。( i5 W4 |0 s/ w7 u. F
  y( o, d" F% P. @
    当我们的用户厌倦了传统的电子邮件/密码注册流程时,他们会选择Google、GitHub等社交登录方式,这种方式虽然节约了用户的时间,但登录信息也会被第三方平台记录,也就是说我们用平台账号做了什么,平台都会一目了然,甚至还会对我们的行为进行分析、画像。那么有没有一种登录方式,它的所有信息都只保存在客户端和后端,并不牵扯三方平台授权,最大化的保证用户隐私呢?Web3.0给我们提供了一种选择:MetaMask。
( w1 \$ r7 X) T! h/ ?. Z& O
5 z2 [3 V7 L0 A( ~& f0 ~& C    MetaMask
3 e+ h: H6 U9 p5 _9 u    MetaMask是用于与以太坊区块链进行交互的软件加密货币钱包。MetaMask允许用户通过浏览器插件或移动应用程序访问其以太坊钱包,然后可以使用这些扩展程序与去中心化应用程序进行交互。当然了,首先需要拥有一个MetaMask钱包,进入https://chrome.google.com/websto ... oehlefnkodbefgpgknn
# C" `  N1 G$ ]7 w; Q$ i. D
; D- c% ]' z3 v$ a: p    安装metamask浏览器插件:
0 I3 c' H  d& g
/ [" s1 |. c7 c# z' P( w. n3 p: [% X" X7 m* X) E
  随后点开插件,创建账号,记录密码、钱包地址、以及助记词等信息。) j4 Z2 l( O8 B- g: a: B9 `. g

0 D) G/ g( P: o( l7 _* P    安装好插件之后,我们就可以利用这个插件和网站应用做交互了。$ ?; u7 H* l7 g2 |. @' r
. k5 ]' U2 `: p, a+ i
    钱包登录流程
, G( v: r8 C- g( {$ U3 @* `    登录逻辑和传统的三方登录还是有差异的,传统三方登录一般是首先跳转三方平台进行授权操作,随后三方平台将code验证码返回给登录平台,登录平台再使用code请求三方平台换取token,再通过token请求用户账号信息,而钱包登录则是先在前端通过Web3.js浏览器插件中保存的私钥对钱包地址进行签名操作,随后将签名和钱包地址发送到后端,后端利用Web3的库用同样的算法进行验签操作,如果验签通过,则将钱包信息存入token,并且返回给前端。7 Y# [7 Q4 C% ^. \0 B

( n* w# g- L( p- f0 H8 v3 H# {( S: u5 \7 n0 S0 u! ]
3 b1 f, @! n. l. s$ o
前端签名操作: h* t- \. }5 I
    首先需要下载前端的Web3.0操作库,https://docs.ethers.io/v4/,随后集成到登录页面中:
  a9 ?, z' w% G1 e0 k
; m* f' F" K7 `& Z% q( z7 W
1 j4 \" R$ [+ S# Z6 P
  1. <script src="{{ static_url("js/ethers-v4.min.js") }}"></script>1 b4 ]* R0 ^9 \' C  x6 G' Y. K; a9 k
  2. <script src="{{ static_url("js/axios.js") }}"></script>7 ]" D! L0 g" q, y% g( ?
  3. <script src="{{ static_url("js/vue.js") }}"></script>
复制代码
# h) @3 m, B0 @7 P6 e/ z

: r. w  s/ ]- r( F' O3 X- _: }, l- U0 V- {* Y
这里我们基于Vue.js配合Axios使用。9 q: |2 i( f- n! a: }
& W9 `* ?8 n  }. A: i3 z/ f5 O
    接着声明登录激活方法:
2 D, |( Y/ C! \4 `$ M9 f6 w' }* B8 r0 x& p5 {, N! \" e
  1. sign_w3:function(){. w: t5 i8 V( ?! Z8 J2 C8 M, W: |

  2. : }  Y7 y8 n* z0 P. j
  3.                     that = this;  u* q4 q- }! t4 X
  4.                     ethereum.enable().then(function () {/ ]6 R8 p% G+ P' ]% e6 e

  5. ; v- A7 l% ^% p" N! `
  6.     this.provider = new ethers.providers.Web3Provider(web3.currentProvider);6 e5 }- ?* Y6 F  ?4 s7 E

  7. # e9 O6 y% B1 T  o7 r4 _& e+ S
  8.     this.provider.getNetwork().then(function (result) {! G4 m7 A) @- g- [
  9.         if (result['chainId'] != 1) {  e7 k; L0 |5 u- ^6 C0 S

  10. 3 I+ D# \* |1 q/ N( M. `
  11.             console.log("Switch to Mainnet!")$ v5 G8 I6 Z8 r9 V# T8 w' P: y

  12. 5 F: Q7 V" `0 {% c! J- K
  13.         } else { // okay, confirmed we're on mainnet8 q: q+ ]) ~+ ~, H7 N

  14. : F# D6 S* i1 X# S: x
  15.             this.provider.listAccounts().then(function (result) {. _1 u7 b, d3 M3 L) Z
  16.                 console.log(result);6 U% K! e5 A. a5 M4 M! S% O
  17.                 this.accountAddress = result[0]; // figure out the user's Eth address
    2 U) s0 ]' m  l5 T  x7 B* M
  18.                 this.provider.getBalance(String(result[0])).then(function (balance) {
    8 U( F% }% ^5 p3 f! T( V
  19.                     var myBalance = (balance / ethers.constants.WeiPerEther).toFixed(4);3 H; k( K6 O, q
  20.                     console.log("Your Balance: " + myBalance);/ s: d. b. S$ b* e$ W
  21.                 });9 t- C; K; v' M6 `$ z( m" a3 o

  22. ( [0 M, T! R) @2 j$ i
  23.                 // get a signer object so we can do things that need signing
    + v! p: S: A( W; v  ?  x
  24.                 this.signer = provider.getSigner();
    , B; q: L: A) s! S
  25. & ^& s. E" g; t: g* f2 U) W8 S
  26.                 var rightnow = (Date.now()/1000).toFixed(0)
    $ m% d$ `/ z5 V6 @  |7 _1 b
  27.         var sortanow = rightnow-(rightnow%600)7 \( R; ?$ v1 Q! l+ C
  28. 0 }4 z% ~& C! @' `" c9 W, l+ E! @1 @2 ^
  29.         this.signer.signMessage("Signing in to "+document.domain+" at "+sortanow, accountAddress, "test password!")/ L& b# s3 f1 F: w: t& M
  30.             .then((signature) => {               that.handleAuth(accountAddress,signature);
    ( N4 S, k& h: N6 ?# m- m. l
  31.             });
    + o* a% t7 l- w7 J
  32. 3 x: P* {2 t7 j) W
  33.                 console.log(this.signer);
    3 m9 }: g" c& H0 h8 O/ l6 A! y
  34.             })
    7 s/ ?/ P: D( ^3 v# W( f
  35.         }
    ) \" G1 Q( g. r9 n" A$ s8 @" H
  36.     })
    , W, y3 o# d2 q: N
  37. })! Q* D4 W6 X6 Q7 j+ A$ ]
  38. . A1 _( u; e! j( T! L/ `$ z
  39.                 },
复制代码
通过使用signMessage方法返回签名,这里加签过程中使用基于时间戳的随机数防止未签名,当前端签名生成好之后,立刻异步请求后台接口:
: c" I3 ]3 f. S. |
/ N- r2 W* ~% s9 Q$ m
  1. //检查验证
    - H' R( p3 J5 y) A) i& }- v" b+ z
  2.                 handleAuth:function(accountAddress, signature){4 |3 Q% j7 Y0 \# c

  3. , `2 r" A6 q* J8 |
  4. " t- b% W( K/ D
  5.                     this.myaxios("/checkw3/","post",{"public_address":accountAddress,"signature":signature}).then(data =>{
    3 Z" v: L# t" i; S
  6. " D. _, b" t. G5 i
  7.                         if(data.errcode==0){
    2 }0 y6 {2 ?) f3 b* Y# a6 Z# w
  8.                             alert("欢迎:"+data.public_address);7 u. k& W; ~, v8 |# e
  9.                             localStorage.setItem("token",data.token);* l( s, V& R7 Q/ ?
  10.                             localStorage.setItem("email",data.public_address);
    * Y0 @# I" R9 `6 e7 R
  11.                             window.location.href = "/";
    / _. |2 G' u) H
  12.                         }else{
    $ H0 \& z8 Y! J& X% v
  13.                             alert("验证失败");
    " d! E9 _4 W; N4 d
  14.                         }5 c% z  Z3 q  w
  15.                  });
    $ Z0 o9 U. j* d- [( v; c! i( }9 W6 Q

  16. ' q3 ~- h0 L8 g$ ], I* _' E

  17. ! h) L( D/ h3 H  K3 Y- O
  18. 2 O8 ~9 f: K) I! F; j% ^" _
  19.                 }
复制代码
这里将当前账户的钱包地址和签名传递给后端,如图所示:
$ V+ B7 O- v( {
. P1 o1 I5 @6 i6 _# c: e, h+ l$ p1 o

5 m: \, P2 b$ Q) G4 d. D' J7 h& F- Z
随后创建异步视图方法:
! e# d( S7 c: ?5 d0 Z; A. N
  1. from tornado.web import url( i, \" k& _* V( O/ R3 a/ q
  2. import tornado.web
    4 b* d3 S7 R: J
  3. from tornado import httpclient
    $ F. ~, G% V7 p( }0 l: {
  4. from .base import BaseHandler( X4 `. {6 w9 k* ^2 z
  5. from web3.auto import w30 s! q+ L$ ~/ R, L" K* l0 `
  6. from eth_account.messages import defunct_hash_message
    8 |- g9 R; O- f5 e' a9 ]5 v8 z
  7. import time" k# k6 Z2 h/ @# H4 x6 ^- k4 \9 [
  8. $ ]+ m, g! _5 O9 T1 ]! P
  9. class CheckW3(BaseHandler):
    " F7 v/ p$ T) F/ M! N

  10. * B; c) }% N; e* o
  11.     async def post(self):" ^4 S* Y1 t* a8 x0 h9 R
  12. 1 b7 ?# C. _5 F  u. K
  13.         public_address = self.get_argument("public_address")
    . P5 G% a* E* g% `
  14.         signature = self.get_argument("signature"); m" d+ N0 \0 ?/ r7 I

  15. : m# V# q" m: [6 }
  16.         domain = self.request.host7 Y0 ?6 G& z! y* {
  17.         if ":" in domain:
    ( k- p# F! x  L$ L! h
  18.             domain = domain[0:domain.index(":")]4 d8 r  ^# V; |* R' z

  19. 8 U$ I1 \4 T  e, ]
  20.         now = int(time.time())
    2 `1 V# c# v: A; O; B
  21.         sortanow = now-now%600$ I& T) ^8 e/ |
  22.    9 r' j" w' R3 w& ^
  23.         original_message = 'Signing in to {} at {}'.format(domain,sortanow)
    . W. U( i) P& e9 r% f$ ]
  24.         print("[+] checking: "+original_message)
    ! q4 a! n% f6 z" p; y$ {
  25.         message_hash = defunct_hash_message(text=original_message)" U) `# T: {9 S2 p- ?4 [4 Q
  26.         signer = w3.eth.account.recoverHash(message_hash, signature=signature)0 P( M. a2 T) g; N* Q2 Y
  27. ' s& x; ?% S! P4 N, c
  28.         if signer == public_address:
    4 N; a: f, v2 w
  29.             try:9 ]: f5 O) ]$ E0 u5 {, D* E# q
  30.                 user = await self.application.objects.get(User,email=public_address)
    2 [: c& C* C/ j6 h$ }
  31.             except Exception as e:
    : }' @" q* D) h8 U) e
  32.                 user = await self.application.objects.create(User,email=public_address,password=create_password("third"),role=1)
    ! x; Z; y9 F. k/ H
  33. , o7 g& ~- z  g$ j
  34.             myjwt = MyJwt()
    6 R3 |. S0 i" N- k' B4 n9 M' _
  35.             token = myjwt.encode({"id":user.id})
    & i& q" q$ Z) H
  36.             self.finish({"msg":"ok","errcode":0,"public_address":public_address,"token":token})
    - A+ f6 w, m- J
  37.         else:9 X, n# Z- T( t9 w4 T3 `
  38.             self.finish({"msg":"could not authenticate signature","errcode":1})
复制代码

- R: j: p0 Z! O" L- M   这里通过recoverHash方法对签名进行反编译操作,如果反编译后的钱包地址和前端传过来的钱包地址吻合,那么说明当前账户的身份验证通过:4 H& h, {& r3 O5 O. X" u
% G5 F0 d* G/ ^. R. ~' d+ j6 ~' E
7 A& x3 Z  t% {5 j4 w! ~2 o

9 h2 A' A5 d2 u- d' l
2 }7 q9 Q8 c3 S9 F$ B 当验签通过之后,利用钱包地址在后台创建账号,随后将钱包地址、token等信息返回给前端,前端将其保存在stroage中即可。( [/ z- s: m6 P
( T2 `  ^! r5 U
    结语" W& p3 n; T3 U4 Z0 z9 A* ]
. B; Q' K2 b  E6 p" J
    没错,将至已至,未来已来,是时候将Web3.0区块链技术融入产品了,虽然有些固有的思维方式依然在人们的脑海挥之不去,但世界却在时不我待地变化着,正是:青山遮不住,毕竟东流去!项目开源在https://github.com/zcxey2911/Tornado6_Vuejs3_Edu
0 e$ Q9 R8 \8 D5 W1 d8 Q9 z ! @6 }4 }! J( w
2 e9 v! O# O" j% ~# R7 D  K
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

江左没浪 小学生
  • 粉丝

    18

  • 关注

    0

  • 主题

    7