4 B1 z8 @- l( O3 m
当我们的用户厌倦了传统的电子邮件/密码注册流程时,他们会选择Google、GitHub等社交登录方式,这种方式虽然节约了用户的时间,但登录信息也会被第三方平台记录,也就是说我们用平台账号做了什么,平台都会一目了然,甚至还会对我们的行为进行分析、画像。那么有没有一种登录方式,它的所有信息都只保存在客户端和后端,并不牵扯三方平台授权,最大化的保证用户隐私呢?Web3.0给我们提供了一种选择:MetaMask。) a. }( L8 e' x" h0 j0 Q
; V& x$ \5 x( O
MetaMask
MetaMask是用于与以太坊区块链进行交互的软件加密货币钱包。MetaMask允许用户通过浏览器插件或移动应用程序访问其以太坊钱包,然后可以使用这些扩展程序与去中心化应用程序进行交互。当然了,首先需要拥有一个MetaMask钱包,进入https://chrome.google.com/websto ... oehlefnkodbefgpgknn 7 {" S% r2 h6 f" H0 c
安装metamask浏览器插件:
% u U2 j7 Y) p
随后点开插件,创建账号,记录密码、钱包地址、以及助记词等信息。
安装好插件之后,我们就可以利用这个插件和网站应用做交互了。
钱包登录流程/ t6 V x3 S: X1 M
登录逻辑和传统的三方登录还是有差异的,传统三方登录一般是首先跳转三方平台进行授权操作,随后三方平台将code验证码返回给登录平台,登录平台再使用code请求三方平台换取token,再通过token请求用户账号信息,而钱包登录则是先在前端通过Web3.js浏览器插件中保存的私钥对钱包地址进行签名操作,随后将签名和钱包地址发送到后端,后端利用Web3的库用同样的算法进行验签操作,如果验签通过,则将钱包信息存入token,并且返回给前端。9 Z4 O8 a' d! }' J. N
. W& x0 f5 F+ K7 ^3 W1 P
前端签名操作, 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
- <script src="{{ static_url("js/ethers-v4.min.js") }}"></script>3 w% T+ E6 M- d a4 K' O7 m
- <script src="{{ static_url("js/axios.js") }}"></script>
- <script src="{{ static_url("js/vue.js") }}"></script>
) 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 |
- sign_w3:function(){" z) M' L7 h; R) ~4 N
- ) ^$ T, i5 D' ?4 H" J+ n
- that = this;
- ethereum.enable().then(function () {" ^: S* B) ~' h! t; v5 C! z+ Q
- 2 c9 E, E3 ?; m& A
- this.provider = new ethers.providers.Web3Provider(web3.currentProvider);
- this.provider.getNetwork().then(function (result) {
- if (result['chainId'] != 1) {
- console.log("Switch to Mainnet!")
- 0 b) t5 g& v% k9 t
- } else { // okay, confirmed we're on mainnet, e ^* ?: B: O2 \4 C, f, H* D* t4 M
- 5 T, d) e: {# _- D
- this.provider.listAccounts().then(function (result) {0 q+ `* V. |1 E/ `' `1 I c' k. v
- console.log(result);2 t j* Y, B; T. \1 K5 T/ Z. P: |
- this.accountAddress = result[0]; // figure out the user's Eth address
- this.provider.getBalance(String(result[0])).then(function (balance) {
- var myBalance = (balance / ethers.constants.WeiPerEther).toFixed(4);
- console.log("Your Balance: " + myBalance);
- });! X% H& f5 A! @! q. X3 K6 ]. W
- + u. v$ i2 }2 p0 p% B/ L$ E
- // get a signer object so we can do things that need signing2 E1 y# z; O( _. z }+ p
- this.signer = provider.getSigner();
- var rightnow = (Date.now()/1000).toFixed(0)
- var sortanow = rightnow-(rightnow%600)& x) Y5 n1 K, l
- this.signer.signMessage("Signing in to "+document.domain+" at "+sortanow, accountAddress, "test password!")
- .then((signature) => { that.handleAuth(accountAddress,signature);9 c# c& ]- {4 w3 X* H9 f/ }
- });2 d- b1 f$ g; b9 i( T
- console.log(this.signer);
- })2 P4 M9 e$ j+ d# @3 P W
- }" |8 G a4 @7 \1 z# u# B/ {
- })
- })
- },
- //检查验证
- handleAuth:function(accountAddress, signature){
- ! K& e! |( y x
- this.myaxios("/checkw3/","post",{"public_address":accountAddress,"signature":signature}).then(data =>{
- " S% Q. N+ ~! l
- if(data.errcode==0){
- alert("欢迎:"+data.public_address);
- localStorage.setItem("token",data.token);
- localStorage.setItem("email",data.public_address);
- window.location.href = "/";
- }else{
- alert("验证失败");
- }/ P+ I; H4 i% C' `3 _
- });
- }
! 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
- from tornado.web import url
- import tornado.web
- from tornado import httpclient# r2 Z5 a: U3 ^: J
- from .base import BaseHandler! E. Q% R! w5 C+ P
- from web3.auto import w3' a; n8 y& }8 b" B
- from eth_account.messages import defunct_hash_message
- import time+ W9 U4 G6 k3 p" q, y# f' J# p
- class CheckW3(BaseHandler):
- x/ Q+ _% u( t1 P, D+ a* V
- async def post(self):
- $ d6 G3 f7 N+ K8 ~
- public_address = self.get_argument("public_address"). y' E% m7 p, `1 X! d
- signature = self.get_argument("signature")
- , T. }# N' o0 T, z* n) f7 b
- domain = self.request.host6 i! r G" U& k+ `- G
- if ":" in domain:
- domain = domain[0:domain.index(":")]6 Y* ` G3 I$ K) T/ P
- now = int(time.time())3 m6 l# M2 ? D: \9 x! v$ ]
- sortanow = now-now%600" s- {7 z( k) q3 \5 g
- & D1 g- K3 x. T- B3 d1 y# X
- original_message = 'Signing in to {} at {}'.format(domain,sortanow)
- print("[+] checking: "+original_message)' C5 i0 E! \# n; \# p1 \
- message_hash = defunct_hash_message(text=original_message) M2 {3 N; M W$ K! J* N/ D4 j
- signer = w3.eth.account.recoverHash(message_hash, signature=signature)
- ! s( }9 a5 R& L9 V* G
- if signer == public_address:
- try:
- user = await self.application.objects.get(User,email=public_address)3 Z: ~1 j* K3 i+ _1 F
- except Exception as e:3 w9 a7 g# R$ \ t3 L) {- {
- user = await self.application.objects.create(User,email=public_address,password=create_password("third"),role=1); P T; u1 S! y1 N
- ( U) q; R/ v' e( r, p$ [4 z
- myjwt = MyJwt()
- token = myjwt.encode({"id":user.id}): {0 }# n& V/ A6 ]; ?# c
- self.finish({"msg":"ok","errcode":0,"public_address":public_address,"token":token})
- else:4 s& O+ a" U. e
- self.finish({"msg":"could not authenticate signature","errcode":1})
这里通过recoverHash方法对签名进行反编译操作,如果反编译后的钱包地址和前端传过来的钱包地址吻合,那么说明当前账户的身份验证通过:
当验签通过之后,利用钱包地址在后台创建账号,随后将钱包地址、token等信息返回给前端,前端将其保存在stroage中即可。
结语
没错,将至已至,未来已来,是时候将Web3.0区块链技术融入产品了,虽然有些固有的思维方式依然在人们的脑海挥之不去,但世界却在时不我待地变化着,正是:青山遮不住,毕竟东流去!项目开源在https://github.com/zcxey2911/Tornado6_Vuejs3_Edu
" H! [* B( n* r7 v