Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
    今天去中心化身份逐渐被广泛采用。用户的部分在线活动在链上是公开的,可通过加密钱包搜索到,用户在链上创造、贡献、赚取和拥有的东西,都反映了他们的喜好,也逐渐积累成该用户的身份和标识。! O, b5 F" y2 G0 Z  ?+ g
4 B1 z8 @- l( O3 m
    当我们的用户厌倦了传统的电子邮件/密码注册流程时,他们会选择Google、GitHub等社交登录方式,这种方式虽然节约了用户的时间,但登录信息也会被第三方平台记录,也就是说我们用平台账号做了什么,平台都会一目了然,甚至还会对我们的行为进行分析、画像。那么有没有一种登录方式,它的所有信息都只保存在客户端和后端,并不牵扯三方平台授权,最大化的保证用户隐私呢?Web3.0给我们提供了一种选择:MetaMask。) a. }( L8 e' x" h0 j0 Q
; V& x$ \5 x( O
    MetaMask
) \6 ]4 H/ k8 }- J4 U    MetaMask是用于与以太坊区块链进行交互的软件加密货币钱包。MetaMask允许用户通过浏览器插件或移动应用程序访问其以太坊钱包,然后可以使用这些扩展程序与去中心化应用程序进行交互。当然了,首先需要拥有一个MetaMask钱包,进入https://chrome.google.com/websto ... oehlefnkodbefgpgknn 7 {" S% r2 h6 f" H0 c

7 j& f3 ?; t7 j$ e# l' k    安装metamask浏览器插件:
1 K, I" _/ E- D0 V1 O
5 _, x' ~$ z7 j$ B  M0 b% u  U2 j7 Y) p
  随后点开插件,创建账号,记录密码、钱包地址、以及助记词等信息。
