【问题标题】:Next-Auth with Provider.Credentials: How to implement when API is already returning a JWT Token?Next-Auth with Provider.Credentials:当 API 已经返回 JWT 令牌时如何实现?
【发布时间】:2021-11-04 05:54:53
【问题描述】:
  • 我有一个 NextJS 页面,我尝试在其中实施 Next-Auth。
  • 我使用凭据登录我的 Rails API。
  • 我的 API 正在返回(已经)一个 JWT-Token。 (所以 NextAuth 不能创建它)

在这种情况下如何为[...nextauth].js 实现Provider.Credentials?

流程“图表” Next request ---> Next API (with Next-Auth) ---> Rails API (returning Token)

目前我有这些options:

 providers: [
    CredentialsProvider({
      name: 'Email',
      credentials: {
        email: { label: "Email", type: "email", placeholder: "meine.email@domain.com" },
        password: {  label: "Passwort", type: "password" }
      },
      async authorize(credentials) {

        // The 'url' is pointing to a Rails API endpoint which returns a JWT Token
        const url = `${process.env.NEXT_PUBLIC_API_URL}/auth/login`;

        const res = await fetch(url, {
          method: 'POST',
          body: JSON.stringify(credentials),
          headers: {
            "Content-Type": "application/json" }
        })
        const user = await res.json()

        // If no error and we have user data, return it
        if (res.ok && user) {
          // I SAW EXAMPLES RETURNING {"email": "blah@tst.com"}
          return user // MY CONTENT {token: 'eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjo0LCJyb2xl…0.OAGiwjj9O_NsH02lIjA2D4HYZkmTQ3_SqtKcVgaIul0'}

        }
        // Return null if user data could not be retrieved
        return null
      }
    })
  ]
}

在浏览器中设置了 session_token,但该内容是我没有设置的(随机的?)。如果不是我的令牌,这些内容是从哪里来的?

我的 Rails API 令牌内容:

{
  "user_id": 4,
  "roles": [
    "user"
  ],
  "exp": 1631096219
}

Next-Auth API 令牌内容:

{
  "iat": 1631009819,
  "exp": 1633601819
}

我是否必须解码我的 API 令牌并在 Provider.Credentials 函数中重新组合?

我实施 Next-Auth 以提供更多的身份验证,例如 Twitter 和 Co,但也使用“useSession”而不是构建我自己的所有东西(不会重新发明轮子)。

【问题讨论】:

    标签: jwt next-auth rails-authorization


    【解决方案1】:

    添加回调。

    export default NextAuth({
      providers: [
        CredentialsProvider({
          name: "Email",
          credentials: {
            email: {
              label: "Email",
              type: "email",
              placeholder: "meine.email@domain.com",
            },
            password: { label: "Passwort", type: "password" },
          },
          async authorize(credentials) {
            // The 'url' is pointing to a Rails API endpoint which returns a JWT Token
            const url = `${process.env.NEXT_PUBLIC_API_URL}/auth/login`;
    
            const res = await fetch(url, {
              method: "POST",
              body: JSON.stringify(credentials),
              headers: {
                "Content-Type": "application/json",
              },
            });
            const user = await res.json();
    
            // If no error and we have user data, return it
            if (res.ok && user) {
              // I SAW EXAMPLES RETURNING {"email": "blah@tst.com"}
              return user; // MY CONTENT {token: 'eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjo0LCJyb2xl…0.OAGiwjj9O_NsH02lIjA2D4HYZkmTQ3_SqtKcVgaIul0'}
            }
            // Return null if user data could not be retrieved
            return null;
          },
        }),
      ],
    
      callbacks: {
        async jwt({ token, user, account, isNewUser }) {// This user return by provider {} as you mentioned above MY CONTENT {token:}
          if (user) {
            if (user.token) {
              token = { accessToken: user.token };
            }
          }
          return token;
        },
    
        // That token store in session
        async session({ session, token }) { // this token return above jwt()
          session.accessToken = token.accessToken;
          //if you want to add user details info
          session.user = { name: "name", email: "email" };//this user info get via API call or decode token. Anything you want you can add
          return session;
        },
      },
    });
    

    【讨论】:

    • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center。
    • 如何读取 cookie 以在进一步的 api 调用中使用 JWT?
    • @user3174311 您可以从 'next-auth/react' 访问会话导入 { useSession }; const {状态,数据}= useSession();
    【解决方案2】:

    因此,您从凭据 authorize 函数返回的用户将存储在 JWT(JSON Web 令牌 - 与所有经过身份验证的请求一起传递)中,这是一个散列/编码(默认情况下未加密!)版本对象。

    您可以使用https://jwt.io 来调试并查看您的 JWT 中的内容。您将eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjo0LCJyb2xl... 值粘贴到该站点的调试器字段中,它会显示{ iat: 49835898: sub: 47897: email: 'abc@xyz.com' } 等值。

    如果您的 rails API 在 authorize 函数的 fetch 调用中向您返回 JWT,您可以使用类似 jwt-decode 的库在此处对其进行解码,并从中附加您想要的任何值在您的应用程序中“持久化”到您从 next-auth 中的 authorize 函数返回的用户对象。

    【讨论】:

    • 反之如何?针对 API 的请求(以获取数据)是否可以/应该使用旧的(原始)令牌或 NextAuth 生成的 JWT 令牌调用 API? API-Server 不会接受 NextAuth 的,对吧?
    • 是的,所以这取决于您对 API 的确切含义。这些 API 路由来自 next.js 吗?然后是next-auth原始jwt。它是来自您的 Rails 应用程序的 API 吗?然后是rails jwt。现在我不是 oauth 专家,但除了您的 userId 之外,rails jwt 中似乎没有任何进一步的识别信息。所以我很好奇您使用 next-auth info 和 rails jwt info 创建的自定义 JWT 是否适用于两者?
    猜你喜欢
    • 2021-08-13
    • 2019-08-08
    • 2021-10-18
    • 2021-12-21
    • 1970-01-01
    • 2016-12-02
    • 2018-12-04
    • 2021-01-22
    • 2017-01-06
    相关资源
    最近更新 更多