如何在 typescript for nextauthjs 中正确编写授权函数

我正在尝试将 Credentials Provider 与 NextJs(“next”:“^12.0.7”)和 NextAuth(“next-auth”:“^4.1.2”)一起使用。我正在用打字稿写这个,并且在正确获取函数方面遇到问题。

这是我的 /pages/api/[...nextauth].ts

import NextAuth, {  } from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import { verifyOTP } from "@/lib/otp";

// {
//   user: {
//     id: 1,
//     username: null,
//     phone: '+919876543210',
//     phoneVerified: true,
//     email: null,
//     emailVerified: false,
//     active: true,
//     token: 'SOME TOKEN',
//     createDate: null
//   },
//   result: 'approved'
// }

export default NextAuth({
  pages: {
    signIn: '/signup',
    newUser: '/signup',
    error: '/signup'
  },
  debug: false,
  secret: "SOME_SECRET",
  // Configure one or more authentication providers
  providers: [
    CredentialsProvider({
      credentials: {
        username: {label: "username", type: "text", placeholder: "markandre"},
        phone: { label: "Phone ", type: "text", placeholder: "+919876543210" },
        otp: {  label: "OTP", type: "text" }
      },
      authorize: async (credentials, _req) => {
        try {
          const res = await verifyOTP(credentials!.phone,
            credentials!.otp, credentials?.username);
          if (res.result === "approved") {
            return Promise.resolve( {
              id: res.user.id,
              email: res.user.email,
              name: res.user.phone,
              token: res.user.token
            });
          }
        } catch (e: any) {
          //const errorMessage = e.response.data.message;
          //throw new Error(errorMessage);
          return Promise.reject(null);
        }
      }
    })
  ],
  session: {
    strategy: 'jwt',
    maxAge: 3 * 60 * 60, // 3 hours
  },
  callbacks: {
    jwt: async ({token, user}) => {
      if (user) {
        token.accessToken = user.token
      }

      return token;
    },
    session:async ({session, token}) => {
      if (token) {
        session.accessToken = token.accessToken;
      }
      return session;
    }
  },
  events: {
    signIn: async (message) => {
      console.log('signIn', message);
    },
    signOut: async (message) => {
      console.log('signOut', message);
    },
    createUser: async(message) => {
      console.log('createUser', message);
    },
    updateUser: async(message) => {
      console.log('updateUser', message);
    },
    linkAccount: async(message) => {
      console.log('linkAccount',message);
    },
    session: async(message) => {
      // console.log('session', message);
    }
  }
})

当我构建这个应用程序时,我不断收到错误

./src/pages/api/auth/[...nextauth].ts:36:7
Type error: Type '(credentials: Record<"username" | "phone" | "otp", string> | undefined, _req: Pick<IncomingRequest, "headers" | "body" | "query" | "method">) => Promise<...>' is not assignable to type '(credentials: Record<"username" | "phone" | "otp", string> | undefined, req: Pick<IncomingRequest, "headers" | "body" | "query" | "method">) => Awaitable<...>'.
  Type 'Promise<Omit<User, "id"> | null | undefined>' is not assignable to type 'Awaitable<Omit<User, "id"> | { id?: string | undefined; } | null>'.
    Type 'Promise<Omit<User, "id"> | null | undefined>' is not assignable to type 'Omit<User, "id">'.
      Index signature for type 'string' is missing in type 'Promise<Omit<User, "id"> | null | undefined>'.

  34 |         otp: {  label: "OTP", type: "text" }
  35 |       },
> 36 |       authorize: async (credentials, _req) => {
     |       ^
  37 |         try {
  38 |           const res = await verifyOTP(credentials!.phone,
  39 |             credentials!.otp, credentials?.username);
info  - Checking validity of types .%

我的 .tsconfig 如下所示

{
  "compilerOptions": {
    "lib": ["dom", "dom.iterable", "esnext"],
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "removeComments": true,
    "preserveConstEnums": true,
    "strict": true,
    "alwaysStrict": false,
    "strictNullChecks": true,
    "noUncheckedIndexedAccess": true,

    "noImplicitAny": true,
    "noImplicitReturns": true,
    "noImplicitThis": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "allowUnreachableCode": false,
    "noFallthroughCasesInSwitch": true,

    "target": "es5",
    "outDir": "out",
    "declaration": true,
    "sourceMap": true,

    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "allowJs": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,

    "jsx": "preserve",
    "noEmit": true,
    "isolatedModules": true,
    "incremental": true,

    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"],
      "@/public/*": ["./public/*"]
    }
  },
  "exclude": ["./out/**/*", "./node_modules/**/*"],
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
}
stack overflow How to write authorize function correctly in typescript for nextauthjs
原文答案
author avatar

接受的答案

如果凭证无效, authorize 函数需要返回代表用户的对象或 false / null

您当前的逻辑没有明确返回 false / null 对于 res.result === "approved" 检查为假的情况,因此是类型错误。您可以通过在 null 块之后显式返回 if 来解决此问题。

authorize: async (credentials, _req) => {
    try {
        const res = await verifyOTP(credentials!.phone, credentials!.otp, credentials?.username);
        if (res.result === "approved") {
            return {
                id: res.user.id,
                email: res.user.email,
                name: res.user.phone,
                token: res.user.token
            };
        }
        return null; // Add this line to satisfy the `authorize` typings
    } catch (e: any) {
        //const errorMessage = e.response.data.message;
        //throw new Error(errorMessage);
        return null;
    }
}

附带说明一下,您也不需要用 null / Promise.resolve() 包装用户对象和 Promise.reject() ,所以我也省略了这些。


答案:

作者头像

这实际上是一个尚未解决的错误: https://github.com/nextauthjs/next-auth/issues/2701

作者头像

通过在 tsconfig.json 中将 strict 模式从 true 设置为 false ,这对我有用。

见下图。

enter image description here