Как выполнить единый вход в Azure с помощью next.js 14 и App Router

Я работаю над веб-приложением React, которое использует React 18 и Next.js 14. Я использую App Router, как рекомендовано настройкой шаблона Next.js, которая создает папку app внутри папки src. Использует layout.tsx в качестве точки входа для своего приложения.

У меня нет папки pages или _app.tsx, как упоминалось во многих статьях.

Я просмотрел официальную документацию next.js (здесь). Но мне не удалось найти четкие сведения о настройке Azure SSO с помощью App Router для моего Next.js приложения.

Просто интересно, есть ли какая-нибудь статья, которая подробно объясняет этот процесс. Или рабочий пример с вышеуказанными предпосылками?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
1 400
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я попробовал следующий React 18 с кодом Next.js 14, используя AppRouter для единого входа.

Код:

src/компоненты/ProtectedRoute.tsx:

import { useRouter } from 'next/router';
import { useMsal } from '@azure/msal-react';
import React from 'react';

const ProtectedRoute: React.FC<{ children: React.ReactNode }> = ({ children }) => {
    const router = useRouter();
    const { instance } = useMsal();
    const isAuthenticated =  true;
    if (!isAuthenticated) {
        router.push('/login');
        return null;
    }
    return <>{children}</>;
};
export default ProtectedRoute;

источник/макеты/Layout.tsx:

import React, { ReactNode } from 'react';
import { MsalProvider } from '@azure/msal-react';
import { PublicClientApplication } from '@azure/msal-browser'; 
import { msalConfig } from '../msalConfig';

interface LayoutProps {
    children: ReactNode;
}
const Layout: React.FC<LayoutProps> = ({ children }) => {
    const msalInstance = new PublicClientApplication(msalConfig);
    return (
        <MsalProvider instance = {msalInstance}>
            <div>
                {children}
            </div>
        </MsalProvider>
    );
};
export default Layout;

src/pages/login.tsx:

import React from 'react';
import { useMsal } from '@azure/msal-react';

const Login: React.FC = () => {
    const { instance } = useMsal();
    const handleLogin = () => {
        instance.loginPopup();
    };
    return (
        <div>
            <h1>Login Page</h1>
            <button onClick = {handleLogin}>Login with Microsoft</button>
        </div>
    );
};
export default Login;

источник/страницы/index.tsx:

import React from 'react';
import { useMsal } from '@azure/msal-react';

const Home: React.FC = () => {
    const { instance, accounts } = useMsal();
    const handleSignIn = () => {
        instance.loginPopup();
    };
    const handleSignOut = () => {
        instance.logout();
    };
    return (
        <div>
            {accounts.length === 0 && (
                <>
                    <h1>Welcome to my Next.js App</h1>
                    <button onClick = {handleSignIn}>Sign In</button>
                </>
            )}
            {accounts.length > 0 && (
                <button onClick = {handleSignOut}>Sign Out</button>
            )}
        </div>
    );
};
export default Home;

src/pages/_app.tsx:

import React from 'react';
import { AppProps } from 'next/app';
import Layout from '../layouts/Layout';

const MyApp: React.FC<AppProps> = ({ Component, pageProps }: AppProps) => {
    return (
        <Layout>
            <Component {...pageProps} />
        </Layout>
    );
};
export default MyApp;

источник/msalConfig.ts:

export const msalConfig = {
    auth: {
        clientId: '<client_ID>',
        authority: 'https://login.microsoftonline.com/<tenant_ID>',
        redirectUri: 'http://localhost:3000', 
    },
};

Я добавил выходной URL-адрес в Аутентификацию приложения Azure как одностраничное приложение, как показано ниже.

http://localhost:3000/

Выход :

Следующий код Next.js выполнился успешно, как показано ниже.

Я успешно вошел в систему и вышел из нее, нажав кнопки «Войти» и «Выйти», как показано ниже.

Ответ принят как подходящий

App Router может быть немного сложнее при обработке перенаправления при реализации SSO. Я проведу вас шаг за шагом по настройке next-auth на ваши React 18, next.js 14 и App Router.

