metaMask login
This commit is contained in:
parent
5fce327ce6
commit
a32a4e4e39
@ -43,6 +43,7 @@
|
||||
"vue-splitpane": "1.0.4",
|
||||
"vuedraggable": "2.20.0",
|
||||
"vuex": "3.1.0",
|
||||
"web3": "^1.7.4",
|
||||
"xlsx": "0.14.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -7,6 +7,13 @@ export function login(data) {
|
||||
data
|
||||
})
|
||||
}
|
||||
export function metamaskLogin(data) {
|
||||
return request({
|
||||
url: '/user/metamask-login',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function getInfo(token) {
|
||||
return request({
|
||||
@ -21,3 +28,11 @@ export function logout() {
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function getNonce(account) {
|
||||
return request({
|
||||
url: '/user/getNonce?account=' + account,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
|
1
src/icons/svg/MetaMask.svg
Normal file
1
src/icons/svg/MetaMask.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1718869327969" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5949" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M517.77536 972.8c133.98016-30.19776 211.70176-70.42048 301.2608-156.3136 29.32736-28.11904 174.04928-63.68256 190.4128-100.83328 23.72608-53.8624-58.2144-115.72224-58.2144-178.40128 0-240.54784-194.06848-435.5584-433.4592-435.5584-239.38048 0-433.44896 195.01056-433.44896 435.5584 0 68.21888-86.13888 124.14976-58.3168 181.62688 15.28832 31.56992 164.1472 73.216 189.51168 97.60768C305.08032 902.68672 383.55968 942.60224 517.77536 972.8z" fill="#FFD797" p-id="5950"></path><path d="M908.77952 65.5872c-0.88064 1.40288 79.0528 276.7872 32.68608 379.32032a439.0912 439.0912 0 0 1 9.76896 92.34432c0 62.6688 81.94048 124.54912 58.2144 178.40128-1.71008 3.8912-4.88448 7.74144-9.216 11.55072-146.59584-39.44448-297.6768-4.31104-453.25312 105.41056l-5.64224 4.00384H494.592C336.24064 723.2 182.55872 686.92992 33.536 727.78752c-3.54304-3.0208-6.11328-5.9904-7.5264-8.9088-27.82208-57.47712 58.3168-113.408 58.3168-181.62688 0-27.4944 2.53952-54.39488 7.38304-80.47616-59.62752-90.97216 27.136-389.7344 26.22464-391.18848 81.39776-14.41792 159.06816 8.76544 233.03168 69.5296a430.40768 430.40768 0 0 1 166.8096-33.42336 430.44864 430.44864 0 0 1 160.94208 31.01696C751.77984 73.728 828.4672 51.36384 908.77952 65.5872z" fill="#FF6F24" p-id="5951"></path><path d="M283.1872 315.51488c31.10912-104.9088-23.97184-186.24512-165.25312-244.0192 1.024 1.65888-77.7216 340.93056 28.89728 383.11936-3.51232 2.92864 41.94304-43.42784 136.35584-139.10016z m461.48608 0c-31.10912-104.9088 23.97184-186.24512 165.24288-244.0192-1.024 1.65888 77.7216 340.93056-28.89728 383.11936 3.52256 2.92864-41.9328-43.42784-136.3456-139.10016z" fill="#922101" opacity=".574" p-id="5952"></path><path d="M647.69024 629.00224c-0.21504-60.29312 44.56448-83.94752 134.3488-70.95296-2.78528 3.072 6.78912 44.93312-40.51968 69.15072-11.264 5.76512-42.53696 6.36928-93.82912 1.80224z m-251.46368 0c0.22528-60.29312-44.55424-83.94752-134.33856-70.95296 2.78528 3.072-6.79936 44.93312 40.50944 69.15072 11.264 5.76512 42.53696 6.36928 93.82912 1.80224z" fill="#350000" p-id="5953"></path><path d="M743.10656 565.72928l0.04096 0.1536c0.78848 3.42016 1.20832 6.99392 1.20832 10.6496 0 23.4496-17.14176 42.82368-39.424 46.00832-3.42016 0.1536-7.2192 0.21504-11.39712 0.18432a45.93664 45.93664 0 0 1-36.7104-26.61376c10.25024-24.832 39.0144-34.95936 86.28224-30.38208z m-459.84768 0l-0.04096 0.1536a47.13472 47.13472 0 0 0-1.20832 10.6496c0 23.4496 17.14176 42.82368 39.424 46.00832 3.40992 0.1536 7.2192 0.21504 11.39712 0.18432a45.93664 45.93664 0 0 0 36.7104-26.61376c-10.26048-24.832-39.0144-34.95936-86.28224-30.38208z" fill="#923320" p-id="5954"></path><path d="M328.6528 574.72c-4.12672 10.24-6.25664 17.43872-6.38976 21.58592-0.23552 6.89152 1.8944 12.5952 6.38976 17.1008 0.768 0.54272 6.44096-5.30432 6.144-17.87904-0.1024-3.72736-2.1504-10.6496-6.144-20.80768z m372.72576 0c-4.12672 10.24-6.2464 17.43872-6.38976 21.58592-0.22528 6.89152 1.90464 12.5952 6.38976 17.1008 0.77824 0.54272 6.44096-5.30432 6.144-17.87904-0.09216-3.72736-2.14016-10.6496-6.144-20.80768z" fill="#FFFFFF" opacity=".632" p-id="5955"></path><path d="M520.42752 863.8464c37.24288 0 67.4304-27.81184 67.4304-62.1056 0-34.304-134.8608-34.304-134.8608 0s30.19776 62.1056 67.4304 62.1056z" fill="#040C12" p-id="5956"></path><path d="M520.15104 152.02304c8.86784 146.97472 40.57088 238.83776 95.10912 275.57888l2.19136 1.4336-0.24576 0.07168c-6.42048 2.53952-71.46496 73.5744-96.80896 138.2912-0.0512 0.08192-0.09216 0-0.12288-0.26624-0.04096 0.256-0.08192 0.34816-0.12288 0.26624-25.35424-64.7168-90.38848-135.75168-96.8192-138.2912l-0.24576-0.07168 2.2016-1.4336c53.71904-36.1984 85.1968-125.87008 94.45376-269.03552l0.4096-6.5536z" fill="#C74D22" p-id="5957"></path><path d="M735.15008 721.8688c49.55136 0 89.72288-17.17248 89.72288-38.3488s-40.17152-38.3488-89.72288-38.3488c-49.5616 0-89.72288 17.17248-89.72288 38.3488s40.17152 38.3488 89.72288 38.3488z m-443.89376 0c49.5616 0 89.72288-17.17248 89.72288-38.3488s-40.17152-38.3488-89.72288-38.3488-89.72288 17.17248-89.72288 38.3488 40.17152 38.3488 89.72288 38.3488z" fill="#C53028" fill-opacity=".3" p-id="5958"></path></svg>
|
After Width: | Height: | Size: 4.3 KiB |
@ -7,6 +7,7 @@ const getters = {
|
||||
cachedViews: state => state.tagsView.cachedViews,
|
||||
token: state => state.user.token,
|
||||
name: state => state.user.name,
|
||||
nonce: state => state.user.nonce,
|
||||
introduction: state => state.user.introduction,
|
||||
roles: state => state.user.roles,
|
||||
permission_routes: state => state.permission.routes,
|
||||
|
@ -6,7 +6,8 @@ const state = {
|
||||
token: getToken(),
|
||||
name: '',
|
||||
introduction: '',
|
||||
roles: []
|
||||
roles: [],
|
||||
nonce: ''
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
@ -21,6 +22,9 @@ const mutations = {
|
||||
},
|
||||
SET_ROLES: (state, roles) => {
|
||||
state.roles = roles
|
||||
},
|
||||
SET_NONCE: (state, nonce) => {
|
||||
state.nonce = nonce
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,6 +101,13 @@ const actions = {
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
// get nonce
|
||||
getNonce({ commit }, nonce) {
|
||||
return new Promise(resolve => {
|
||||
commit('SET_NONCE', nonce)
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
|
||||
// dynamically modify permissions
|
||||
async changeRoles({ commit, dispatch }, role) {
|
||||
|
@ -1,22 +1,58 @@
|
||||
<template>
|
||||
<div class="social-signup-container">
|
||||
<div class="sign-btn" @click="wechatHandleClick('wechat')">
|
||||
<span class="wx-svg-container"><svg-icon icon-class="wechat" class="icon" /></span>
|
||||
WeChat
|
||||
</div>
|
||||
<div class="sign-btn" @click="tencentHandleClick('tencent')">
|
||||
<span class="qq-svg-container"><svg-icon icon-class="qq" class="icon" /></span>
|
||||
QQ
|
||||
<!-- <div class="sign-btn" @click="wechatHandleClick('wechat')">-->
|
||||
<!-- <span class="wx-svg-container"><svg-icon icon-class="wechat" class="icon" /></span>-->
|
||||
<!-- WeChat-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="sign-btn" @click="tencentHandleClick('tencent')">-->
|
||||
<!-- <span class="qq-svg-container"><svg-icon icon-class="qq" class="icon" /></span>-->
|
||||
<!-- QQ-->
|
||||
<!-- </div>-->
|
||||
<div class="sign-btn" @click="marketHandleClick('MetaMask')">
|
||||
<span class="qq-svg-container"><svg-icon icon-class="MetaMask" class="icon" /></span>
|
||||
Market
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import openWindow from '@/utils/open-window'
|
||||
import Web3 from 'web3'
|
||||
import { getNonce, metamaskLogin } from '@/api/user'
|
||||
|
||||
export default {
|
||||
name: 'SocialSignin',
|
||||
data() {
|
||||
return {
|
||||
provider: '',
|
||||
web3: '',
|
||||
chainId: '',
|
||||
account: '',
|
||||
redirect: undefined,
|
||||
otherQuery: {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route: {
|
||||
handler: function(route) {
|
||||
const query = route.query
|
||||
if (query) {
|
||||
this.redirect = query.redirect
|
||||
this.otherQuery = this.getOtherQuery(query)
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getOtherQuery(query) {
|
||||
return Object.keys(query).reduce((acc, cur) => {
|
||||
if (cur !== 'redirect') {
|
||||
acc[cur] = query[cur]
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
},
|
||||
wechatHandleClick(thirdpart) {
|
||||
alert('ok')
|
||||
// this.$store.commit('SET_AUTH_TYPE', thirdpart)
|
||||
@ -32,6 +68,131 @@ export default {
|
||||
// const redirect_uri = encodeURIComponent('xxx/redirect?redirect=' + window.location.origin + '/auth-redirect')
|
||||
// const url = 'https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=' + client_id + '&redirect_uri=' + redirect_uri
|
||||
// openWindow(url, thirdpart, 540, 540)
|
||||
},
|
||||
async marketHandleClick(thirdpart) {
|
||||
if (!this.hasMetamask()) {
|
||||
this.$message({
|
||||
message: '请先安装MetaMask插件',
|
||||
type: 'error',
|
||||
duration: 1200
|
||||
})
|
||||
return
|
||||
}
|
||||
this.provider = await this.connectMetaMask()
|
||||
if (!this.provider) {
|
||||
return
|
||||
}
|
||||
this.web3 = new Web3(this.provider)
|
||||
this.chainId = await this.web3.eth.getChainId()
|
||||
const accounts = await this.web3.eth.getAccounts()
|
||||
if (accounts && accounts.length > 0) {
|
||||
this.account = accounts[0]
|
||||
}
|
||||
await getNonce(this.account).then(response => {
|
||||
if (response.code === 0) {
|
||||
this.$store.dispatch('user/getNonce', response.data)
|
||||
} else {
|
||||
this.$message({
|
||||
message: response.message,
|
||||
type: 'error',
|
||||
duration: 1200
|
||||
})
|
||||
return
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.log('Api getNonce Error:' + err)
|
||||
})
|
||||
await this.metaMaskLogin()
|
||||
},
|
||||
hasMetamask() {
|
||||
if (typeof window.ethereum !== 'undefined') {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
},
|
||||
connectMetaMask() {
|
||||
var provider = window.ethereum
|
||||
try {
|
||||
provider.request({ method: 'eth_requestAccounts' })
|
||||
} catch (error) {
|
||||
if (error.code === -32002) {
|
||||
throw new Error('MeatMask not login, Open MeatMask and login first')
|
||||
} else {
|
||||
throw new Error('User Rejected')
|
||||
}
|
||||
}
|
||||
return provider
|
||||
},
|
||||
async metaMaskLogin() {
|
||||
const account = this.account
|
||||
const net_id = this.chainId
|
||||
const nonce = this.$store.getters.nonce
|
||||
const tips = 'This signature is only used for verify your account'
|
||||
const signMsg = {
|
||||
tips,
|
||||
nonce
|
||||
}
|
||||
const EIP721_DOMAIN_DATA = [
|
||||
{ name: 'name', type: 'string' },
|
||||
{ name: 'version', type: 'string' }
|
||||
]
|
||||
|
||||
const signObj = {
|
||||
types: {
|
||||
EIP712Domain: EIP721_DOMAIN_DATA,
|
||||
set: [
|
||||
{ name: 'tips', type: 'string' },
|
||||
{ name: 'nonce', type: 'string' }
|
||||
]
|
||||
},
|
||||
primaryType: 'set',
|
||||
domain: {
|
||||
name: 'Auth',
|
||||
version: '1'
|
||||
},
|
||||
message: signMsg
|
||||
}
|
||||
const signature = await this.signData(signObj, account)
|
||||
const authData = {
|
||||
account,
|
||||
nonce,
|
||||
signature,
|
||||
tips,
|
||||
net_id
|
||||
}
|
||||
metamaskLogin(authData).then(response => {
|
||||
this.$router.push({ path: this.redirect || '/', query: this.otherQuery })
|
||||
console.log(response)
|
||||
}).catch((err) => {
|
||||
console.log('Api getNonce Error:' + err)
|
||||
})
|
||||
},
|
||||
async signData(signObj, signer) {
|
||||
const msgParams = JSON.stringify(signObj)
|
||||
const from = signer
|
||||
const params = [from, msgParams]
|
||||
const result = await this.sendCmd(
|
||||
'eth_signTypedData_v4',
|
||||
params,
|
||||
from
|
||||
)
|
||||
return result.result
|
||||
},
|
||||
async sendCmd(method, params, from) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.web3.currentProvider.sendAsync({
|
||||
method,
|
||||
params,
|
||||
from
|
||||
}, async function(err, result) {
|
||||
if (err) {
|
||||
reject && reject(err)
|
||||
return
|
||||
}
|
||||
resolve && resolve(result)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,16 +45,25 @@
|
||||
</el-form-item>
|
||||
</el-tooltip>
|
||||
<el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">Login</el-button>
|
||||
<div style="position:relative;margin-top: 30px">
|
||||
<el-button class="thirdparty-button" type="primary" @click="showDialog=true">
|
||||
Or connect with
|
||||
</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
|
||||
<el-dialog title="Or connect with" :visible.sync="showDialog">
|
||||
<social-sign />
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { validUsername } from '@/utils/validate'
|
||||
import SocialSign from './components/SocialSignin'
|
||||
|
||||
export default {
|
||||
name: 'Login',
|
||||
components: {},
|
||||
components: { SocialSign },
|
||||
data() {
|
||||
const validateUsername = (rule, value, callback) => {
|
||||
if (!validUsername(value)) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user