Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
    今天去中心化身份逐渐被广泛采用。用户的部分在线活动在链上是公开的,可通过加密钱包搜索到,用户在链上创造、贡献、赚取和拥有的东西,都反映了他们的喜好,也逐渐积累成该用户的身份和标识。. m0 D7 g& M+ q% i
' i- P( R/ t# Y. w4 D: c3 w
    当我们的用户厌倦了传统的电子邮件/密码注册流程时,他们会选择Google、GitHub等社交登录方式,这种方式虽然节约了用户的时间,但登录信息也会被第三方平台记录,也就是说我们用平台账号做了什么,平台都会一目了然,甚至还会对我们的行为进行分析、画像。那么有没有一种登录方式,它的所有信息都只保存在客户端和后端,并不牵扯三方平台授权,最大化的保证用户隐私呢?Web3.0给我们提供了一种选择:MetaMask。
7 w4 U. j* K* S% }8 z5 O
8 u* T  X# [3 y2 d, v$ Y, w    MetaMask2 F$ z# W  `9 y! s
    MetaMask是用于与以太坊区块链进行交互的软件加密货币钱包。MetaMask允许用户通过浏览器插件或移动应用程序访问其以太坊钱包,然后可以使用这些扩展程序与去中心化应用程序进行交互。当然了,首先需要拥有一个MetaMask钱包,进入https://chrome.google.com/websto ... oehlefnkodbefgpgknn
0 d( p5 p( v% b$ M' i4 O0 X
/ D& q8 E. Y% h7 \    安装metamask浏览器插件:' U7 p* ]- B4 s! ?( J% @
0 |" T: m3 ~' @9 x/ v0 k

& h% y$ V- L: F  _+ V  随后点开插件,创建账号,记录密码、钱包地址、以及助记词等信息。
* e/ o6 ^% G7 S2 J& [+ a
7 `8 v( N/ u5 {; Q4 [- y2 g* ]6 b    安装好插件之后,我们就可以利用这个插件和网站应用做交互了。! A* q* v$ D* l* u# ~9 d3 t5 m- i
* z, [9 k) i% D! A
    钱包登录流程
3 A1 h# n! b' n6 H% s, g+ |    登录逻辑和传统的三方登录还是有差异的,传统三方登录一般是首先跳转三方平台进行授权操作,随后三方平台将code验证码返回给登录平台,登录平台再使用code请求三方平台换取token,再通过token请求用户账号信息,而钱包登录则是先在前端通过Web3.js浏览器插件中保存的私钥对钱包地址进行签名操作,随后将签名和钱包地址发送到后端,后端利用Web3的库用同样的算法进行验签操作,如果验签通过,则将钱包信息存入token,并且返回给前端。
& `. w7 ^$ w1 e: b( i
) l( S, @! s2 d- K, B( J
% L. K3 {* g  F+ y
) T- F! F' k+ _前端签名操作
* ?  @0 G8 @: b" C) t    首先需要下载前端的Web3.0操作库,https://docs.ethers.io/v4/,随后集成到登录页面中:
' W0 i# V' m# ]% h/ N1 y' }
0 D7 E) M: u9 ^6 Q9 y* c7 q( j" |1 j/ m) T( c8 f# `
  1. <script src="{{ static_url("js/ethers-v4.min.js") }}"></script># P  N2 j0 O5 |3 e! V
  2. <script src="{{ static_url("js/axios.js") }}"></script>
    + s$ o  X- t! E
  3. <script src="{{ static_url("js/vue.js") }}"></script>
复制代码
( ~, m5 n5 y. W

  }/ i1 ^( _8 g0 P, r; \, x  E5 w' J3 Y3 T7 D/ z
这里我们基于Vue.js配合Axios使用。" b8 c8 i, f- t$ ]: _( b

) {( k, i) r6 F- }8 y; ?% w    接着声明登录激活方法:% h3 B$ D# ]: V" l1 K, K
4 t. K1 ^. ]4 T; V, _. `' [/ H
  1. sign_w3:function(){; I! ]* ]% Y- T$ q2 z6 _( j8 y1 q
  2. : \, z* k7 z* n4 z: E
  3.                     that = this;; A* i% J* ^4 U" W' H/ Q5 B
  4.                     ethereum.enable().then(function () {. X$ q' @3 x0 L5 @6 b7 Q* Q

  5. % u: z5 v0 X* O7 c
  6.     this.provider = new ethers.providers.Web3Provider(web3.currentProvider);
    ! [* ?  w  t/ T, |! U. {/ }4 m
  7. / C5 u6 M6 ~( n5 |( s. u, v; Y
  8.     this.provider.getNetwork().then(function (result) {5 `9 |+ N3 S  V* Z) w, G
  9.         if (result['chainId'] != 1) {
    6 ^! r  L: ?# r$ X+ i1 _
  10. 9 m9 m0 X+ n) s6 A
  11.             console.log("Switch to Mainnet!")/ ^; _; l; Z) l- n. O" |) ^

  12. 5 ]- G7 O6 `1 X7 s: `4 C
  13.         } else { // okay, confirmed we're on mainnet
    & v+ g+ }$ }& `" Q1 E
  14. . }  ?2 i+ [% k, h
  15.             this.provider.listAccounts().then(function (result) {6 Z! i! ]0 p& d- o  h
  16.                 console.log(result);
    ' d0 T5 d0 J5 I4 M; j- E
  17.                 this.accountAddress = result[0]; // figure out the user's Eth address
    $ T1 [8 z& v( Y, h) }- T0 A! A
  18.                 this.provider.getBalance(String(result[0])).then(function (balance) {/ [7 T2 r. h5 A
  19.                     var myBalance = (balance / ethers.constants.WeiPerEther).toFixed(4);1 Y* V+ H4 L) M2 x$ S: \
  20.                     console.log("Your Balance: " + myBalance);4 w! }7 o  e: r9 W6 G
  21.                 });
    6 S/ R9 |$ T. h: i6 r' v% o

  22. 6 P: a8 X6 D" _9 _  N4 J
  23.                 // get a signer object so we can do things that need signing
    - a/ v' k4 x/ z9 S) Q
  24.                 this.signer = provider.getSigner();
    0 c' z- Y# T5 v* D3 g9 b8 ]4 f1 C

  25.   E) i7 @* R' Q8 i# \9 y9 ?2 `
  26.                 var rightnow = (Date.now()/1000).toFixed(0)
    8 k. b9 H7 h( M- i
  27.         var sortanow = rightnow-(rightnow%600)3 V6 W6 e1 H. V; i  T% c* z

  28. - x0 A7 W5 J! Z4 m% r
  29.         this.signer.signMessage("Signing in to "+document.domain+" at "+sortanow, accountAddress, "test password!")
    + v+ l5 ?2 @5 Z$ |
  30.             .then((signature) => {               that.handleAuth(accountAddress,signature);- w( \3 f$ j8 Y  t% c, H
  31.             });
    8 |( ?+ |) g6 ]4 d7 j
  32. . D. f- h2 ^: ?& V- l  r
  33.                 console.log(this.signer);
    , ?+ O# Z% u) C, p
  34.             })/ l4 t& L  A- q
  35.         }
    5 Z" `5 }% L' `9 N+ t1 F. w* {
  36.     })
    4 @' r& k: {. {; k7 K  e- r
  37. })
    , \  j# q3 `! H$ e: F

  38. , o3 w2 g" U# p
  39.                 },
