Next Auth凭证提供程序 – SignIn()和映射到我的API Dto

huangapple go评论51阅读模式
英文:

Next Auth Credentials Provider - SignIn() and Mapping to my API Dto

问题

我正在使用Next.js和Next Auth与我的后端C# ASP.NET API通信。

我的API的响应如下DTO:

{
  "data": {
    "accessToken": "string",
    "refreshToken": "string",
    "email": "user@example.com",
    "username": "string",
    "roles": [
      "string"
    ]
  },
  "success": true,
  "message": "string"
 }

我在尝试将这些信息传递到next auth会话中以便可以使用useSession()获取它们时遇到了困难。

我也希望能够在登录表单中向用户显示API的"message",以防其帐户被锁定或发生其他情况。

这是我的代码:

[...nextauth].js

import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import { API_URL } from "@/constants";

export const authOptions = {
  // 配置一个或多个身份验证提供程序
  providers: [
    // 添加您的提供程序
    CredentialsProvider({
      name: "Credentials",
      credentials: {
        username: { label: "Username", type: "text", placeholder: "jsmith" },
        password: { label: "Password", type: "password" },
      },
      async authorize(credentials, req) {
        const { username, password } = credentials;

        const body = JSON.stringify({
          username,
          password,
        });

        // 向我们的API发送登录请求。
        const res = await fetch(`${API_URL}/Login`, {
          method: "POST",
          headers: {
            Accept: "application/json",
            "Content-Type": "application/json; charset=utf-8",
          },
          body: body,
        });

        const data = await res.json();

        // 我们的API的响应包含
        /*
					{
					"data": {
						"accessToken": "string",
						"refreshToken": "string",
						"email": "user@example.com",
						"username": "string",
						"roles": [
						"string"
						]
					},
					"success": true,
					"message": "string"
					}
				*/

        const user = {
          success: data.success,
          message: data.message,
          email: data.data.email,
          username: data.data.username,
          accessToken: data.data.accessToken,
          refreshToken: data.data.refreshToken,
          roles: data.data.roles,
        };

        // 到这里都没问题!
        // 我可以获取填充的用户对象。

        if (res.ok && user) {
          return user; // 是否真的将完整的用户对象返回给会话?
        } else {
          return null;
        }
      },
    }),
  ],
  pages: { signIn: "/login" },
};

export default NextAuth(authOptions);

导航链接:

<Nav.Link as={Link} href='/login' onClick={() => signIn()}>Login</Nav.Link>
<Nav.Link as={Link} href='/signout' onClick={() => signOut({callbackUrl: '/'})}>Signout</Nav.Link>

登录表单:

// 从表单获取数据。
const nextAuthSettings = {
  username: event.target.username.value,
  password: event.target.password.value,
  redirect: true,
  callbackUrl: "/dashboard",
};

// 将表单数据发送到Next Auth
const result = await signIn("credentials", nextAuthSettings);

// 错误处理
// 这不起作用
// 我认为signIn()不会不幸地返回用户对象的副本...
if (!result.success) {
  // 在页面上显示API错误消息
  setErrorMsg(result.message);
}

然后在各个页面中,当我想要访问用户对象时,我正在做这个:

import { useSession } from "next-auth/react";

const { data: session } = useSession();

// 这只显示电子邮件
<span>{session?.user.email}</span>;

// 当我在控制台上打印时,它看起来像JWT或其他东西
{
"user": {
  "email": "users@email.com"
},
"expires": "2023-03-16T12:39:28.120Z"
}

任何帮助都将不胜感激!
我需要能够在我的应用程序中访问API返回的用户对象。
目前我只能获取session.user.email,没有别的信息。感觉我没有将API的响应映射到Next Auth希望我创建的东西...

英文:

I am using Next.js and Next Auth to talk to my backend C# ASP.NET API.

My API's response is the following DTO:

{
  &quot;data&quot;: {
    &quot;accessToken&quot;: &quot;string&quot;,
    &quot;refreshToken&quot;: &quot;string&quot;,
    &quot;email&quot;: &quot;user@example.com&quot;,
    &quot;username&quot;: &quot;string&quot;,
    &quot;roles&quot;: [
    &quot;string&quot;
    ]
  },
  &quot;success&quot;: true,
  &quot;message&quot;: &quot;string&quot;
 }

I am having a hard time getting that info into the next auth session so that I can grab it with useSession().

I'd also like to be able to display the API "message" to the user in the login form. Incase their account is locked or whatever.

This is what I have:

[...nextauth].js

