npm install next-auth@betaimport NextAuth, { DefaultSession, User } from "next-auth";
import Credentials from "next-auth/providers/credentials";
declare module "next-auth" {
/**
* 登录成功后, Session 中会包含用户 id、mob_icc、mob_num 信息,正常情况下,
* 前端只需要使用 id 就可以了,其他信息可以从数据库中查询
*/
interface Session {
user: {
id: string,
mob_icc: string,
mob_num: string,
} & DefaultSession["user"]
}
/**
* 登录成功后, User 中会包含用户 id、mob_icc、mob_num 信息,正常情况下,
* 前端只需要使用 id 就可以了,其他信息可以从数据库中查询
*/
interface User {
id: string,
mob_icc: string,
mob_num: string,
}
}
export const { handlers, signIn, signOut, auth } = NextAuth({
basePath: process.env.NEXT_PUBLIC_BASE_PATH + "/api/auth", // 自定义 auth 路由,如果项目不是根目录,需要配置
trustHost: true,
useSecureCookies: false,
providers: [
Credentials({
// Credentials 认证方式,当没有第三方登录时使用
credentials: {
mob_icc: {}, // 自定义认证项,可以是用户名密码,也可以是手机号验证码等等
mob_num: {},
checkcode: {},
},
authorize: async (credentials) => { // 自定义认证逻辑
let user: User | null = null;
const mob_icc = credentials?.mob_icc;
const mob_num = credentials?.mob_num;
const checkcode = credentials?.checkcode;
// 验证过程略
// 登录成功时,返回 User
user = {
id: "1", // 实际项目中,这里应该是数据库中的用户 ID
mob_icc,
mob_num,
};
return user;
// 登录失败时,返回 null
return null;
},
}),
],
callbacks: {
jwt({ token, user }) {
// 登录成功时,将用户信息添加到 token 中,只存 id 就够
if (user) { // User is available during sign-in
token.id = user.id;
token.mob_icc = user.mob_icc;
token.mob_num = user.mob_num;
}
return token;
},
session({ session, token }) {
// 登录成功时,将 token 中的用户信息添加到 session 中, 其实只取 id 就够
return {
...session,
user: {
...session.user,
id: token.id as string,
mob_icc: token.mob_icc as string,
mob_num: token.mob_num as string,
},
}
},
},
})/**
* 登录路由,使用 Credentials 认证方式
* 登录成功后,会返回一个包含用户信息的 Session
* 登录失败时,会返回 null
* 这段基本不用变
*/
import { handlers } from "@/auth";
export const { GET, POST } = handlers;服务端认证比较容易,只需要调用 signIn 方法即可,认证成功后,会返回一个包含用户信息的 Session,认证失败时,会返回 null。
但是服务端不擅长处理登录状态,所以需要在客户端处理登录状态。
在客户端认证时,如果认证是部署在根目录,一般按官方文档的方式处理,就是在登录成功后,将用户信息添加到 Session 中,然后在客户端使用 useSession 钩子获取用户信息。
但是如果认证不是部署在根目录,比如部署在 /app 目录下,用官方的配置方法无法成功,即使配置 basePath 也无效。
这时候可以新建一个 action.ts 文件,声明其在只服务端运行,然后包裹一下 signIn 方法,这样就能可以解决客户端认证失败的问题了,例如:
"use server";
import { signIn } from "@/app/auth";
export const loginAction = async (formData: FormData) => {
const mob_icc = formData.get("mob_icc");
const mob_num = formData.get("mob_num");
const checkcode = formData.get("checkcode");
const result = await signIn("credentials", {
basePath: process.env.NEXT_PUBLIC_BASE_PATH,
mob_icc,
mob_num,
checkcode,
});
return result;
}如果需要在客户端获取 Session,就在 layout.tsx 文件中添加 SessionProvider 组件,例如:
import { SessionProvider } from "next-auth/react";
import { auth } from "@/app/auth";
export default async function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
// 获取服务器会话
const session = await auth();
return (
<html lang="en">
<body>
<SessionProvider session={session}>
{children}
</SessionProvider>
</body>
</html>
);
}这样客户端页面只需要调用 useSession 钩子即可获取用户信息,例如:
import { useSession } from "next-auth/react";
const { data: session } = useSession();在客户端调用的好处是,不需要在服务端处理登录状态,只需要在客户端获取用户信息,就可以知道用户是否登录了。
如果只在服务端获取 Session,就需要在服务端调用 auth 方法,例如:
const session = await auth();原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。