新增:登录验证签功能
This commit is contained in:
parent
3e0bf253be
commit
e882c74449
2018
package-lock.json
generated
2018
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -18,7 +18,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@mdi/font": "^7.4.47",
|
||||
"buffer": "^6.0.3",
|
||||
"ethers": "^6.16.0",
|
||||
"pinia": "^3.0.4",
|
||||
"siwe": "^3.0.0",
|
||||
"vue": "^3.5.27",
|
||||
"vue-router": "^5.0.1",
|
||||
"vuetify": "^4.0.0-beta.0"
|
||||
@ -46,6 +49,7 @@
|
||||
"prettier": "3.8.1",
|
||||
"typescript": "~5.9.3",
|
||||
"vite": "^7.3.1",
|
||||
"vite-plugin-node-polyfills": "^0.25.0",
|
||||
"vite-plugin-vue-devtools": "^8.0.5",
|
||||
"vitest": "^4.0.18",
|
||||
"vue-tsc": "^3.2.4"
|
||||
|
||||
@ -35,15 +35,15 @@
|
||||
</div>
|
||||
|
||||
<v-btn
|
||||
class="metamask-btn"
|
||||
class="wallet-btn"
|
||||
color="success"
|
||||
block
|
||||
@click="connectWithMetaMask"
|
||||
@click="connectWithWallet"
|
||||
:loading="isConnecting"
|
||||
:disabled="isConnecting"
|
||||
>
|
||||
<span class="metamask-icon">🟡</span>
|
||||
{{ isConnecting ? 'Connecting...' : 'Connect with MetaMask' }}
|
||||
<span class="wallet-icon">🟡</span>
|
||||
{{ isConnecting ? 'Connecting...' : 'Connect with Wallet' }}
|
||||
</v-btn>
|
||||
|
||||
<div v-if="errorMessage" class="error-message">
|
||||
@ -64,6 +64,8 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { BrowserProvider } from 'ethers'
|
||||
import { SiweMessage } from 'siwe'
|
||||
|
||||
const router = useRouter()
|
||||
const email = ref('')
|
||||
@ -79,14 +81,16 @@ const handleLogin = () => {
|
||||
router.push('/')
|
||||
}
|
||||
|
||||
const connectWithMetaMask = async () => {
|
||||
const connectWithWallet = async () => {
|
||||
isConnecting.value = true
|
||||
errorMessage.value = ''
|
||||
|
||||
try {
|
||||
// Check if MetaMask is installed
|
||||
// Check if Ethereum wallet is installed
|
||||
if (!window.ethereum) {
|
||||
throw new Error('MetaMask is not installed. Please install it to continue.')
|
||||
throw new Error(
|
||||
'Ethereum wallet is not installed. Please install MetaMask, TokenPocket or another Ethereum wallet to continue.',
|
||||
)
|
||||
}
|
||||
|
||||
// Request account access
|
||||
@ -95,36 +99,76 @@ const connectWithMetaMask = async () => {
|
||||
})
|
||||
|
||||
const walletAddress = accounts[0]
|
||||
console.log('Connected to MetaMask with account:', walletAddress)
|
||||
console.log('Connected to wallet with account:', walletAddress)
|
||||
|
||||
// Validate wallet address format
|
||||
if (!walletAddress || !/^0x[0-9a-fA-F]{40}$/.test(walletAddress)) {
|
||||
throw new Error('Invalid wallet address format. Please check your wallet connection.')
|
||||
}
|
||||
|
||||
// Get chain ID
|
||||
const chainId = await window.ethereum.request({
|
||||
method: 'eth_chainId',
|
||||
})
|
||||
|
||||
// Create Siwe-formatted message manually
|
||||
// const scheme = window.location.protocol.slice(0, -1);
|
||||
// const domain = 'polymarket.com';//window.location.host
|
||||
// const uri = 'https://api.xtrader.vip/base/walletLogin';//window.location.origin
|
||||
|
||||
const scheme = window.location.protocol.slice(0, -1)
|
||||
const domain = window.location.host
|
||||
const origin = window.location.origin
|
||||
|
||||
const statement = 'Sign in to PolyMarket'
|
||||
const version = '1'
|
||||
|
||||
const issuedAt = new Date().toISOString()
|
||||
const provider = new BrowserProvider(window.ethereum)
|
||||
const signer = await provider.getSigner()
|
||||
const siwe = new SiweMessage({
|
||||
scheme,
|
||||
domain,
|
||||
address: signer.address,
|
||||
statement,
|
||||
uri: origin,
|
||||
version: '1',
|
||||
chainId: chainId,
|
||||
})
|
||||
const message = siwe.prepareMessage()
|
||||
// 去掉message 头部的http://
|
||||
// 将 message 中匹配 signer.address 值的内容替换为小写
|
||||
// const lowerAddress = signer.address.toLowerCase()
|
||||
const message1 = message.replace(/^https?:\/\//, '')
|
||||
// console.log('Cleaned Siwe message:', cleanedMessage)
|
||||
// const cleanedMessage = message1.replace(/^https?:\/\//, '')
|
||||
// console.log('Cleaned Siwe message:', cleanedMessage)
|
||||
|
||||
// Generate nonce for security
|
||||
const nonce = Math.floor(Math.random() * 1000000).toString()
|
||||
const nonce = siwe.nonce //Math.floor(Math.random() * 1000000).toString()
|
||||
|
||||
// Create message to sign
|
||||
const message = `happy new year`
|
||||
// Construct Siwe message according to EIP-4361 standard
|
||||
// const message = `${domain} wants you to sign in with your Ethereum account:\n${walletAddress}\n\n${statement}\n\nURI: ${origin}\nVersion: ${version}\nChain ID: ${parseInt(chainId, 16)}\nNonce: ${nonce}\nIssued At: ${issuedAt}`
|
||||
|
||||
console.log('Generated Siwe-formatted message:', message1)
|
||||
|
||||
// Request signature
|
||||
const signature = await window.ethereum.request({
|
||||
method: 'personal_sign',
|
||||
params: [message + nonce, walletAddress],
|
||||
params: [message1, signer.address],
|
||||
})
|
||||
|
||||
console.log('Signature:', signature)
|
||||
console.log('Login data:', {
|
||||
message,
|
||||
nonce,
|
||||
signature,
|
||||
walletAddress,
|
||||
})
|
||||
|
||||
// Call login API
|
||||
const loginResponse = await fetch('https://api.xtrader.vip/base/walletLogin', {
|
||||
//http://localhost:8080 //https://api.xtrader.vip
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
message,
|
||||
Message: message1,
|
||||
nonce,
|
||||
signature,
|
||||
walletAddress,
|
||||
@ -142,8 +186,9 @@ const connectWithMetaMask = async () => {
|
||||
// In a real application, you would store the token or session data here
|
||||
router.push('/')
|
||||
} catch (error: any) {
|
||||
console.error('Error connecting to MetaMask:', error)
|
||||
errorMessage.value = error.message || 'Failed to connect with MetaMask'
|
||||
console.error('Error connecting to wallet:', error)
|
||||
errorMessage.value =
|
||||
error.message || 'Failed to connect with wallet. Please check your wallet and try again.'
|
||||
} finally {
|
||||
isConnecting.value = false
|
||||
}
|
||||
@ -160,10 +205,34 @@ const connectWithMetaMask = async () => {
|
||||
min-height: calc(100vh - 80px);
|
||||
}
|
||||
|
||||
/* PC端样式 - 固定大小 */
|
||||
@media (min-width: 600px) {
|
||||
.login-card {
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
padding: 24px;
|
||||
max-width: 480px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
/* 手机端样式 - 铺满页面 */
|
||||
@media (max-width: 599px) {
|
||||
.login-container {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.login-row {
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.login-card {
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
padding: 32px 24px;
|
||||
min-height: 100vh;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.login-title {
|
||||
@ -200,7 +269,7 @@ const connectWithMetaMask = async () => {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.metamask-btn {
|
||||
.wallet-btn {
|
||||
height: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -208,7 +277,7 @@ const connectWithMetaMask = async () => {
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.metamask-icon {
|
||||
.wallet-icon {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
|
||||
@ -1,20 +1,35 @@
|
||||
import { fileURLToPath, URL } from 'node:url'
|
||||
// import { fileURLToPath, URL } from 'node:url'
|
||||
|
||||
// import { defineConfig } from 'vite'
|
||||
// import vue from '@vitejs/plugin-vue'
|
||||
// import vueJsx from '@vitejs/plugin-vue-jsx'
|
||||
// import vueDevTools from 'vite-plugin-vue-devtools'
|
||||
|
||||
// // https://vite.dev/config/
|
||||
// export default defineConfig({
|
||||
// plugins: [vue(), vueJsx(), vueDevTools()],
|
||||
// resolve: {
|
||||
// alias: {
|
||||
// '@': fileURLToPath(new URL('./src', import.meta.url)),
|
||||
// },
|
||||
// },
|
||||
// })
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import vueJsx from '@vitejs/plugin-vue-jsx'
|
||||
import vueDevTools from 'vite-plugin-vue-devtools'
|
||||
// 1. 导入插件
|
||||
import { nodePolyfills } from 'vite-plugin-node-polyfills'
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
vue(),
|
||||
vueJsx(),
|
||||
vueDevTools(),
|
||||
// 2. 将此插件添加到插件数组中
|
||||
nodePolyfills({
|
||||
// 为了彻底解决SIWE等库的问题,建议包含以下选项
|
||||
protocolImports: true,
|
||||
}),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||
},
|
||||
// 3. 可选但推荐:显式定义 process.env 以避免其他潜在错误
|
||||
define: {
|
||||
'process.env': {},
|
||||
},
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user