Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
    今天去中心化身份逐渐被广泛采用。用户的部分在线活动在链上是公开的,可通过加密钱包搜索到,用户在链上创造、贡献、赚取和拥有的东西,都反映了他们的喜好,也逐渐积累成该用户的身份和标识。2 ~/ P" |9 ^% l5 o

$ M: f" ]/ o% [. M( R9 T" X    当我们的用户厌倦了传统的电子邮件/密码注册流程时,他们会选择Google、GitHub等社交登录方式,这种方式虽然节约了用户的时间,但登录信息也会被第三方平台记录,也就是说我们用平台账号做了什么,平台都会一目了然,甚至还会对我们的行为进行分析、画像。那么有没有一种登录方式,它的所有信息都只保存在客户端和后端,并不牵扯三方平台授权,最大化的保证用户隐私呢?Web3.0给我们提供了一种选择:MetaMask。5 h- B! k( l% _; g
& \" j/ `0 \* \& b6 H0 H  |+ B4 e
    MetaMask
% Z7 I& }8 r" P% {/ G2 e    MetaMask是用于与以太坊区块链进行交互的软件加密货币钱包。MetaMask允许用户通过浏览器插件或移动应用程序访问其以太坊钱包,然后可以使用这些扩展程序与去中心化应用程序进行交互。当然了,首先需要拥有一个MetaMask钱包,进入https://chrome.google.com/websto ... oehlefnkodbefgpgknn 9 P, @3 V- t% K* {; }' G  j! \
: D/ G% F/ m& U0 ?5 k' u
    安装metamask浏览器插件:
) X0 r  u. z5 ?& y
( `! Y* g2 i/ f' a0 |( p
7 h! Z: u- ]' T! ?. e+ p  随后点开插件,创建账号,记录密码、钱包地址、以及助记词等信息。
- m, N, i3 J5 d  c) t
  F2 Z8 j, A4 ?' \1 L: ^) ^    安装好插件之后,我们就可以利用这个插件和网站应用做交互了。' s' n9 F3 w) C2 r

) v0 j9 Y, G5 O" c    钱包登录流程
# a9 E1 B# ]" Y& p4 C    登录逻辑和传统的三方登录还是有差异的,传统三方登录一般是首先跳转三方平台进行授权操作,随后三方平台将code验证码返回给登录平台,登录平台再使用code请求三方平台换取token,再通过token请求用户账号信息,而钱包登录则是先在前端通过Web3.js浏览器插件中保存的私钥对钱包地址进行签名操作,随后将签名和钱包地址发送到后端,后端利用Web3的库用同样的算法进行验签操作,如果验签通过,则将钱包信息存入token,并且返回给前端。2 E! @; s" [% y
' o. n1 W6 V; _! `. R0 x

0 @) X8 |$ n% c6 @, [6 Z+ c/ g7 F; Z7 l
前端签名操作$ ^! t# B6 I; l( F# A2 T- B
    首先需要下载前端的Web3.0操作库,https://docs.ethers.io/v4/,随后集成到登录页面中:
( K" k$ c& j1 t4 H  \9 k# Z3 }9 }5 ]
7 O& F2 ?- X# m' o
  1. <script src="{{ static_url("js/ethers-v4.min.js") }}"></script>" D- F/ b. [+ o8 j( ^- ~
  2. <script src="{{ static_url("js/axios.js") }}"></script>
    ; c. K& C0 q* N) D6 t; `5 d
  3. <script src="{{ static_url("js/vue.js") }}"></script>
复制代码

; W& o$ m3 l& I2 O  _5 D0 N- F7 E
. J/ G  ?. `0 [1 a
- w/ d0 L" e  }$ n这里我们基于Vue.js配合Axios使用。
# d! W. _1 b2 R$ ~2 m/ F
+ `' d: Y: G8 W" ]& X    接着声明登录激活方法:
. f# q4 _2 e) m4 e2 g
* @/ o0 g( S. U; b. A" k
  1. sign_w3:function(){/ X8 i7 K! |# H8 B

  2. ! \# s" M* O4 V% q% f9 t" \
  3.                     that = this;; S( h# y: I1 o
  4.                     ethereum.enable().then(function () {7 O* d, ]7 V' j; m& t
  5. : ?+ z5 S/ p; k
  6.     this.provider = new ethers.providers.Web3Provider(web3.currentProvider);
    - ]5 V4 e( i$ d/ {: U
  7. 1 ~6 i% L! G! H2 p# V) F
  8.     this.provider.getNetwork().then(function (result) {
    " T7 Q# ]; h) a6 `  Q4 c$ R$ O
  9.         if (result['chainId'] != 1) {
    , X1 D) N( q) u' @2 E

  10. 5 E! |% a# J, Z, ^
  11.             console.log("Switch to Mainnet!"), u$ M) S# h( F* e/ `& ?3 p
  12. % b2 A7 A9 a8 _3 ~( S
  13.         } else { // okay, confirmed we're on mainnet
    4 h! A' d) R( n8 p: ^1 m
  14. + X* R( x3 q  _5 |/ z" H
  15.             this.provider.listAccounts().then(function (result) {
    . d7 J0 k& Y6 C+ V7 N0 `
  16.                 console.log(result);' y% W" l, F% d. v; g0 u0 q
  17.                 this.accountAddress = result[0]; // figure out the user's Eth address
    8 o' V2 Y& |1 p$ }
  18.                 this.provider.getBalance(String(result[0])).then(function (balance) {
    7 B, n1 ~: I5 M
  19.                     var myBalance = (balance / ethers.constants.WeiPerEther).toFixed(4);
    1 h; p% n/ C! C0 a
  20.                     console.log("Your Balance: " + myBalance);
    3 v+ L* j  {/ ^) i0 |8 y
  21.                 });
    9 h* H& K0 D* u$ q

  22. 1 _* O/ {6 Y8 \; P* Q8 e3 j% o; o& s
  23.                 // get a signer object so we can do things that need signing4 P7 j+ z2 }) ~  Z
  24.                 this.signer = provider.getSigner();
    + m9 M, q% K0 h' g

  25. # g9 D6 ^$ n$ v" a* k3 I  Q9 g
  26.                 var rightnow = (Date.now()/1000).toFixed(0)( }% p0 d: E) d! V8 X5 Q/ b, [
  27.         var sortanow = rightnow-(rightnow%600)
    $ I4 F% o' t; R- E- E2 D2 \- b

  28. ( i- {  y% O: ]  b/ Z$ w& J
  29.         this.signer.signMessage("Signing in to "+document.domain+" at "+sortanow, accountAddress, "test password!")
    # H' K- _3 O* x3 f
  30.             .then((signature) => {               that.handleAuth(accountAddress,signature);' ?6 |, ~5 O/ U! x" K- z
  31.             });% _: L- c3 B* d, {& q* Y1 ^
  32. ( a; J/ S4 C# f3 U) o% n8 p
  33.                 console.log(this.signer);
    : M5 o  D& R. h" A* P3 w
  34.             })
    * A3 z' }, v; b( M, w
  35.         }
    ' S1 `* @" |0 l+ m  \
  36.     })
    + V( D5 ^  z& u" ]: i' D8 ]
  37. })
    1 I3 R8 Q3 {) V) r( Q9 i$ s

  38. & x! G. {8 S2 f1 m/ h5 ]" y
  39.                 },
复制代码
通过使用signMessage方法返回签名,这里加签过程中使用基于时间戳的随机数防止未签名,当前端签名生成好之后,立刻异步请求后台接口:
  N) b- P' V- `3 a! P4 ^% h
% T/ K: b- z* V: P! j* k% S6 Y
  1. //检查验证
    - e5 s8 ~  T; e7 U6 `
  2.                 handleAuth:function(accountAddress, signature){7 j5 O% s) E' T- V, I
  3. # w1 K  x, H' V) H% U: C! G; M& F
  4. 0 c# a" O( c2 H1 R  {
  5.                     this.myaxios("/checkw3/","post",{"public_address":accountAddress,"signature":signature}).then(data =>{( e+ ]* c" M! s4 @* Z

  6. $ d6 i. O4 t$ {. H& Q" g* ?
  7.                         if(data.errcode==0){1 ]6 Z# e3 t# E6 t3 \
  8.                             alert("欢迎:"+data.public_address);/ `, {  x2 K$ h
  9.                             localStorage.setItem("token",data.token);
    $ m5 S3 j8 j4 _' Y' J6 V
  10.                             localStorage.setItem("email",data.public_address);$ j/ G7 K7 Q5 S* w! H: E! C5 Q9 N
  11.                             window.location.href = "/";4 `+ t' e8 C* Y: x( g( h2 S1 W
  12.                         }else{
    ; r  Y7 ?3 }$ Y" R( Z
  13.                             alert("验证失败");5 P! ~/ k: e" z( k" L
  14.                         }
    8 A6 o3 e2 L5 J( I
  15.                  });: n6 `* c, v+ b" T

  16. 4 y6 c. v5 a! Y2 G% v3 c

  17. # y& Q. H2 F  m; ?* M

  18. 0 w, m- o5 V0 T- I! {) I
  19.                 }
复制代码
这里将当前账户的钱包地址和签名传递给后端,如图所示:
& T8 m) J! Q! ^8 ]0 ~) I) U8 {8 r
  A% [4 h/ L. X; A. w1 v" E9 B0 A" H$ V+ v% J9 b

) H8 z2 ]8 a9 _9 p
0 s8 f  G1 N4 ?: Y) D. }9 T 随后创建异步视图方法:
# ]/ M- w6 b" {
  1. from tornado.web import url( t  M  a; m2 J6 t7 z
  2. import tornado.web
    8 `0 |; D/ P1 J5 X
  3. from tornado import httpclient/ f9 Z9 J" A. L! Q
  4. from .base import BaseHandler
    ( N: j% O' D( G* w6 t
  5. from web3.auto import w3
    ' g9 N2 ^4 e3 v, \1 p
  6. from eth_account.messages import defunct_hash_message& F  o& M  _( k  {+ A
  7. import time
      w; S, H% ^; }( t" X

  8. 6 U6 B. _. G+ ~8 P. z" l' e! W8 j
  9. class CheckW3(BaseHandler):  p; |9 [7 W# D& B3 o* y
  10. 9 d3 ^0 Q# R$ @7 R. M; F
  11.     async def post(self):
    $ L* K# K6 I# [9 A% D" d4 e- [
  12. : g, M7 b" _7 c6 e9 E, J7 f7 q) A4 w
  13.         public_address = self.get_argument("public_address")9 S# U1 r- s) S
  14.         signature = self.get_argument("signature")
    ) E, c9 a5 {# P/ t& j* P
  15. 6 d, q. u5 p+ p$ W
  16.         domain = self.request.host4 F, |! c  o* _- V
  17.         if ":" in domain:
    ! L7 u! M6 }" X" X1 o& ~
  18.             domain = domain[0:domain.index(":")]
    8 r2 M% R; H7 Q

  19. 2 Z$ p5 A& w0 W) e* L/ Y
  20.         now = int(time.time())4 `' M8 q4 x1 D- q& g4 M
  21.         sortanow = now-now%600
    2 J% E3 B, X0 I) v0 x$ J1 V- z
  22.    
    + X2 _$ c4 U6 \% V, u
  23.         original_message = 'Signing in to {} at {}'.format(domain,sortanow)
    / b1 V) o$ z1 w; w& l+ S
  24.         print("[+] checking: "+original_message)6 i* ~6 H( |' l# r( I
  25.         message_hash = defunct_hash_message(text=original_message)
    , N; C5 {5 }& c! n# \# i
  26.         signer = w3.eth.account.recoverHash(message_hash, signature=signature)7 `. t+ O4 B$ S+ P8 ~

  27. ; N# B- v7 o# k1 T& x0 W
  28.         if signer == public_address:4 R8 M/ _/ {: q# p! j
  29.             try:6 {8 w$ E* |3 S' V! V. u: @5 C. A+ C
  30.                 user = await self.application.objects.get(User,email=public_address)  A9 b5 X# c- e+ k/ l( y7 k5 x* a
  31.             except Exception as e:
    * }$ C* c9 x9 R, {0 l3 x
  32.                 user = await self.application.objects.create(User,email=public_address,password=create_password("third"),role=1)+ K6 }! i1 b* s. D  V

  33. ; m  X7 b' c2 C8 {5 _# o5 w
  34.             myjwt = MyJwt()
    4 G/ d, u" w& D7 m3 Q* D% d
  35.             token = myjwt.encode({"id":user.id})" a, B* p# ?/ `2 P2 N! Y
  36.             self.finish({"msg":"ok","errcode":0,"public_address":public_address,"token":token})8 o, E; |+ b$ _5 j8 `) k; ^
  37.         else:- b: p4 {. q$ X4 ?( J# _, [3 v
  38.             self.finish({"msg":"could not authenticate signature","errcode":1})
复制代码
8 S; [% y  u: ?6 N4 X/ [" }, ?
   这里通过recoverHash方法对签名进行反编译操作,如果反编译后的钱包地址和前端传过来的钱包地址吻合,那么说明当前账户的身份验证通过:. m/ [# [0 \) T6 P# T4 t+ Y- e

. o0 B) l6 x# [  a: s( o  x3 |% b; D" C* q; }# i* H
- J; J% x$ ]; M3 }  z
8 m/ c0 ]8 K0 ?( m& \+ M& L' M" B
当验签通过之后,利用钱包地址在后台创建账号,随后将钱包地址、token等信息返回给前端,前端将其保存在stroage中即可。" r8 J  d: g: I" O4 K

7 F6 m2 j4 V! z' C1 }% s& H. Z+ Q    结语
3 c/ B8 L. v/ Z; _. @
) s7 B# v5 y+ X& U7 D- q2 I    没错,将至已至,未来已来,是时候将Web3.0区块链技术融入产品了,虽然有些固有的思维方式依然在人们的脑海挥之不去,但世界却在时不我待地变化着,正是:青山遮不住,毕竟东流去!项目开源在https://github.com/zcxey2911/Tornado6_Vuejs3_Edu
- \5 L" F* x1 a& @( I7 _
2 c! [  ~3 I# I$ d, T1 `! `
# Q& h! p2 t( a! z4 y* Q
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

江左没浪 小学生
  • 粉丝

    18

  • 关注

    0

  • 主题

    7