Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
    今天去中心化身份逐渐被广泛采用。用户的部分在线活动在链上是公开的,可通过加密钱包搜索到,用户在链上创造、贡献、赚取和拥有的东西,都反映了他们的喜好,也逐渐积累成该用户的身份和标识。0 y) }6 f( H2 j2 h( Z- h$ d+ ]

6 F) Q  n$ K# }4 [+ {/ `    当我们的用户厌倦了传统的电子邮件/密码注册流程时,他们会选择Google、GitHub等社交登录方式,这种方式虽然节约了用户的时间,但登录信息也会被第三方平台记录,也就是说我们用平台账号做了什么,平台都会一目了然,甚至还会对我们的行为进行分析、画像。那么有没有一种登录方式,它的所有信息都只保存在客户端和后端,并不牵扯三方平台授权,最大化的保证用户隐私呢?Web3.0给我们提供了一种选择:MetaMask。
3 {: {# p$ `5 a3 ]5 w4 h3 F2 P
4 |  m9 Q; \* Q4 ^. W    MetaMask& U5 ]8 m9 K! C; c# v$ I
    MetaMask是用于与以太坊区块链进行交互的软件加密货币钱包。MetaMask允许用户通过浏览器插件或移动应用程序访问其以太坊钱包,然后可以使用这些扩展程序与去中心化应用程序进行交互。当然了,首先需要拥有一个MetaMask钱包,进入https://chrome.google.com/websto ... oehlefnkodbefgpgknn
- b. D& L+ L' Z5 w4 o8 J; A" i' F
/ `( s: [- i  h$ z" ]    安装metamask浏览器插件:
* T) @( R1 i' T% Q
8 H8 g% R1 H9 n4 Z: p# G
6 R: p: B1 s$ i% f- L  随后点开插件,创建账号,记录密码、钱包地址、以及助记词等信息。
( J3 L; W. D& [0 v4 O0 a5 {, B, j
8 c* r  N9 B3 U8 w& ^4 V    安装好插件之后,我们就可以利用这个插件和网站应用做交互了。
$ l4 y7 S( e  W. U$ l& d
+ w% A: M; g: t1 s, U; [& l0 O    钱包登录流程
: M( w% z0 ]9 q7 D" q    登录逻辑和传统的三方登录还是有差异的,传统三方登录一般是首先跳转三方平台进行授权操作,随后三方平台将code验证码返回给登录平台,登录平台再使用code请求三方平台换取token,再通过token请求用户账号信息,而钱包登录则是先在前端通过Web3.js浏览器插件中保存的私钥对钱包地址进行签名操作,随后将签名和钱包地址发送到后端,后端利用Web3的库用同样的算法进行验签操作,如果验签通过,则将钱包信息存入token,并且返回给前端。7 h2 v: P& i5 \+ h$ |/ ~1 W% ^! R
0 ]7 `1 o6 `: y' A# Q

* m& c2 B7 \$ H0 f( U
* t# y4 W  k) U9 ~7 u, s* W  M前端签名操作
, ?. N; E" X6 w# p* }4 L- E% ?/ o- ^    首先需要下载前端的Web3.0操作库,https://docs.ethers.io/v4/,随后集成到登录页面中:& Z( [; }) P( g& v

% v! ~4 y$ M* ~  ?5 i) h! h5 u& \" y
2 P' \: x) G( `' P3 b8 K/ z
  1. <script src="{{ static_url("js/ethers-v4.min.js") }}"></script>$ E: g/ R$ C, o1 M! Y& `
  2. <script src="{{ static_url("js/axios.js") }}"></script>1 z' e. E! J! \0 ~* F7 B
  3. <script src="{{ static_url("js/vue.js") }}"></script>
复制代码
" d8 {0 d; `6 a( r% G+ r

& o; \4 T# c/ C$ y5 }, e6 ~! R  l8 M
这里我们基于Vue.js配合Axios使用。* \- @2 Q/ l: W1 a. x

4 {5 R" P: v% \/ b/ }% J    接着声明登录激活方法:
, U0 c* L4 K: p6 v0 ?  \, m9 ?5 D) g5 E6 A- X
  1. sign_w3:function(){
    4 ~  u/ X1 J4 ~- h: T) a! Y
  2. / Y- C! w0 \( ~0 S7 {0 n* H9 ^
  3.                     that = this;
      j8 c; R! [9 v+ ~8 D
  4.                     ethereum.enable().then(function () {4 ~% l9 z% |0 b3 k/ L

  5. & [$ ~9 H' F2 ^9 }+ E7 h* L' L
  6.     this.provider = new ethers.providers.Web3Provider(web3.currentProvider);
    % z, ]4 e2 }9 L6 O

  7. 3 F; n5 \/ w, G: d! q  B4 o
  8.     this.provider.getNetwork().then(function (result) {6 K, l. l6 R$ e1 [9 v6 S
  9.         if (result['chainId'] != 1) {8 A* {" J' C2 T  F; O
  10. 5 X! O9 [( ?% H( q1 m3 ]6 s
  11.             console.log("Switch to Mainnet!")0 W( ^; P; y& k! f% E  M0 f

  12. 8 [- K2 {5 a6 T2 k2 e
  13.         } else { // okay, confirmed we're on mainnet
    7 e9 A# M9 @8 H0 n& N
  14. 7 |6 U+ B! L" ]" d" o
  15.             this.provider.listAccounts().then(function (result) {
    / y, i7 j6 Q" o# n; Z3 O6 o
  16.                 console.log(result);
    4 j# B: ^/ I& E% h
  17.                 this.accountAddress = result[0]; // figure out the user's Eth address
    1 B: s. T  f1 d6 |2 m8 `" @: X
  18.                 this.provider.getBalance(String(result[0])).then(function (balance) {
      \8 F; W& m' O8 |9 K
  19.                     var myBalance = (balance / ethers.constants.WeiPerEther).toFixed(4);. I' |' ~$ l! G& l
  20.                     console.log("Your Balance: " + myBalance);
    ( Z/ M; S' A  N% d: D  o+ K
  21.                 });
    " K& D; X) s; z# ?
  22. ( X* R7 B; V6 ~" m
  23.                 // get a signer object so we can do things that need signing
    9 Y- b& p& m7 ^) o( p2 d8 w
  24.                 this.signer = provider.getSigner();
      b6 u0 E( J: y% W* I

  25. . [$ R4 Q9 z# ~& l# @
  26.                 var rightnow = (Date.now()/1000).toFixed(0)
    * I% M; \6 g( g% G& c# \; q% b! ]$ G% S
  27.         var sortanow = rightnow-(rightnow%600)
    4 A4 N8 b+ o) i/ v8 h

  28. & E5 E0 Z  q0 B8 }
  29.         this.signer.signMessage("Signing in to "+document.domain+" at "+sortanow, accountAddress, "test password!")
    # v- |0 G2 }) {3 i. n/ J- v- ]
  30.             .then((signature) => {               that.handleAuth(accountAddress,signature);& c/ J& b  p; ?( G; W
  31.             });
    9 F0 L% @% {+ Y% e3 G

  32. 9 c( N0 {9 l# _3 |8 s
  33.                 console.log(this.signer);
    + G+ k4 B( Y, z
  34.             })
    " t4 ^, z6 R+ T$ a
  35.         }4 S! ^6 q- T  J3 p$ J+ n: O
  36.     })
    % J) G' C# V  C2 f2 h
  37. })
    . {$ P' |0 m9 u: n$ p

  38. " g7 p! X) U) i* X
  39.                 },
复制代码
通过使用signMessage方法返回签名,这里加签过程中使用基于时间戳的随机数防止未签名,当前端签名生成好之后,立刻异步请求后台接口:
' q& h) N+ r! ~/ R+ u: I0 @5 y1 G3 }! h; n
  1. //检查验证+ X; @1 o' D5 j
  2.                 handleAuth:function(accountAddress, signature){  o' a& b6 v+ _
  3. 0 w5 D/ v& Z6 q) U) e

  4. * u4 A  W% S/ m2 v' ^
  5.                     this.myaxios("/checkw3/","post",{"public_address":accountAddress,"signature":signature}).then(data =>{$ i6 T% C" {% M; z8 g0 \
  6. " O" |+ C3 U( D# }6 [" ~! g
  7.                         if(data.errcode==0){
    4 m0 Y/ H1 Z9 W9 a7 U, O3 x( o; C
  8.                             alert("欢迎:"+data.public_address);. x7 h8 S. _# \9 [
  9.                             localStorage.setItem("token",data.token);! W2 {1 z$ K. W/ V: e0 a
  10.                             localStorage.setItem("email",data.public_address);' M5 f# C2 e8 `& K
  11.                             window.location.href = "/";4 D  {" K* n7 z& Z, |4 o
  12.                         }else{
    ! |% ^7 f- F" h  d9 X  g5 M. _8 T) n
  13.                             alert("验证失败");
    4 t) ?6 H, g( x' |
  14.                         }
    : C$ b- l' z. V6 Z8 Q- f$ Q
  15.                  });
    ) B# {, J7 B5 k0 X
  16. 2 B. U( p7 R! n& g3 C  q

  17. 9 {7 \2 @" T7 V6 v' |; X
  18. 4 q, `: g: J  |( E8 v1 ?+ B
  19.                 }
复制代码
这里将当前账户的钱包地址和签名传递给后端,如图所示:7 v' M0 f! p) U* N' C
8 c5 ?4 \6 V( p' d$ |: w& o' X! p
2 B6 x  x) J1 s& I

( o7 j' r+ ^# K+ ^7 O
5 k" B% _3 b( }. Y 随后创建异步视图方法:8 ]% D: E& ]" O3 j, X
  1. from tornado.web import url3 X* k. a5 I/ p% X& }# F
  2. import tornado.web
    # F. _5 e, \' [- k" s
  3. from tornado import httpclient: I4 g) x* _7 u8 f) J! t: M' O
  4. from .base import BaseHandler
    8 h% _8 L; }# f& H( t* H2 |
  5. from web3.auto import w3
    + S9 h0 M' _- ]( \
  6. from eth_account.messages import defunct_hash_message
    ' S5 Y$ ?' j: O/ K* a) [+ ?/ I1 c
  7. import time# k/ q$ z; \" S9 N! Z  ^4 J' [

  8. 2 Y& |# U2 C. }, B
  9. class CheckW3(BaseHandler):0 ^  h) V" [3 S1 w
  10. ) L' t( j# _; G  Y" M/ U* k
  11.     async def post(self):
    ) l4 y) X. K2 o5 j( W

  12. " d3 B  N7 P0 P" i/ s
  13.         public_address = self.get_argument("public_address")
    2 c( o/ k" ]* z' M$ s
  14.         signature = self.get_argument("signature"), G" {% Y9 H; Q0 g
  15. , {! L2 L$ u; y. C3 v
  16.         domain = self.request.host
    " n+ c" h* I( c
  17.         if ":" in domain:
    7 `) a9 B2 Z) n* y3 B' @+ M! ~
  18.             domain = domain[0:domain.index(":")]0 r) ~6 X! F# [5 [5 x7 F  Q& ^' E% h

  19. 4 r9 V8 A9 c! `. y/ T3 {9 I: ?
  20.         now = int(time.time())
    / R% D7 S* b6 [2 U0 g  V
  21.         sortanow = now-now%600
    1 c8 ^) |/ I1 ]# ^3 h6 ]. P
  22.    
    1 X2 a8 f: O# m
  23.         original_message = 'Signing in to {} at {}'.format(domain,sortanow)
    . L8 y0 V$ j' a5 W
  24.         print("[+] checking: "+original_message)) X( _3 ^; M, }! W% X1 E
  25.         message_hash = defunct_hash_message(text=original_message): Z  e; j+ D9 N+ V  o7 u
  26.         signer = w3.eth.account.recoverHash(message_hash, signature=signature)
    . s' e, \8 L7 L  R4 I

  27. % z7 @; K! O+ ^4 M
  28.         if signer == public_address:  ~# H) Y% G; v' U3 r
  29.             try:
    3 n8 _/ i, I4 I5 f( ~& r
  30.                 user = await self.application.objects.get(User,email=public_address)
    % w% B3 ~5 e5 `6 M
  31.             except Exception as e:0 L5 G6 S+ L$ m( x& r% _' k
  32.                 user = await self.application.objects.create(User,email=public_address,password=create_password("third"),role=1)9 B; @" z# u5 ^* n, s: c! g9 F) U

  33. 8 q+ u2 x3 u3 d0 _1 E+ J" Q4 |
  34.             myjwt = MyJwt()
    4 l9 B1 H% S$ t, l
  35.             token = myjwt.encode({"id":user.id})
    . U: r3 ^; Q; Y0 v! n2 s7 z" V
  36.             self.finish({"msg":"ok","errcode":0,"public_address":public_address,"token":token})) I: I$ _6 I3 V2 l' v% t
  37.         else:5 P! ?2 K" L3 T. e6 [9 O  R7 k
  38.             self.finish({"msg":"could not authenticate signature","errcode":1})
复制代码

% C; b4 D  H7 d/ }   这里通过recoverHash方法对签名进行反编译操作,如果反编译后的钱包地址和前端传过来的钱包地址吻合,那么说明当前账户的身份验证通过:2 ~, ?3 R( ?6 w1 ^" C) A; _; W

* f# o, [- F1 P4 g. o1 C* S5 b; X: G; z8 i$ ?' ]5 u
2 f$ }1 j( V% F9 @: E9 a

  n2 x( B4 s+ |; h 当验签通过之后,利用钱包地址在后台创建账号,随后将钱包地址、token等信息返回给前端,前端将其保存在stroage中即可。
: L. |& e6 f7 l- j0 E* [4 k$ i" b7 ~- F
    结语
0 K* @$ z1 ~! i( }7 q& T0 K# l
" }1 i1 t) L* d    没错,将至已至,未来已来,是时候将Web3.0区块链技术融入产品了,虽然有些固有的思维方式依然在人们的脑海挥之不去,但世界却在时不我待地变化着,正是:青山遮不住,毕竟东流去!项目开源在https://github.com/zcxey2911/Tornado6_Vuejs3_Edu % _, u8 X# b$ D& ?
4 ]: ]$ X, p0 ~5 @

) {9 A( p& ^: H# @7 a
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

江左没浪 小学生
  • 粉丝

    18

  • 关注

    0

  • 主题

    7