next-auth集成以太坊钱包登陆
YoungJeff
·发布于 7 个月前·64 人看过
Next-auth中可以通过Credentials进行任意凭证登陆,如用户名和密码,那如果通过以太坊钱包进行登陆呢?
基于siwe这个库即可实现
siwe全称:sign in with Ethereum
具体实现
版本:
{
"next-auth": "5.0.0-beta.15",
"siwe": "^2.3.2",
}
-
next-auth配置
import NextAuth from 'next-auth'; import Credentials from 'next-auth/providers/credentials'; import { PrismaAdapter } from '@auth/prisma-adapter'; import { SiweMessage } from 'siwe'; import type { SiweMessage as SiweMessageType } from 'siwe'; export const { handlers, auth, signOut, signIn } = NextAuth({ ... providers: [ Credentials({ name: 'Ethereum', credentials: { message: { label: 'Message', type: 'text', placeholder: '0x0', }, signature: { label: 'Signature', type: 'text', placeholder: '0x0', }, }, async authorize(credentials) { const siwe = new SiweMessage( JSON.parse( credentials?.message as string, ) as Partial<SiweMessageType>, ); const result = await siwe.verify({ signature: credentials?.signature as string, }); if (result.success) { return { // 根据自己需要返回 id: siwe.address, name: siwe.address, }; } return null; }, }), ], ... });
-
连接钱包组件
'use client'; import React from 'react'; import { getCsrfToken, signIn } from 'next-auth/react'; import { SiweMessage } from 'siwe'; import { useAccount, useConnect, useSignMessage } from 'wagmi'; import { injected } from 'wagmi/connectors'; import { Button } from '@/components/ui/button'; import { PATHS } from '@/constants'; export async function getServerSideProps() { return { props: { csrfToken: await getCsrfToken(), }, }; } export const SignWithWallet = () => { const { signMessageAsync } = useSignMessage(); const { address, isConnected, chain } = useAccount(); const { connect, status } = useConnect(); const signMsg: () => Promise<void> = React.useCallback(async () => { const message = new SiweMessage({ domain: window.location.host, address: address, statement: 'Sign in with Ethereum to the app.', uri: window.location.origin, version: '1', chainId: chain?.id, nonce: await getCsrfToken(), }); const signature = await signMessageAsync({ message: message.prepareMessage(), }); await signIn('credentials', { message: JSON.stringify(message), signature, redirectTo: PATHS.ADMIN_HOME, }); }, [address, chain, signMessageAsync]); React.useEffect(() => { if (status === 'success') { signMsg().catch(() => ({})); } }, [status, signMsg]); const handleLogin = async () => { if (!isConnected) { connect({ connector: injected() }); return; } await signMsg(); }; return ( <Button variant="default" className="!w-full" type="button" onClick={() => handleLogin()} > Connect Wallet </Button> ); };
注:
因为是客户端组件,所以getCsrfToken需要从next-auth/react导出
效果如图: