Я работаю над веб-приложением 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
приложения.
Просто интересно, есть ли какая-нибудь статья, которая подробно объясняет этот процесс. Или рабочий пример с вышеуказанными предпосылками?
Я попробовал следующий 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
App Router
., вы должны увидеть папку app
внутри src
Next.js 14
. Согласно официальной документации [next-auth][1]
., конфигурация совместима с App Router
следующим образом.api
внутри папки app
auth
внутри api
[...nextauth]
внутри папки auth
route.ts
файл внутри [...nextauth]
папкиsrc/app/api/auth/[..nextauth]/router.ts
Шаг 3. Настройка конфигурации следующей аутентификации
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
Полагаю, это уберет ваш блокировщик.
безопасно ли хранить такой токен на интерфейсе в useSession?
лучше использовать getToken
от next-auth/jwt
?
По какой-то причине необходимо проверить совместимость
msal-react
сApp Router
. сmsal-react
. происходит аутентификация Microsoft., но при перенаправлении обратно в мое приложение реагирования я вижу, что учетные записи представляют собой пустой объект. но сnext-auth
я не вижу проблемы. на данный момент.,next-auth
решил мою проблемуmsal-react
.