Hi 游客

更多精彩,请登录!

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

' L! X5 K( a$ n, p3 R7 U    安装metamask浏览器插件:
2 i/ k1 a% d5 O( E& _2 S
* k3 B/ t) v2 x& ]4 i( |; y1 [, G. p- U% g
  随后点开插件,创建账号,记录密码、钱包地址、以及助记词等信息。
) W& W( n' A- I2 ]$ R) ?! H, ?9 P+ E& m; d6 D' L
    安装好插件之后,我们就可以利用这个插件和网站应用做交互了。
5 }. N% ^7 a! N1 P4 {
5 I* K. p$ S; S/ G1 Q' p% K. B    钱包登录流程
7 {" S; J, @8 `& z5 u7 u    登录逻辑和传统的三方登录还是有差异的,传统三方登录一般是首先跳转三方平台进行授权操作,随后三方平台将code验证码返回给登录平台,登录平台再使用code请求三方平台换取token,再通过token请求用户账号信息,而钱包登录则是先在前端通过Web3.js浏览器插件中保存的私钥对钱包地址进行签名操作,随后将签名和钱包地址发送到后端,后端利用Web3的库用同样的算法进行验签操作,如果验签通过,则将钱包信息存入token,并且返回给前端。
, S6 J9 l& y2 _7 ?! @# _0 \7 r; m

5 M* z# G( b- y. G# Y# j8 m: t& A
前端签名操作
4 @7 |: J/ P/ \: g3 }0 E    首先需要下载前端的Web3.0操作库,https://docs.ethers.io/v4/,随后集成到登录页面中:0 \& a9 m9 N+ ?; T8 I# }
8 M3 @% l  a9 [

  a" j( i2 \) h$ c# z
  1. <script src="{{ static_url("js/ethers-v4.min.js") }}"></script>! J5 r/ ^  m, ?  i7 B' ]
  2. <script src="{{ static_url("js/axios.js") }}"></script>
    ) b1 `& ?8 z4 w  a
  3. <script src="{{ static_url("js/vue.js") }}"></script>
复制代码
3 y/ R! r2 O* e4 y) E

7 i1 C6 N* U: W" L" Y3 C) Z4 X1 ?/ C& ^7 c
这里我们基于Vue.js配合Axios使用。8 F' b: m9 T* o0 R! y+ [4 f

: P2 q! C% G! @; D7 i, }1 O: |8 |. v, z    接着声明登录激活方法:& y2 d7 g/ W+ w/ P

  R; ?9 o' ]3 u0 k+ |
  1. sign_w3:function(){: P, g" ?, {3 V- q2 H( _
  2. 6 F# l$ e/ ]6 f: T, r, z1 v
  3.                     that = this;2 }9 g/ A1 g) y
  4.                     ethereum.enable().then(function () {" v6 h( R. G5 `/ \. M% m# |5 J$ G
  5. ; o# `& i9 _3 e: K. I- }( `: w! V1 }
  6.     this.provider = new ethers.providers.Web3Provider(web3.currentProvider);9 {$ P4 O+ q9 [' D. z0 l
  7. 3 l* K7 Q0 ^2 A; i8 d$ ~
  8.     this.provider.getNetwork().then(function (result) {
    0 X9 I$ {/ a% y6 u! d  i
  9.         if (result['chainId'] != 1) {
    7 i1 c0 p0 q2 R) r

  10. ; T9 W9 M1 Y: _& x
  11.             console.log("Switch to Mainnet!")2 r0 }- Y4 f4 G1 M6 C! `7 A5 X

  12. ( w; `; \9 P3 G; q7 Z, u$ X
  13.         } else { // okay, confirmed we're on mainnet
    & @/ i5 @+ Y0 Z- p* u/ n9 `
  14. 4 w% q/ b5 O4 _' _
  15.             this.provider.listAccounts().then(function (result) {! ~4 ?+ K0 V" ^9 u
  16.                 console.log(result);
      S3 C( W$ b& |1 k7 y
  17.                 this.accountAddress = result[0]; // figure out the user's Eth address
    6 w/ @0 C6 p; W' P# }
  18.                 this.provider.getBalance(String(result[0])).then(function (balance) {! T# Y7 Y$ Q" X. J6 r! B
  19.                     var myBalance = (balance / ethers.constants.WeiPerEther).toFixed(4);' j* k1 J" ]$ T  H& W
  20.                     console.log("Your Balance: " + myBalance);
    0 U3 u1 h5 G3 N5 i
  21.                 });
    # E: y/ a# T# J; g
  22. # ~' S# D) B# |% K# t) M
  23.                 // get a signer object so we can do things that need signing+ B% c6 ~3 H' F* w8 ~6 t
  24.                 this.signer = provider.getSigner();! q' X( m; x$ J& h9 y5 u

  25.   d+ ^3 y3 j' l8 I* Z. {
  26.                 var rightnow = (Date.now()/1000).toFixed(0)
    * Z  m* J, F! ?$ D# M! H* Q" ?
  27.         var sortanow = rightnow-(rightnow%600)
    # Z3 M1 z9 [3 g
  28. / e' U' y; d( r- u! h" O+ G
  29.         this.signer.signMessage("Signing in to "+document.domain+" at "+sortanow, accountAddress, "test password!")" ^5 P2 H( G, e  P& b- [* o$ N& E
  30.             .then((signature) => {               that.handleAuth(accountAddress,signature);
    6 d7 {+ \1 r+ E' I/ p1 g
  31.             });
    . w. ]' k! C& U2 }6 _) |6 X. A
  32. 2 G% K& h8 _' l$ k- O: ]; W
  33.                 console.log(this.signer);9 g. {& h7 r9 K! p/ `) b9 L' L# E5 h
  34.             })' {( I' S% @5 f' r; k4 P9 D
  35.         }
    . B. k4 Y4 G* U! s$ m2 p
  36.     })
    , Q: C9 f, d% e/ Y1 m( o
  37. })6 D) X8 A1 H$ ?; j. N
  38. - Z# @4 Z+ R5 Z5 U; S2 B
  39.                 },