( w# ]* W! q2 J1 ]; @
& B( s7 Y0 Z; t" k6 ~    安装好插件之后,我们就可以利用这个插件和网站应用做交互了。
7 e; [1 k3 G% m! I1 C2 h5 w
7 k- i6 K$ m7 U% X    钱包登录流程/ t6 V  x3 S: X1 M
    登录逻辑和传统的三方登录还是有差异的,传统三方登录一般是首先跳转三方平台进行授权操作,随后三方平台将code验证码返回给登录平台,登录平台再使用code请求三方平台换取token,再通过token请求用户账号信息,而钱包登录则是先在前端通过Web3.js浏览器插件中保存的私钥对钱包地址进行签名操作,随后将签名和钱包地址发送到后端,后端利用Web3的库用同样的算法进行验签操作,如果验签通过,则将钱包信息存入token,并且返回给前端。9 Z4 O8 a' d! }' J. N

: n# `: @! V( U0 _8 L" m' }. W& x0 f5 F+ K7 ^3 W1 P

# h7 m& V6 U4 s) |- G, W前端签名操作, R, K( |+ t  |# a
    首先需要下载前端的Web3.0操作库,https://docs.ethers.io/v4/,随后集成到登录页面中:- N9 Z( W, R& o8 ]# Y1 P
, x" W2 h! I" S2 C8 \; n: d
" v5 B: ?* c6 E6 C6 n& H
  1. <script src="{{ static_url("js/ethers-v4.min.js") }}"></script>3 w% T+ E6 M- d  a4 K' O7 m
  2. <script src="{{ static_url("js/axios.js") }}"></script>
    ! J/ z, d1 a  u' h
  3. <script src="{{ static_url("js/vue.js") }}"></script>
复制代码
: p# O1 Y  Y2 Q/ c& x0 @. V9 I

0 w3 E8 ~5 R# g$ C6 J+ f) G  E/ U3 ~4 U) o& ]1 C8 L+ O
这里我们基于Vue.js配合Axios使用。/ [9 h$ j% e# x
7 W2 f: f4 J- X, ~' n8 D! k9 u
    接着声明登录激活方法:3 H8 J* S7 g/ U: @- ~' d9 k6 |

& F; `9 _& a* ]- a
  1. sign_w3:function(){" z) M' L7 h; R) ~4 N
  2. ) ^$ T, i5 D' ?4 H" J+ n
  3.                     that = this;
    * e2 }  f4 v1 p' H$ N
  4.                     ethereum.enable().then(function () {" ^: S* B) ~' h! t; v5 C! z+ Q
  5. 2 c9 E, E3 ?; m& A
  6.     this.provider = new ethers.providers.Web3Provider(web3.currentProvider);
    # B* e8 ?" z$ e. d7 b

  7. 5 B! A: f3 A. I/ i
  8.     this.provider.getNetwork().then(function (result) {
    ' P; A" X2 x- ?, K- Y
  9.         if (result['chainId'] != 1) {
    5 M9 t% o# Y- X7 e

  10. 6 x) N& @: k% |5 r1 o7 |* L( p
  11.             console.log("Switch to Mainnet!")
    ' R' H* i9 Q7 B- H9 L/ a7 q
  12. 0 b) t5 g& v% k9 t
  13.         } else { // okay, confirmed we're on mainnet, e  ^* ?: B: O2 \4 C, f, H* D* t4 M
  14. 5 T, d) e: {# _- D
  15.             this.provider.listAccounts().then(function (result) {0 q+ `* V. |1 E/ `' `1 I  c' k. v
  16.                 console.log(result);2 t  j* Y, B; T. \1 K5 T/ Z. P: |
  17.                 this.accountAddress = result[0]; // figure out the user's Eth address
    4 _6 R8 b+ S8 N* S; \  ]
  18.                 this.provider.getBalance(String(result[0])).then(function (balance) {
    ; w3 W6 R2 _* p: \8 o; x. O/ N
  19.                     var myBalance = (balance / ethers.constants.WeiPerEther).toFixed(4);
    5 b' n( O& A+ L& X
  20.                     console.log("Your Balance: " + myBalance);
    + R4 J+ s* j( {8 ~  J9 K
  21.                 });! X% H& f5 A! @! q. X3 K6 ]. W
  22. + u. v$ i2 }2 p0 p% B/ L$ E
  23.                 // get a signer object so we can do things that need signing2 E1 y# z; O( _. z  }+ p
  24.                 this.signer = provider.getSigner();
    7 U2 b% O; D1 R0 U7 ^8 P

  25. 7 ^  f) l/ ~. c3 ~
  26.                 var rightnow = (Date.now()/1000).toFixed(0)
    2 Q% q! p' i! D1 Q9 P! T
  27.         var sortanow = rightnow-(rightnow%600)& x) Y5 n1 K, l

  28. 9 |: Q# V3 E1 ]; q3 n
  29.         this.signer.signMessage("Signing in to "+document.domain+" at "+sortanow, accountAddress, "test password!")
    : ]0 k$ @1 w" L7 _2 O
  30.             .then((signature) => {               that.handleAuth(accountAddress,signature);9 c# c& ]- {4 w3 X* H9 f/ }
  31.             });2 d- b1 f$ g; b9 i( T

  32. 6 Q$ Y: R: U# E1 E1 c8 H6 M9 @+ Z& O
  33.                 console.log(this.signer);
    5 \+ \/ {9 |; X2 `3 s- W
  34.             })2 P4 M9 e$ j+ d# @3 P  W
  35.         }" |8 G  a4 @7 \1 z# u# B/ {
  36.     })
    * [+ d+ s$ v" Q+ y+ O7 M
  37. })
    3 g. k( f- J. ?" Q

  38. * Q# G8 F6 K7 o+ v
  39.                 },
复制代码
通过使用signMessage方法返回签名,这里加签过程中使用基于时间戳的随机数防止未签名,当前端签名生成好之后,立刻异步请求后台接口:
$ @: W% O; L8 H* r" ?! z+ ]7 v" g' u- p
0 Z+ e1 Y* W, A6 N
  1. //检查验证
    6 {+ x+ Z7 o9 f
  2.                 handleAuth:function(accountAddress, signature){
    5 J& N: r1 F5 ]! `& A/ i
  3. ! K& e! |( y  x

  4. & S6 F! G, X# `: V
  5.                     this.myaxios("/checkw3/","post",{"public_address":accountAddress,"signature":signature}).then(data =>{
    4 r& G, X. f9 T: H
  6. " S% Q. N+ ~! l
  7.                         if(data.errcode==0){
    6 W0 I. D* O0 R7 _+ Z
  8.                             alert("欢迎:"+data.public_address);
    ; D& u$ H  e! T9 ~' E! q
  9.                             localStorage.setItem("token",data.token);
    8 l3 ?7 `+ t) L" ^9 v$ M2 x% T
  10.                             localStorage.setItem("email",data.public_address);
    2 U* E' Z/ V9 d" T, r1 X. m
  11.                             window.location.href = "/";
    5 D9 f- ?4 d; X/ v
  12.                         }else{
    6 f6 u: f/ E) {0 Y. L& H# K
  13.                             alert("验证失败");
    % |) K5 v/ m' u
  14.                         }/ P+ I; H4 i% C' `3 _
  15.                  });
    0 ~* ?2 G. o9 X& D! G% G7 o

  16. 6 r) Q7 I/ Z  B+ _' ?. k

  17. & G5 K, Y8 R& s, o- o$ R/ m  y- H; E

  18. - m" |8 O) V, L9 `
  19.                 }
复制代码
这里将当前账户的钱包地址和签名传递给后端,如图所示:
& }$ H. W  g6 R8 Q  e; E. N! O, V) u9 o9 z  E' @: ~
  s/ E- K# K0 O
