Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
    今天去中心化身份逐渐被广泛采用。用户的部分在线活动在链上是公开的,可通过加密钱包搜索到,用户在链上创造、贡献、赚取和拥有的东西,都反映了他们的喜好,也逐渐积累成该用户的身份和标识。$ |0 f& y# j8 f! j
$ l, b7 M7 y! Z- C  @
    当我们的用户厌倦了传统的电子邮件/密码注册流程时,他们会选择Google、GitHub等社交登录方式,这种方式虽然节约了用户的时间,但登录信息也会被第三方平台记录,也就是说我们用平台账号做了什么,平台都会一目了然,甚至还会对我们的行为进行分析、画像。那么有没有一种登录方式,它的所有信息都只保存在客户端和后端,并不牵扯三方平台授权,最大化的保证用户隐私呢?Web3.0给我们提供了一种选择:MetaMask。/ F6 p) |! c; e! y3 I
/ f7 m6 K& z6 S% \2 y% Q; _
    MetaMask
! y/ E# o/ q; R5 v$ G    MetaMask是用于与以太坊区块链进行交互的软件加密货币钱包。MetaMask允许用户通过浏览器插件或移动应用程序访问其以太坊钱包,然后可以使用这些扩展程序与去中心化应用程序进行交互。当然了,首先需要拥有一个MetaMask钱包,进入https://chrome.google.com/websto ... oehlefnkodbefgpgknn 3 _5 t4 R# q' w8 I+ |5 Q
: h$ A/ }# z# [
    安装metamask浏览器插件:: H( e5 `  b" ~$ m# I

1 z7 u) {" ~1 @7 o+ s; n. a
( J$ W# I7 `! H3 _% M& K' y9 R  随后点开插件,创建账号,记录密码、钱包地址、以及助记词等信息。7 T% @- M+ S9 N

  }9 Y* N. {! D' D% u    安装好插件之后,我们就可以利用这个插件和网站应用做交互了。, z# \' D( H# K1 k- m

6 ^+ G8 Q5 e2 y+ y$ W/ C8 P- n7 K) C    钱包登录流程) c8 p/ G  j2 x9 i
    登录逻辑和传统的三方登录还是有差异的,传统三方登录一般是首先跳转三方平台进行授权操作,随后三方平台将code验证码返回给登录平台,登录平台再使用code请求三方平台换取token,再通过token请求用户账号信息,而钱包登录则是先在前端通过Web3.js浏览器插件中保存的私钥对钱包地址进行签名操作,随后将签名和钱包地址发送到后端,后端利用Web3的库用同样的算法进行验签操作,如果验签通过,则将钱包信息存入token,并且返回给前端。7 c3 g6 x9 ~+ i

$ t$ q! n: D2 I% M1 T/ t" C) K