шаг 1. Установите зависимости

  • Установите next-auth с помощью команды npm i next-auth.

шаг 2: Настройка пути для конфигурации next-auth

  1. Поскольку вы используете App Router., вы должны увидеть папку app внутри src
  2. Кроме того, вы заявляете, что используете Next.js 14. Согласно официальной документации [next-auth][1]., конфигурация совместима с App Router следующим образом.
  3. создать папку api внутри папки app
  4. создайте папку auth внутри api
  5. создать папку [...nextauth] внутри папки auth
  6. создать route.ts файл внутри [...nextauth] папки
  7. в идеале ваш путь должен выглядеть так src/app/api/auth/[..nextauth]/router.ts

Шаг 3. Настройка конфигурации следующей аутентификации

  • Настройте URL-адрес перенаправления следующим образом.
  • https://localhost:3000/api/auth/callback/azure-ad в приложении Azure URL-адрес перенаправления регистрации.
  • для производства: https://yourapplication.com/api/auth/callback/azure-ad в URL-адресе перенаправления регистрации приложения Azure.
  • Для получения более подробной информации см. здесь для получения пошагового руководства.
  • Настройте свой router.ts. Скопируйте приведенный ниже код и настройте его в соответствии с вашими требованиями.

import NextAuth from "next-auth";
import AzureADProvider from "next-auth/providers/azure-ad";

const { AZURE_AD_CLIENT_ID, AZURE_AD_CLIENT_SECRET, AZURE_AD_TENANT_ID } =
  process.env;

if (!AZURE_AD_CLIENT_ID || !AZURE_AD_CLIENT_SECRET || !AZURE_AD_TENANT_ID) {
  throw new Error("The Azure AD environment variables are not set.");
}

const handler = NextAuth({
  secret: AZURE_AD_CLIENT_SECRET,
  providers: [
    AzureADProvider({
      clientId: AZURE_AD_CLIENT_ID,
      clientSecret: AZURE_AD_CLIENT_SECRET,
      tenantId: AZURE_AD_TENANT_ID,
    }),
  ],
  callbacks: {
    async jwt({ token, account }) {
      if (account) {
        token = Object.assign({}, token, {
          access_token: account.access_token,
        });
      }
      return token;
    },
    async session({ session, token }) {
      if (session) {
        session = Object.assign({}, session, {
          access_token: token.access_token,
        });
        console.info(session);
      }
      return session;
    },
  },
});

export { handler as GET, handler as POST };

Примечание. Вы можете декодировать access_token и id_token для получения groups, token_expiry и т. д. с помощью jwt-decode в соответствии с вашими требованиями.

Шаг 4: Настройка SessionProvider

  • Перейдите в layout.tsx и оберните свое приложение в SessionProvider следующим образом:

"use client";
import React, { useRef } from "react";
import "./globals.css";
import { Box } from "@mui/material";
import { AppStore, makeStore } from "@/lib/store";
import { Provider } from "react-redux";
import { PersistGate } from "redux-persist/integration/react";
import { SessionProvider } from "next-auth/react";
import { ProtectedComponents } from "./components/ProtectedComponents";

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  const storeRef = useRef<AppStore>();
  if (!storeRef.current) {
    storeRef.current = makeStore();
  }

  return (
    <html lang = "en">
      <body>
        <SessionProvider>
          <Provider store = {storeRef.current}>
            <PersistGate
              loading = {null}
              persistor = {storeRef.current.__persistor}
            >
              <Box sx = {{ display: "flex" }}>
                <ProtectedComponents>{children}</ProtectedComponents>
              </Box>
            </PersistGate>
          </Provider>
        </SessionProvider>
      </body>
    </html>
  );
}

Примечание. Не беспокойтесь об импорте кода route.js., next-auth. автоматически выбирает конфигурацию, если она размещена в нужном месте

В приведенном выше коде я упомянул ProtectedComponents о доступе при наличии session.

Давайте попробуем установить ProtectedComponents, выбрав session информацию следующим образом.