7 ?, \6 P" g. L* h4 a
0 Z& R( H; M# }  n" F5 [$ }
随后创建异步视图方法:4 l- z, ]1 {: O7 m: T
  1. from tornado.web import url
    & U& @( e/ Z. |' H' p
  2. import tornado.web
    + c- }2 Y& E( {; ~7 d) q! _
  3. from tornado import httpclient# r2 Z5 a: U3 ^: J
  4. from .base import BaseHandler! E. Q% R! w5 C+ P
  5. from web3.auto import w3' a; n8 y& }8 b" B
  6. from eth_account.messages import defunct_hash_message
    ) k+ M5 K1 T$ ^5 y5 N
  7. import time+ W9 U4 G6 k3 p" q, y# f' J# p

  8. ! k* t4 U. n4 }4 k9 V
  9. class CheckW3(BaseHandler):
    6 y- M' t3 Q5 K1 ~
  10.   x/ Q+ _% u( t1 P, D+ a* V
  11.     async def post(self):
    - K% l+ C0 H$ N) H: y4 n: F
  12. $ d6 G3 f7 N+ K8 ~
  13.         public_address = self.get_argument("public_address"). y' E% m7 p, `1 X! d
  14.         signature = self.get_argument("signature")
    ( O9 |7 x% ]) ~
  15. , T. }# N' o0 T, z* n) f7 b
  16.         domain = self.request.host6 i! r  G" U& k+ `- G
  17.         if ":" in domain:
    9 y' r* L/ p. b3 e- q' X' s8 J  ~
  18.             domain = domain[0:domain.index(":")]6 Y* `  G3 I$ K) T/ P

  19. ' d7 n% B/ R4 l) I" q3 z
  20.         now = int(time.time())3 m6 l# M2 ?  D: \9 x! v$ ]
  21.         sortanow = now-now%600" s- {7 z( k) q3 \5 g
  22.    & D1 g- K3 x. T- B3 d1 y# X
  23.         original_message = 'Signing in to {} at {}'.format(domain,sortanow)
    ; ]8 X& [4 G: R
  24.         print("[+] checking: "+original_message)' C5 i0 E! \# n; \# p1 \
  25.         message_hash = defunct_hash_message(text=original_message)  M2 {3 N; M  W$ K! J* N/ D4 j
  26.         signer = w3.eth.account.recoverHash(message_hash, signature=signature)
    / h5 \7 h  a9 p; k' K* i
  27. ! s( }9 a5 R& L9 V* G
  28.         if signer == public_address:
    0 M$ E. P: T: Y6 J6 f
  29.             try:
    , A: y& E) Q, O: d7 T/ w9 m7 f( f
  30.                 user = await self.application.objects.get(User,email=public_address)3 Z: ~1 j* K3 i+ _1 F
  31.             except Exception as e:3 w9 a7 g# R$ \  t3 L) {- {
  32.                 user = await self.application.objects.create(User,email=public_address,password=create_password("third"),role=1); P  T; u1 S! y1 N
  33. ( U) q; R/ v' e( r, p$ [4 z
  34.             myjwt = MyJwt()
    - l7 h. W4 l' S& G" |8 F
  35.             token = myjwt.encode({"id":user.id}): {0 }# n& V/ A6 ]; ?# c
  36.             self.finish({"msg":"ok","errcode":0,"public_address":public_address,"token":token})
    # z8 ?( k8 i) j0 N3 {( U1 I8 ]% z  q
  37.         else:4 s& O+ a" U. e
  38.             self.finish({"msg":"could not authenticate signature","errcode":1})
复制代码
* |1 X$ Z6 w- z' D* s3 }3 D( ]
   这里通过recoverHash方法对签名进行反编译操作,如果反编译后的钱包地址和前端传过来的钱包地址吻合,那么说明当前账户的身份验证通过:
$ l& _! e: x) Y1 D9 G& z  F8 B3 v
+ B  v3 k* ?9 [" ?" @; R/ O# d) z
8 U4 y) h: {& `. m
2 C7 m/ B3 r0 v( q1 V
8 C+ H  x  h  k* u, S, d' a, X 当验签通过之后,利用钱包地址在后台创建账号,随后将钱包地址、token等信息返回给前端,前端将其保存在stroage中即可。
# Z. s( `( A" M% O. r0 |" I+ `
0 j, Y0 B8 p  U1 {. |    结语
: }6 L4 D  p3 r( B, d+ N& c
5 c, F2 Y5 t& a- p    没错,将至已至,未来已来,是时候将Web3.0区块链技术融入产品了,虽然有些固有的思维方式依然在人们的脑海挥之不去,但世界却在时不我待地变化着,正是:青山遮不住,毕竟东流去!项目开源在https://github.com/zcxey2911/Tornado6_Vuejs3_Edu
- _5 ~. U: p( w " H! [* B( n* r7 v

9 X$ i* v- O& i9 F
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

江左没浪 小学生
  • 粉丝

    18

  • 关注

    0

  • 主题

    7