复制代码
通过使用signMessage方法返回签名,这里加签过程中使用基于时间戳的随机数防止未签名,当前端签名生成好之后,立刻异步请求后台接口:
# U% q, f# j( c4 m1 r  J6 Q0 I) U/ s. P! L% g
  1. //检查验证; f. u$ f/ W0 O
  2.                 handleAuth:function(accountAddress, signature){
    . l+ ^: }6 [/ F! t
  3. & ~; S. [! r: |; p) p- i  _/ ?2 J
  4. ' d) v: g! }  t9 R; Q
  5.                     this.myaxios("/checkw3/","post",{"public_address":accountAddress,"signature":signature}).then(data =>{
    , _7 e7 W' L" M- o" [

  6. 3 n2 r  {. I2 Y; o% n7 u
  7.                         if(data.errcode==0){. O, S6 p, n+ a7 |1 W4 t  q
  8.                             alert("欢迎:"+data.public_address);, w2 S/ g# D) V3 l
  9.                             localStorage.setItem("token",data.token);/ P8 r5 U+ O0 C- E
  10.                             localStorage.setItem("email",data.public_address);8 X8 ^4 u8 c6 T, N" f( |
  11.                             window.location.href = "/";
    + h# V( R7 `5 ?  q
  12.                         }else{; b0 b& \) M: @0 [0 m
  13.                             alert("验证失败");% o. V% t; w  x- o8 j
  14.                         }' c" Q1 I0 b1 l1 {, t( Y
  15.                  });# v: `0 g! D& ?1 |/ s  q
  16. " O; d% d% ?- q' l, f: O& J( n

  17. $ A( }  r  \, n0 t7 n" k

  18. + E) L$ ]) m0 @  I$ s  b% m
  19.                 }
复制代码
这里将当前账户的钱包地址和签名传递给后端,如图所示:' y5 y$ \6 I. D  \0 T8 B
3 F: U; J6 Q1 o3 ^& T4 w9 q
8 S! M3 A" T' v
9 a* q9 H4 _; E2 Z- H, M