import React, { useEffect, ReactNode } from "react";
import { useSession } from "next-auth/react";
import { usePathname, useRouter } from "next/navigation";
import { Grid } from "@mui/material";
import Header from "./Header";

export const ProtectedComponents = ({ children }: { children: ReactNode }) => {
  const { data: session, status, update } = useSession();
  const router = useRouter();
  const pathName = usePathname();

  useEffect(() => {
    if (status === "loading") return; // Do nothing while loading
    if (session && pathName === "/") router.push("/dashboard");
    if (!session) router.push("/"); // If not authenticated, force log in
  }, [session, status]);

  return (
    <Grid container sx = {{ backgroundColor: "#F8F8F9" }}>
      <Grid item xs = {true}>
        <Grid container>
          {session && pathName !== "/" && (
            <Grid item xs = {12}>
              <Header />
            </Grid>
          )}
          <Grid item p = {2} xs = {true}>
            {children}
          </Grid>
        </Grid>
      </Grid>
    </Grid>
  );
};

Шаг 5. Настройка методов входа и выхода.

  • Вход: встроенные методы для signIn и signOut предоставляются next-auth следующим образом.

для входа:

import { signIn } from "next-auth/react";
const handleLoginClick = async () => {
  try {
    signIn();
  } catch (error) {
    console.error(error);
  }
};
<Button
  variant = "contained"
  color = "primary"
  fullWidth
  onClick = {handleLoginClick}
>
  Login
</Button>;

Для выхода из системы:

import { signOut } from "next-auth/react";
const handleLogOutClick = async () => {
  try {
    signOut();
  } catch (error) {
    console.error(error);
  }
};
<Button
  variant = "contained"
  color = "primary"
  fullWidth
  onClick = {handleLogOutClick}
>
  Login
</Button>;

На этом, по сути, завершается первоначальная настройка, необходимая для настройки следующей аутентификации Azure single sign on.

Шаг 6: Настройка NEXTAUTH_URL.

Последний, но тем не менее важный. NEXTAUTH_URL — это ключ к сервису next-auth, позволяющий фиксировать аутентификацию вашей почты redirection url.

если не указано, по умолчанию перенаправляется на localhost.

Если вы работаете на локальном хосте, NEXTAUTH_URL не является обязательным. Но при развертывании в таких средах, как dev, qa и prod., необходимо определить NEXTAUTH_URL в .env.

будет примерно так NEXTAUTH_URL=https://myapp.com

Полагаю, это уберет ваш блокировщик.

По какой-то причине необходимо проверить совместимость msal-react с App Router. с msal-react. происходит аутентификация Microsoft., но при перенаправлении обратно в мое приложение реагирования я вижу, что учетные записи представляют собой пустой объект. но с next-auth я не вижу проблемы. на данный момент., next-auth решил мою проблему msal-react.

sabarinath 15.04.2024 09:37

безопасно ли хранить такой токен на интерфейсе в useSession?

Matthias 16.05.2024 15:43

лучше использовать getToken от next-auth/jwt?

Matthias 16.05.2024 15:59

Другие вопросы по теме

Похожие вопросы

Как исправить недопустимое имя хоста для этой ошибки аренды при доступе к файлам в SharePoint с помощью API Microsoft Graph
Какое разрешение требуется для создания нового пользователя в Microsoft с использованием Graph API в C#
Как обновить изображение профиля пользователя с помощью Graph API в C#
Как получить сведения о пользователе из каталога Azure с помощью C# и API Graph?
Az-GetRoleAssigments не возвращает данные для DisplayName, SignInName и типа объекта — Azure Powershell Runbook
Каков метод предпочтительного сохранения данных для использования токена доступа (строки подключения) в качестве метода аутентификации в кеше Redis
Каков основной тип управляемого удостоверения, назначенного пользователем?
Ошибка потока общедоступного клиентского приложения Microsoft Azure
Переименуйте группу безопасности в EntraID и сопоставьте имена входа и пользователей Azure SQL
Как настроить динамически генерируемые URL-адреса перенаправления в AAD для сред предварительной версии?