复制代码
通过使用signMessage方法返回签名,这里加签过程中使用基于时间戳的随机数防止未签名,当前端签名生成好之后,立刻异步请求后台接口:
" n5 f: `/ {; X) K8 O/ U  y  I0 [& ^$ R9 |* d, o1 Y+ p
  1. //检查验证
    0 k# |* w  `) F
  2.                 handleAuth:function(accountAddress, signature){
    7 X% r% K( r4 @* }& L

  3. - i* r% U7 ^' s% l

  4. 7 U: o. R' i7 n7 k6 w! O
  5.                     this.myaxios("/checkw3/","post",{"public_address":accountAddress,"signature":signature}).then(data =>{
    # l& d- y, S. G0 e3 M" n
  6. , J3 c+ y7 X9 c0 q1 s+ P# D
  7.                         if(data.errcode==0){! o3 H+ _" C- w% @  y. g9 ^( Q
  8.                             alert("欢迎:"+data.public_address);
    $ m' V3 c4 f; ~( @
  9.                             localStorage.setItem("token",data.token);
    $ e8 p( ~7 @/ }( m: n3 R
  10.                             localStorage.setItem("email",data.public_address);
    0 l, ~  O; O) k/ D( Y* [
  11.                             window.location.href = "/";& Q5 ~# e) p" j# }8 D
  12.                         }else{. w$ ]' o3 U% @; d5 s, k
  13.                             alert("验证失败");; D: E' ]3 C0 I
  14.                         }$ b7 [' A+ H/ K- _# L& P
  15.                  });
    . A! ~. K+ U  q0 A  I. B: x7 Y

  16. 2 y, ]4 S4 H) f$ s7 l0 P
  17. 5 y( c- ]2 X1 k" ]
  18. . h& N; i! @+ L
  19.                 }
复制代码
这里将当前账户的钱包地址和签名传递给后端,如图所示:/ Q9 J) j9 F8 L1 C) l

5 C7 ~- X8 [  l8 A  p8 l( B7 j( t6 S. h' o& y- u2 K
' f: R3 l( A: |) s
/ }) q7 R4 S1 w  ]7 d# {- x
随后创建异步视图方法:
( h& {* m8 \* N# j( Z7 L
  1. from tornado.web import url
    1 |* H" y5 B# c+ N
  2. import tornado.web
    . R% A0 Y, h( ?9 V& g
  3. from tornado import httpclient/ |8 y2 ~3 v9 `) w( E5 s
  4. from .base import BaseHandler* [. C" P) @" j; x  t! a/ d- f$ U9 K+ d
  5. from web3.auto import w3/ W% h- P; q4 D% A% {0 h" u
  6. from eth_account.messages import defunct_hash_message0 Q1 ^; z, b' F
  7. import time
    - w" E; ], G0 i" j  S3 `
  8. 7 J& l, H7 J" \- ?5 _
  9. class CheckW3(BaseHandler):4 U0 B' G. X2 C  D2 `7 @
  10.   B) c. E2 ~. p- Y/ l1 F
  11.     async def post(self):: `1 I8 n( v: |/ S. d! x
  12. 2 z! W" k0 h# w5 `1 v8 L2 v! i
  13.         public_address = self.get_argument("public_address")( Z9 p* [1 f# b( [) o$ C
  14.         signature = self.get_argument("signature")
    ' O% R2 p4 ~9 g: O& k0 }

  15. 9 \+ Y3 p# W+ G
  16.         domain = self.request.host
    $ t( u3 F" z$ ^
  17.         if ":" in domain:0 h5 Y' K3 q  C0 {$ N* ]
  18.             domain = domain[0:domain.index(":")]
    + h$ |  E4 Y" ^3 L& ]1 ?, f; d( G

  19. 3 |& U% ?  B! r4 X' {
  20.         now = int(time.time())( _8 x* d) F3 }: S4 C4 ~  ?+ W
  21.         sortanow = now-now%600- f/ `$ m0 Z  @" r. x
  22.    
    . w% {+ j# a" \1 R2 ?
  23.         original_message = 'Signing in to {} at {}'.format(domain,sortanow)
    0 l$ U+ `) \  \% s* [: E
  24.         print("[+] checking: "+original_message); x9 e1 T9 D1 Z7 e$ o; _8 U2 f
  25.         message_hash = defunct_hash_message(text=original_message)
    5 _& ~( n# u. P6 }* V- L0 j
  26.         signer = w3.eth.account.recoverHash(message_hash, signature=signature)
    * E; h- m7 p- [: \" P0 e3 Z
  27. 4 z, t2 O7 @: {. q* b7 w: C# W
  28.         if signer == public_address:* s7 m( Q, C' o; c
  29.             try:
    ( R+ g0 [6 @! w: Z. E7 T3 ]5 l. _/ U! U
  30.                 user = await self.application.objects.get(User,email=public_address)
    4 A' S$ r# D' D5 [/ N" I) G
  31.             except Exception as e:
    , Y+ ^+ G+ G4 t: Q
  32.                 user = await self.application.objects.create(User,email=public_address,password=create_password("third"),role=1)
    5 N- ~) K: {, t6 d

  33. # w1 Y$ s5 X: r
  34.             myjwt = MyJwt()
    ! }( w! D* B% A0 r8 b
  35.             token = myjwt.encode({"id":user.id})8 x! O0 [7 r' _& l% |9 b
  36.             self.finish({"msg":"ok","errcode":0,"public_address":public_address,"token":token})( I: ]9 D3 Q' }: t; ~
  37.         else:
    3 L; @* b& k) j
  38.             self.finish({"msg":"could not authenticate signature","errcode":1})
复制代码

; w7 A% a& G# d( m   这里通过recoverHash方法对签名进行反编译操作,如果反编译后的钱包地址和前端传过来的钱包地址吻合,那么说明当前账户的身份验证通过:
, e* `1 Y5 F8 l+ i0 C1 G5 `* s" m9 c: C# W6 b
( u" B/ i( n! k4 J7 {- c( y! G
# f0 ]' S' ?4 ~) O5 Z+ E* f
6 z) Z! ^. T0 b9 B5 i! b/ A
当验签通过之后,利用钱包地址在后台创建账号,随后将钱包地址、token等信息返回给前端,前端将其保存在stroage中即可。
2 m& e1 d1 ]9 @: ]
% r2 x& U" G) v    结语
, ^4 A- s" l8 s: E" E& d% @% {3 C- I: l
    没错,将至已至,未来已来,是时候将Web3.0区块链技术融入产品了,虽然有些固有的思维方式依然在人们的脑海挥之不去,但世界却在时不我待地变化着,正是:青山遮不住,毕竟东流去!项目开源在https://github.com/zcxey2911/Tornado6_Vuejs3_Edu 1 t" e. K; q8 X! u. @4 {
/ `0 `4 U; P4 J3 Y

( t5 i3 Z4 y* W1 Q& i
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

江左没浪 小学生
  • 粉丝

    18

  • 关注

    0

  • 主题

    7