$ _. U& n) s( ?  a2 l 随后创建异步视图方法:
# |! |! h; f, H: L* J. x. c
  1. from tornado.web import url
    & }1 F  B: M' o8 S/ Z# `
  2. import tornado.web
    % o9 v) c( |- R2 \" i
  3. from tornado import httpclient- X( y) R' U- m
  4. from .base import BaseHandler: R- }. T9 e2 P: K/ t" R- @7 u& U
  5. from web3.auto import w3+ F" o, @8 {" X
  6. from eth_account.messages import defunct_hash_message6 V' Z, R% B; ~
  7. import time
    ) d9 A+ R( o2 J0 M3 F' m
  8. # V' W% W) P1 f
  9. class CheckW3(BaseHandler):
    ' |1 l0 z& ~) r1 B9 f: \

  10. 3 ?7 k3 H* V6 H
  11.     async def post(self):
    & V- i2 z( h0 J) c5 a% q! t4 B
  12. ! j  `( o* A% t
  13.         public_address = self.get_argument("public_address"), R. Z* b' A; d6 w, l
  14.         signature = self.get_argument("signature"); K2 c1 h- ^& \* H9 c+ N. ]

  15. # g8 U" Z% |0 h+ e! ^. u- V
  16.         domain = self.request.host+ \% F0 |1 A4 {; _
  17.         if ":" in domain:8 o( L3 d0 p' Z
  18.             domain = domain[0:domain.index(":")]$ f, I8 z8 ]0 f
  19. 6 Y6 [; U2 D7 O* V2 s
  20.         now = int(time.time())8 K1 M* u8 r- a) C8 N" ^
  21.         sortanow = now-now%600
    $ D. q- I  L' l+ H9 O' T
  22.    7 s) k4 o; W5 \& k5 i" \' G" S
  23.         original_message = 'Signing in to {} at {}'.format(domain,sortanow)2 _3 m. d* _2 Q6 I9 p
  24.         print("[+] checking: "+original_message), i( H& X/ S) i: e; u: \/ r
  25.         message_hash = defunct_hash_message(text=original_message); v- p  m9 o( l  D$ D% [# r% I
  26.         signer = w3.eth.account.recoverHash(message_hash, signature=signature)
    ' z/ z) n  }) o; S4 b
  27. 9 \, A9 G+ M6 x4 [& ^9 k( K. A1 o
  28.         if signer == public_address:3 n+ u* G# V  @5 O' j
  29.             try:
    . U/ o; i  J' s/ e4 G0 d
  30.                 user = await self.application.objects.get(User,email=public_address)
    - h8 }, a( j$ C: i4 M. ?/ a
  31.             except Exception as e:
    ' s: A3 V, K6 C5 e5 o& H0 X
  32.                 user = await self.application.objects.create(User,email=public_address,password=create_password("third"),role=1)6 ]- F0 N$ Q* y

  33. 6 H# @# n( ^# N# l3 d$ U5 Z5 z
  34.             myjwt = MyJwt()
    ' h+ E' h" ~4 e
  35.             token = myjwt.encode({"id":user.id})
    " Z0 d. g" A# G8 T  C7 a1 R
  36.             self.finish({"msg":"ok","errcode":0,"public_address":public_address,"token":token})
    % K: n7 f2 x/ Z" j9 K$ d* i/ W
  37.         else:
    $ z: r7 h& K; `. e
  38.             self.finish({"msg":"could not authenticate signature","errcode":1})
复制代码
0 \& R  u8 _5 ]' y2 G$ K+ n' X
   这里通过recoverHash方法对签名进行反编译操作,如果反编译后的钱包地址和前端传过来的钱包地址吻合,那么说明当前账户的身份验证通过:" M& h6 t; Y* v. d

2 u- s/ a4 p7 c& ~  a  \
* _3 p. R( {$ x& W- u$ B) h2 ^9 e4 R* m/ r7 F
4 n" W& ?1 B* l- c6 X
当验签通过之后,利用钱包地址在后台创建账号,随后将钱包地址、token等信息返回给前端,前端将其保存在stroage中即可。
$ U: n9 f8 o5 S- M, n$ g: l2 y( [& e* R6 h
    结语/ \/ C/ s) ]8 f5 x

  T* @4 N+ s# {6 x6 k  ?/ j7 N    没错,将至已至,未来已来,是时候将Web3.0区块链技术融入产品了,虽然有些固有的思维方式依然在人们的脑海挥之不去,但世界却在时不我待地变化着,正是:青山遮不住,毕竟东流去!项目开源在https://github.com/zcxey2911/Tornado6_Vuejs3_Edu
3 _' _8 E' D8 h$ x
  H, A8 n4 O7 m$ N
3 `1 L" s2 P3 I/ A9 N6 z, z
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

江左没浪 小学生
  • 粉丝

    18

  • 关注

    0

  • 主题

    7