Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
    今天去中心化身份逐渐被广泛采用。用户的部分在线活动在链上是公开的,可通过加密钱包搜索到,用户在链上创造、贡献、赚取和拥有的东西,都反映了他们的喜好,也逐渐积累成该用户的身份和标识。- u& j3 }5 h7 Y9 }/ g  s( O! T3 y

/ ~5 _4 Q/ V) u7 o1 r" y    当我们的用户厌倦了传统的电子邮件/密码注册流程时,他们会选择Google、GitHub等社交登录方式,这种方式虽然节约了用户的时间,但登录信息也会被第三方平台记录,也就是说我们用平台账号做了什么,平台都会一目了然,甚至还会对我们的行为进行分析、画像。那么有没有一种登录方式,它的所有信息都只保存在客户端和后端,并不牵扯三方平台授权,最大化的保证用户隐私呢?Web3.0给我们提供了一种选择:MetaMask。
3 G; ~8 y9 l$ h. W7 f8 O
2 X7 u5 e* d4 X7 [& E    MetaMask1 W' y' E& ]4 {8 z
    MetaMask是用于与以太坊区块链进行交互的软件加密货币钱包。MetaMask允许用户通过浏览器插件或移动应用程序访问其以太坊钱包,然后可以使用这些扩展程序与去中心化应用程序进行交互。当然了,首先需要拥有一个MetaMask钱包,进入https://chrome.google.com/websto ... oehlefnkodbefgpgknn
* s( j; x$ g( L  z5 U/ b& G' l( a$ g: x! q0 z( ?' m
    安装metamask浏览器插件:
% o) ~8 J& c, k5 r" r5 M2 O7 n5 i/ S/ T2 d7 Y
4 k7 p/ w6 p/ Z" b( |$ J$ R
  随后点开插件,创建账号,记录密码、钱包地址、以及助记词等信息。0 e$ t/ _. s1 _7 \

& ^' n2 |2 q  o; x; a5 c3 }    安装好插件之后,我们就可以利用这个插件和网站应用做交互了。
$ \% P/ J; I$ t0 M( i7 i
. Y' p/ p. R& W% j    钱包登录流程
& j" v* _7 o3 a( f    登录逻辑和传统的三方登录还是有差异的,传统三方登录一般是首先跳转三方平台进行授权操作,随后三方平台将code验证码返回给登录平台,登录平台再使用code请求三方平台换取token,再通过token请求用户账号信息,而钱包登录则是先在前端通过Web3.js浏览器插件中保存的私钥对钱包地址进行签名操作,随后将签名和钱包地址发送到后端,后端利用Web3的库用同样的算法进行验签操作,如果验签通过,则将钱包信息存入token,并且返回给前端。: y, {; N: j8 ?3 ]" k/ N4 z: i, C

- Q  {. p' ], j' b
4 u2 P2 s$ E# K3 h- a! R# M9 r7 g
前端签名操作) D" Q3 G) |# s
    首先需要下载前端的Web3.0操作库,https://docs.ethers.io/v4/,随后集成到登录页面中:' X3 b# Q$ D- m& V+ G* I* Z" h) |
3 Q) C" a( Y2 A' j2 z$ T

" Q; H. q: X6 V4 g' N
  1. <script src="{{ static_url("js/ethers-v4.min.js") }}"></script>( Z& @( j4 y, L  }1 @
  2. <script src="{{ static_url("js/axios.js") }}"></script>8 J: c& ~' \$ w4 _9 E- F
  3. <script src="{{ static_url("js/vue.js") }}"></script>
复制代码
4 L& P1 u! E# R' R% B1 b2 z
7 K$ q( n1 T. \& `8 ^$ `

& N' l& f2 w: [/ Y! ?' j这里我们基于Vue.js配合Axios使用。
1 T( z3 ~$ V$ B  Y2 w) s
; `% m$ A) @# e# B) ^    接着声明登录激活方法:
' ?) @# b9 O6 X, ?6 F6 B) q- O" K% ]
9 c& s3 W6 D7 i. H- Y. }
  1. sign_w3:function(){% [: o3 E  ~: `

  2. ! V/ w7 n$ ~2 k* u
  3.                     that = this;
    2 D0 ?/ K. ]' _. x( a
  4.                     ethereum.enable().then(function () {
    ) E5 U0 Q' k. M& P5 m0 R
  5.   h2 o8 T: X4 B
  6.     this.provider = new ethers.providers.Web3Provider(web3.currentProvider);
      Z( B# W# M( n+ {4 P
  7. * k6 ]  z) M/ W1 D; n& D% _
  8.     this.provider.getNetwork().then(function (result) {
    7 [3 S& r  }4 n
  9.         if (result['chainId'] != 1) {
    2 s1 d' x# D: M% n' z/ r  Z
  10. # j  p5 u. v  |+ w2 Q& }
  11.             console.log("Switch to Mainnet!")
    * H/ a# A! \4 o* _8 O5 S9 v& J$ w- ]! ~
  12. 7 S/ u" Z) W, m1 u7 j" T
  13.         } else { // okay, confirmed we're on mainnet
    / i# U+ \' ]* d7 D7 x: u1 b

  14. / l1 Y4 _9 W2 v" C
  15.             this.provider.listAccounts().then(function (result) {7 |& R7 w+ ?2 k, k+ |" A6 x
  16.                 console.log(result);
    / d$ P3 I' l$ C9 j1 j. ~' F: m
  17.                 this.accountAddress = result[0]; // figure out the user's Eth address; S3 P: u+ t& |/ l/ p
  18.                 this.provider.getBalance(String(result[0])).then(function (balance) {) N( t8 A' {) K
  19.                     var myBalance = (balance / ethers.constants.WeiPerEther).toFixed(4);  S" D# Y: z  O
  20.                     console.log("Your Balance: " + myBalance);- q) |8 f! N' T. |! m
  21.                 });6 P" R0 {( u  x% U) E

  22. & C$ T: j4 }  |: I( I7 c' Q
  23.                 // get a signer object so we can do things that need signing
    : T6 D4 V; \' D2 p: t
  24.                 this.signer = provider.getSigner();
    " D1 ]! ?3 @$ K" c' X4 M5 q
  25. * U8 a# d. x! ]  ~7 ]8 c0 v2 x
  26.                 var rightnow = (Date.now()/1000).toFixed(0)
    & l6 j+ \& |/ v. X8 A5 Z
  27.         var sortanow = rightnow-(rightnow%600), D( N: N  ?. E/ q
  28. % v  i7 S1 ^+ u
  29.         this.signer.signMessage("Signing in to "+document.domain+" at "+sortanow, accountAddress, "test password!")
    * _/ T( A" R* C1 Y8 w# X# D
  30.             .then((signature) => {               that.handleAuth(accountAddress,signature);
    6 F9 v0 @4 I) o$ w: I2 K
  31.             });/ I# K: v" D2 \1 U! O2 p5 R

  32. & a& q5 M3 Q8 s, s6 I& |0 V
  33.                 console.log(this.signer);) Y  Q, n! i4 {/ q: Q  j, w. \
  34.             })5 v; }% q, g5 O/ D1 E! N& F
  35.         }1 V: W( o, Q( e' }/ B
  36.     }); k4 M& ?9 L4 Y6 ?, l+ @) d! o
  37. })1 j3 P* D5 s& q  q/ [
  38. 7 ~) g/ {) u& j8 q$ ~7 n4 e( L
  39.                 },
复制代码
通过使用signMessage方法返回签名,这里加签过程中使用基于时间戳的随机数防止未签名,当前端签名生成好之后,立刻异步请求后台接口:5 ], R) w5 f9 Z8 X: G8 e5 L, F
* B) n9 u% I6 l8 o4 @$ d' D$ T' G0 b5 [
  1. //检查验证
    " ]! z! H7 ], ~+ [8 ?
  2.                 handleAuth:function(accountAddress, signature){- Y" t0 p5 [( I$ e: y
  3. 6 Q! c$ k9 ]7 M- d! ?6 y

  4.   ^, q( w4 a9 \6 m1 i  O9 y( J- p
  5.                     this.myaxios("/checkw3/","post",{"public_address":accountAddress,"signature":signature}).then(data =>{
    3 c4 k6 T; |7 {' U0 E! P

  6. 0 k& o2 \) e9 ^% Y+ b# w) O* p% q
  7.                         if(data.errcode==0){2 u9 ^+ u& x' [" B  r3 h
  8.                             alert("欢迎:"+data.public_address);
      W8 v3 `" k0 b
  9.                             localStorage.setItem("token",data.token);
    1 m# C" ?* ^1 M) ]1 K
  10.                             localStorage.setItem("email",data.public_address);. f% s* S+ M! P0 \$ _) V" e
  11.                             window.location.href = "/";
    " n* j2 D. U0 k) V! Q
  12.                         }else{
    + |' c7 G! t' L/ _5 t% a
  13.                             alert("验证失败");0 O- l2 R1 T, i( I( J
  14.                         }
    8 F: T1 m5 W! M& r+ w: }
  15.                  });  Y, i) P2 c$ w

  16. 4 s3 H& l7 y0 ~; k- A
  17. . k; [3 T5 I6 z3 t- ?
  18. ) E4 O3 z7 B4 I$ i% v
  19.                 }
复制代码
这里将当前账户的钱包地址和签名传递给后端,如图所示:9 R# W( E0 y( K% P! \8 u' t
. I- x2 i% ~# E/ E1 V7 X5 s

% B7 }) }; H0 M7 ^6 [
8 N/ v* @) A# j* _( U
6 `1 ~! X& j& H* h% v 随后创建异步视图方法:2 C: C. a" a" m+ d
  1. from tornado.web import url& F5 ]: v0 \1 H4 Z4 n5 N+ S5 D+ u
  2. import tornado.web
    5 c* p9 h% q' E4 u4 |7 w# x" |) [
  3. from tornado import httpclient6 ~- X6 [8 z! ?# T
  4. from .base import BaseHandler
    8 Y/ c6 R( G& b* W% c& N
  5. from web3.auto import w35 O6 Z( \& e" H6 V/ Z+ p/ B/ A
  6. from eth_account.messages import defunct_hash_message$ A8 L" z1 k" i' U
  7. import time
    / X& y# d; C( F: P* M. q! ]* x$ @
  8. 5 `4 a/ j2 D6 Q3 [
  9. class CheckW3(BaseHandler):2 N% \3 o, ?0 o

  10. 8 s: P( G& N# X6 \
  11.     async def post(self):
    1 {" H8 v5 n  R6 y
  12. " J2 }' g- l/ t% M  |8 {
  13.         public_address = self.get_argument("public_address")
    % C: d$ w/ X$ Y) |6 y$ ^' F
  14.         signature = self.get_argument("signature")
    & A% w6 e. {" g. A3 u
  15. ; {, @6 n5 X3 d
  16.         domain = self.request.host
    1 V8 s/ t! y+ y& C/ Y# B
  17.         if ":" in domain:. ]4 J6 \6 B# a3 ]$ {8 u3 ^
  18.             domain = domain[0:domain.index(":")]
    0 k/ a1 N# {" `. D4 @" X3 Z2 L+ ]0 d1 N

  19. ) E' n+ L, I$ e& R3 n. c
  20.         now = int(time.time())' g7 O( X. X2 }9 K! O+ T; K# \
  21.         sortanow = now-now%600
    # Q" V3 j* @2 A# d& \" ^/ u  s' d  j5 k% H
  22.    
    - H: |3 H  k4 L
  23.         original_message = 'Signing in to {} at {}'.format(domain,sortanow)  w8 ?4 ^7 L: B# B
  24.         print("[+] checking: "+original_message)
    2 F3 A) C: P, W; c9 c  ~
  25.         message_hash = defunct_hash_message(text=original_message)9 k- \4 A- O; p2 C. I4 f
  26.         signer = w3.eth.account.recoverHash(message_hash, signature=signature)0 i9 N* q$ Q- ?: `$ k% o

  27. ; _+ n! E0 d9 q: |' i# e+ T
  28.         if signer == public_address:+ u# y3 W# i& M! N
  29.             try:, |) C  r  Q( Z) s# D; i* W
  30.                 user = await self.application.objects.get(User,email=public_address). |3 I9 A% w" N
  31.             except Exception as e:  |7 X  J5 B3 `  H6 j0 h
  32.                 user = await self.application.objects.create(User,email=public_address,password=create_password("third"),role=1)
    0 G1 J6 i+ z; w" U
  33. 6 l( }  J5 ]2 K
  34.             myjwt = MyJwt()! n( e* a1 x& Z4 O* e7 [
  35.             token = myjwt.encode({"id":user.id})
    * y! v( u% B1 u
  36.             self.finish({"msg":"ok","errcode":0,"public_address":public_address,"token":token})
    ! R* y9 j7 s, K. L  u+ @2 }
  37.         else:
      w( x0 z2 E- H! `
  38.             self.finish({"msg":"could not authenticate signature","errcode":1})
复制代码
% L0 C' I0 G5 v
   这里通过recoverHash方法对签名进行反编译操作,如果反编译后的钱包地址和前端传过来的钱包地址吻合,那么说明当前账户的身份验证通过:7 [2 n) q/ @( e4 |, T5 h. l
$ Q9 Y* S' r2 J& `. G& d
* D. K- ~, t/ R! ]" [
) P+ ?# S3 P/ x; e" y* U$ e% e

0 C: z* {0 o3 D9 P2 s! k9 z 当验签通过之后,利用钱包地址在后台创建账号,随后将钱包地址、token等信息返回给前端,前端将其保存在stroage中即可。8 `0 r' r- ], m0 D4 ]8 Q

2 S! z! k# E3 i  x# }1 H" K8 Z2 y. @    结语, d+ \* |; Q2 I
7 ^( a7 P3 l% [. j! F1 F3 [
    没错,将至已至,未来已来,是时候将Web3.0区块链技术融入产品了,虽然有些固有的思维方式依然在人们的脑海挥之不去,但世界却在时不我待地变化着,正是:青山遮不住,毕竟东流去!项目开源在https://github.com/zcxey2911/Tornado6_Vuejs3_Edu
3 I6 C: |5 u, X+ s - f4 K& ~/ L( O

: m# M  u2 R$ ?  g
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

江左没浪 小学生
  • 粉丝

    18

  • 关注

    0

  • 主题

    7