使用 NextJS 和 NextAuth v4 构建身份验证
由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!
今天我们将使用 Next.js 和 NextAuth 构建一个身份验证示例应用程序。我们将使用自定义表单和凭据提供程序,以便轻松地在项目中引入自定义数据库或端点进行凭据验证。如果您需要在项目中编写少量代码来实现身份验证功能,这是一个很好的样板。
什么是 NextAuth?
它是一个完整的 Next.js 应用开源解决方案。它旨在简化应用中多种用户身份验证方式的处理。它内置支持 OAuth、Google 等多种身份验证服务。NextAuth 也非常适合数据库身份验证,因为它提供了广泛的数据库支持。
演示
项目设置
yarn create next-app app && cd app
mkdir components && cd pages && touch login.js && cd api && mkdir auth
npm i next-auth axios
我们先从编辑开始。_app.js
我们将导入SessionProvider和userSession。
-
会话提供程序将允许我们向组件提供会话数据。
-
useSession 是一个客户端 React Hook,它允许我们确定用户是否已通过身份验证并获取用户数据。
我们将创建一个身份验证功能组件,该组件将允许我们确定是否应该允许用户访问某些页面,或者是否需要将用户重定向回登录页面。
import { SessionProvider, useSession } from 'next-auth/react'
import { useEffect } from 'react'
import { useRouter } from 'next/router'
export default function MyApp({ Component, pageProps: pageProps }) {
return (
<SessionProvider session={pageProps.session}>
{Component.auth ? (
<Auth>
<Component {...pageProps} />
</Auth>
) : (
<Component {...pageProps} />
)}
</SessionProvider>
)
}
function Auth({ children }) {
const router = useRouter()
const { data: session, status, token } = useSession()
const isUser = !!session?.user
useEffect(() => {
if (status === 'loading') return // Do nothing while loading
if (!isUser) router.push('/login') //Redirect to login
}, [isUser, status])
if (isUser) {
return children
}
// Session is being fetched, or no user.
// If no user, useEffect() will redirect.
return <div>Loading...</div>
}
现在我们将创建一个动态 API 路由来捕获所有路径,/api/auth因为 NextAuth 默认需要访问这些路由。凭据提供程序允许我们实现用户授权逻辑,这里我们需要数据库或 API 来验证用户凭据是否有效。如果出现错误,则会在登录表单中返回一条消息。为了简单起见,本示例中使用了硬编码的用户。我们将使用会话 cookie 中的加密 JWT(JWE)。
在 [...nextauth].js 目录下创建pages/api/auth文件
import NextAuth from 'next-auth'
import CredentialsProvider from 'next-auth/providers/credentials'
//Api route function that is returned from next auth
export default NextAuth({
providers: [
CredentialsProvider({
async authorize(credentials) {
// credentials will to passed from our login form
// Your own logic here either check agains database or api endpoint
// e.g. verify password if valid return user object.
const user = {
id: 1,
name: 'john',
email: 'user@example.com',
password: '12345',
}
if (
credentials.email === user.email &&
credentials.password === user.password
)
return user
throw new Error('Incorrect Credentials') // This will be error message displayed in login form
},
}),
],
callbacks: {
// called after sucessful signin
jwt: async ({ token, user }) => {
if (user) token.id = user.id
return token
}, // called whenever session is checked
session: async ({ session, token }) => {
if (token) session.id = token.id
return session
},
},
secret: 'SECRET_HERE',
session: {
strategy: 'jwt',
maxAge: 1 * 24 * 60 * 60, // 1d
},
jwt: {
secret: 'SECRET_HERE',
encryption: true,
},
})
现在我们将实现login.js
登录函数,该函数会调用并传递用户详细信息进行授权。如果凭据匹配,用户将被授予访问权限并重定向到受保护的“/”路由。
import { signIn, useSession } from 'next-auth/react'
import { useRouter } from 'next/router'
import { useState, useRef } from 'react'
const Login = () => {
const { status, loading } = useSession()
const router = useRouter()
const [error, setError] = useState(false)
const emailRef = useRef()
const passwordRef = useRef()
if (status === 'authenticated') {
router.push('/')
}
const loginHandler = async (e) => {
e.preventDefault()
const { error } = await signIn('credentials', {
redirect: false,
email: emailRef.current.value,
password: passwordRef.current.value,
callbackUrl: '/',
})
if (error) setError(error)
}
return (
<>
{status === 'unauthenticated' && (
<>
<p>{status}</p>
<h3>{error}</h3>
<h3>Log in</h3>
<form onSubmit={(e) => loginHandler(e)}>
<input placeholder='Email' name='email' ref={emailRef} />
<input placeholder='Pasword' name='password' ref={passwordRef} />
<input type='submit' />
</form>
</>
)}
</>
)
}
export default Login
index.js我们在 index.js 文件中Dashboard.auth = true将此路由标记为受保护路由。因此,只有经过身份验证的用户才能访问它。
import Navbar from '../components/Navbar'
export default function Dashboard() {
return (
<>
<Navbar />
<h1>secret dashboard</h1>
</>
)
}
Dashboard.auth = true
最后,我们将创建一个带有注销按钮的导航栏,以便销毁会话并重定向到登录页面。
Navbar.js
import { signOut, useSession } from 'next-auth/react'
const Navbar = () => {
const { data: session } = useSession()
return (
<div
style={{
display: 'flex',
flexDirection: 'row',
width: '100%',
backgroundColor: '#b91c1c',
}}
>
<a>{session.user.name}</a>
<button
onClick={() => {
signOut({ redirect: false })
}}
>
Signout
</button>
</div>
)
}
export default Navbar
总而言之,NextAuth 是一款功能强大且灵活的身份验证解决方案,并拥有便于开发者使用的文档。借助 NextAuth,我们可以简化应用程序的用户身份验证流程,并遵循良好的实践和模式。
希望这篇文章对你们有所帮助。感谢阅读!
文章来源:https://dev.to/przpiw/build-authentication-with-react-and-nextauth-v4-2edc