import NextAuth from &quot;next-auth&quot;;
import CredentialsProvider from &quot;next-auth/providers/credentials&quot;;
import { API_URL } from &quot;@/constants&quot;;

export const authOptions = {
  // Configure one or more authentication providers
  providers: [
    // Add Your Providers Here
    CredentialsProvider({
      name: &quot;Credentials&quot;,
      credentials: {
        username: { label: &quot;Username&quot;, type: &quot;text&quot;, placeholder: &quot;jsmith&quot; },
        password: { label: &quot;Password&quot;, type: &quot;password&quot; },
      },
      async authorize(credentials, req) {
        const { usernme, password } = credentials;

        const body = JSON.stringify({
          username,
          password,
        });

        // Login request to our API.
        const res = await fetch(`${API_URL}/Login`, {
          method: &quot;POST&quot;,
          headers: {
            Accept: &quot;application/json&quot;,
            &quot;Content-Type&quot;: &quot;application/json; charset=utf-8&quot;,
          },
          body: body,
        });

        const data = await res.json();

        // Our API&#39;s response contains
        /*
					{
					&quot;data&quot;: {
						&quot;accessToken&quot;: &quot;string&quot;,
						&quot;refreshToken&quot;: &quot;string&quot;,
						&quot;email&quot;: &quot;user@example.com&quot;,
						&quot;username&quot;: &quot;string&quot;,
						&quot;roles&quot;: [
						&quot;string&quot;
						]
					},
					&quot;success&quot;: true,
					&quot;message&quot;: &quot;string&quot;
					}
				*/

        const user = {
          success: data.success,
          message: data.message,
          email: data.data.email,
          username: data.data.username,
          accessToken: data.data.accessToken,
          refreshToken: data.data.refreshToken,
          roles: data.data.roles,
        };

        // EVERYTHING TO HERE IS GOOD!
        // I CAN GET THE user OBJECT FILLED.

        if (res.ok &amp;&amp; user) {
          return user; //&lt;---- is this actually returning the full user object to the session?
        } else {
          return null;
        }
      },
    }),
  ],
  pages: { signIn: &quot;/login&quot; },
};

export default NextAuth(authOptions);

Navbar Links:

&lt;Nav.Link as={Link} href=&#39;/login&#39; onClick={() =&gt; signIn()}&gt;Login&lt;/Nav.Link&gt;
&lt;Nav.Link as={Link} href=&#39;/signout&#39; onClick={() =&gt; signOut({callbackUrl: &#39;/&#39;})}&gt;Signout&lt;/Nav.Link&gt;

Login form:

// Get data from the form.
const nextAuthSettings = {
  username: event.target.username.value,
  password: event.target.password.value,
  redirect: true,
  callbackUrl: &quot;/dashboard&quot;,
};

// Send the form data to Next Auth
const result = await signIn(&quot;credentials&quot;, nextAuthSettings);

// Error Handling
// THIS DOES NOT WORK
// I don&#39;t think signIn() returns a copy of the user object unfortunately...
if (!result.success) {
  // Display the API Error Message On The Page
  setErrorMsg(result.message);
}

And then in various pages, when I want to access the user object I am doing this :

import { useSession } from &quot;next-auth/react&quot;;

const { data: session } = useSession();

// This only shows the email
&lt;span&gt;{session?.user.email}&lt;/span&gt;;

// It looks like a JWT or something when I console log it
{
&quot;user&quot;: {
  &quot;email&quot;: &quot;users@email.com&quot;
},
&quot;expires&quot;: &quot;2023-03-16T12:39:28.120Z&quot;
}

Any help appreciated!
I need to be able to access the user object my API is returning throughout my app.
At the moment I'm just getting this session.user.email and nothing else ??
it's like I am not mapping the API's response to whatever Next Auth wants me to create...

答案1

得分: 0

你需要使用 callbacks

callbacks: {
    async jwt({ user, token }) {
      // 从用户更新令牌
      if (user) {
        token.user = user;
      }
      // 返回最终令牌
      return token;
    },
    async session({ session, token }) {
      // 从令牌更新会话
      session.user = token.user;
      return session;
    },
  },

现在,您可以使用 useSession() 访问您的会话,并使用 getToken() 访问令牌。

英文:

you have to use callbacks :

callbacks: {
    async jwt({ user, token }) {
      //   update token from user
      if (user) {
        token.user = user;
      }
      //   return final_token
      return token;
    },
    async session({ session, token }) {
      // update session from token
      session.user = token.user;
      return session;
    },
  },

Now you can access your session with useSession() and your token with getToken()

huangapple
  • 本文由 发表于 2023年2月14日 21:12:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/75448357.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定