0 J* R: g: ^8 f! }+ {前端签名操作" `+ m3 _0 a. Q! X  A
    首先需要下载前端的Web3.0操作库,https://docs.ethers.io/v4/,随后集成到登录页面中:
# ^" B4 y- h7 g8 G7 e0 }- g7 p- L; Z* `
) `. O) E2 o: f! p( o' q1 ?
  1. <script src="{{ static_url("js/ethers-v4.min.js") }}"></script>6 F; N! i' z; f3 Z7 U  s
  2. <script src="{{ static_url("js/axios.js") }}"></script>9 O+ p$ Q' g- A( P3 _% ?
  3. <script src="{{ static_url("js/vue.js") }}"></script>
复制代码

* L2 X7 U, ]. M9 Z- V0 v+ l2 F: o9 J, W' t0 v# t7 C; z+ O3 S
& f3 |3 ^/ l- a  h# D
这里我们基于Vue.js配合Axios使用。. |, U1 Y& Z- _) M, B) p

: ]" F+ |, V- H- K4 u- p    接着声明登录激活方法:0 F* D1 d2 u& ~$ v0 `1 ~; r! |
( |3 W( }% W! @1 E7 o
  1. sign_w3:function(){; J/ M" f0 U  p* w1 x% j+ U) G: |& k5 r

  2. # q3 G. G: r( X
  3.                     that = this;
    - f$ a  H9 S- S9 x/ `, B
  4.                     ethereum.enable().then(function () {
    * k" C7 y( y+ m2 @4 t

  5. 3 u& H# \7 Z" U- i5 Z* K
  6.     this.provider = new ethers.providers.Web3Provider(web3.currentProvider);
    9 B, n6 C  _$ r2 V
  7. 5 D$ F8 C! T( w4 b2 J
  8.     this.provider.getNetwork().then(function (result) {! o6 x5 R% z% R" a  o, _( @
  9.         if (result['chainId'] != 1) {
    , t- t  J' E- x" j) k, {$ V
  10. " e, C5 t/ O- O* F4 b
  11.             console.log("Switch to Mainnet!")2 L$ Q: |. p: A( H) L9 j

  12. # j8 l/ s& T- K; U
  13.         } else { // okay, confirmed we're on mainnet
    ! m' I4 h. [" I7 E0 l7 e" U5 G

  14. & s& I) A# K& f% t- F& @5 W
  15.             this.provider.listAccounts().then(function (result) {
      F! M$ p, |4 ]
  16.                 console.log(result);" A) C- S7 T" W* N: {; N
  17.                 this.accountAddress = result[0]; // figure out the user's Eth address
    % h1 n  ~# s% {$ K/ C2 v
  18.                 this.provider.getBalance(String(result[0])).then(function (balance) {5 r' F! n$ ^; U8 z- B2 W- B
  19.                     var myBalance = (balance / ethers.constants.WeiPerEther).toFixed(4);3 I4 L& E! y& Z$ F2 z
  20.                     console.log("Your Balance: " + myBalance);
    4 [' L7 [. s( i+ z9 t& h0 K
  21.                 });
    . r  h0 |+ a) s" C) {! r

  22. # |% K( u0 q# ?% P% C& s
  23.                 // get a signer object so we can do things that need signing
    6 o3 r0 H, o- _
  24.                 this.signer = provider.getSigner();1 Q' q4 n' n/ ?9 W5 Z

  25. 3 H) b0 |/ M4 G4 j/ M
  26.                 var rightnow = (Date.now()/1000).toFixed(0)6 z* j$ p2 ]: y2 N
  27.         var sortanow = rightnow-(rightnow%600)
    2 b: E# ]8 X0 o' ?

  28. - U' o; i+ A) I  }; \. E1 i: r
  29.         this.signer.signMessage("Signing in to "+document.domain+" at "+sortanow, accountAddress, "test password!")4 f$ `. ?( s* ]9 ]* X
  30.             .then((signature) => {               that.handleAuth(accountAddress,signature);
    7 A; u+ j! ?" n- G( @- u
  31.             });
    ) \" o( E. V0 u, v  S4 |
  32. 4 c, J6 \% z$ J
  33.                 console.log(this.signer);* r# B5 s$ g' M! ]% M% ?5 {3 q
  34.             })
    - M! U2 w" S7 T# X0 i
  35.         }
    0 F" Y" l" V/ |0 v3 l
  36.     })4 `( C/ ^- J3 h* P; h
  37. }), R7 B2 y7 ]6 l, l' h2 {5 J7 P7 w

  38. % r6 m, C' c2 I! N
  39.                 },
复制代码
通过使用signMessage方法返回签名,这里加签过程中使用基于时间戳的随机数防止未签名,当前端签名生成好之后,立刻异步请求后台接口:
; {4 \; z1 m1 c0 l7 G
5 |/ ]$ f/ I# N- K$ a" S& _
  1. //检查验证* G0 s! r4 ^% Z# N
  2.                 handleAuth:function(accountAddress, signature){  L$ ?5 m0 O" b1 U
  3. " l) H* S* h: b" A1 I. V
  4. 5 o2 C/ q1 ]/ w- e
  5.                     this.myaxios("/checkw3/","post",{"public_address":accountAddress,"signature":signature}).then(data =>{/ `) t3 M, h: Z$ o7 V
  6. 3 m4 C, ^1 R5 m/ j0 w/ O: m
  7.                         if(data.errcode==0){" G: }7 A8 w1 t" e" x: n
  8.                             alert("欢迎:"+data.public_address);# h9 U& q& L! }. Z$ c$ ^! i7 N; T
  9.                             localStorage.setItem("token",data.token);8 d1 Q" ^+ ^$ X6 r9 l0 \# a8 ^( H( a
  10.                             localStorage.setItem("email",data.public_address);3 i, J- R( G, \& o" M8 D& S) d
  11.                             window.location.href = "/";
    " F" ]( i3 c: s: A8 ^# _& M) m2 `$ v
  12.                         }else{
    6 u4 t, r" ]& k# l% c7 o& {
  13.                             alert("验证失败");
    2 J8 t# H8 H- E, M
  14.                         }
    / E/ `; K  }. W- N3 @2 H! p
  15.                  });
    / G( I: E! \' u  t
  16. + r  W8 q* T. w5 q9 t+ Z
  17. % ^7 p; o5 c$ ~" ^" e

  18. 5 r  E; n6 k/ P
  19.                 }
复制代码
这里将当前账户的钱包地址和签名传递给后端,如图所示:0 G) x2 [# d% M

1 s; \5 j. C0 p) t! z  l: f% R: a$ T6 ]9 c  r2 ]% b

* l6 O5 y0 C6 R- H/ R: t3 U& b/ K" \" D7 B; H4 p; ?
随后创建异步视图方法:
0 H# {+ A9 @) q/ p+ @
  1. from tornado.web import url2 O3 [8 ]& \3 H: [0 L
  2. import tornado.web
    4 h$ x2 T3 m& c( g5 X
  3. from tornado import httpclient/ ~/ D% b# {4 L$ R$ w1 z  f
  4. from .base import BaseHandler
    , L( q5 A, V3 T7 d
  5. from web3.auto import w3
      S$ H/ U- S4 l5 G% R( h3 d! X
  6. from eth_account.messages import defunct_hash_message- q" \% C8 n# Z6 b( L
  7. import time! q* n0 `4 T8 r0 d' o; W5 `+ a
  8. 9 k1 U7 J" w( @- C/ Q3 u
  9. class CheckW3(BaseHandler):
    9 |/ j2 Z3 |4 Z6 Z7 p4 g

  10. * ^6 j" t- f3 |) ?
  11.     async def post(self):5 w1 X2 `5 I  y. [! _
  12. 9 d3 v2 M! J( h  u
  13.         public_address = self.get_argument("public_address")" R" l5 s2 D2 }! N# j
  14.         signature = self.get_argument("signature")
      s9 F7 @' b2 x0 a3 f
  15. 8 x& W8 m0 c- c% [' G
  16.         domain = self.request.host9 x, U' m( Z8 k$ _  o0 w. D% \
  17.         if ":" in domain:1 Z8 |, q9 T6 R: V
  18.             domain = domain[0:domain.index(":")]$ h  B$ q2 J+ O$ @

  19. # g7 B% i) y& K6 R
  20.         now = int(time.time())
    : {; C4 n: Q# O( N' R1 y
  21.         sortanow = now-now%600
    9 y1 J3 h5 q! h# i
  22.    9 E$ ]# R( s0 w
  23.         original_message = 'Signing in to {} at {}'.format(domain,sortanow), f5 ]& ?9 Y- Q
  24.         print("[+] checking: "+original_message)
    ; q$ P; ]: {5 f9 s( j5 J
  25.         message_hash = defunct_hash_message(text=original_message)
    - c, @3 O* O$ K9 n- u
  26.         signer = w3.eth.account.recoverHash(message_hash, signature=signature)0 U0 b7 W( e; J0 ^+ Z1 C1 @; H4 P7 o

  27. 5 y% j& \" H3 ~6 L7 w
  28.         if signer == public_address:
    / J/ I" V9 U+ f' s# ]
  29.             try:
    7 i$ L- k3 t% k) X: H! T- s5 ]  ^
  30.                 user = await self.application.objects.get(User,email=public_address)
    3 X/ j, h6 W1 n# C
  31.             except Exception as e:: s$ l/ N! Y; z
  32.                 user = await self.application.objects.create(User,email=public_address,password=create_password("third"),role=1)4 G$ e# I- ~& p% }8 x

  33. 8 s! H! [6 o8 B" s$ c9 U6 x( I7 @
  34.             myjwt = MyJwt()
    * O& f' N0 w+ T. G  N6 a
  35.             token = myjwt.encode({"id":user.id})0 U; i, P; n8 A8 G# m7 J
  36.             self.finish({"msg":"ok","errcode":0,"public_address":public_address,"token":token})8 p2 R7 B' z! K  b
  37.         else:
    ! Q9 |! k# i% {# W. J- H
  38.             self.finish({"msg":"could not authenticate signature","errcode":1})
复制代码
7 _/ K. V) g1 m1 B
   这里通过recoverHash方法对签名进行反编译操作,如果反编译后的钱包地址和前端传过来的钱包地址吻合,那么说明当前账户的身份验证通过:
5 u) d  [4 S3 U2 o9 E; J9 T% ]6 a
* v% o) O- ~% Z2 J" I' p  v. y
9 R$ X6 {, c- k8 |0 P4 _  U( d# w& [' c# Z$ u2 |7 O
! N1 X1 B& u, e
当验签通过之后,利用钱包地址在后台创建账号,随后将钱包地址、token等信息返回给前端,前端将其保存在stroage中即可。
. W. s5 W  }1 q* W% r* m/ ^$ ~2 o8 w3 d9 j7 |" |
    结语! C; {! s( f) R! H0 n! R4 i

9 R9 t% x% ^, J    没错,将至已至,未来已来,是时候将Web3.0区块链技术融入产品了,虽然有些固有的思维方式依然在人们的脑海挥之不去,但世界却在时不我待地变化着,正是:青山遮不住,毕竟东流去!项目开源在https://github.com/zcxey2911/Tornado6_Vuejs3_Edu
) x6 }& w7 f  r- J/ E/ d! N : i& N9 ]) W3 k& k! Z, I$ U

  ]2 W2 f; _3 {! s& [2 I  W( ^
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

江左没浪 小学生
  • 粉丝

    18

  • 关注

    0

  • 主题

    7