发布于 2026-01-06 5 阅读
0

使用面部认证构建安全的员工仪表盘:Next.js 综合教程;DEV 全球展示挑战赛,由 Mux 呈现:展示你的项目!

使用面部识别构建安全的员工仪表盘:Next.js 全面教程

由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!

准备好革新您的工作场所管理了吗?在本教程中,我们将深入探讨如何创建一个利用人脸识别技术的先进员工仪表盘。我们将使用一些最热门的 Web 开发工具:Next.js、FACEIO和 Shadcn UI。完成本指南后,您将拥有一个简洁、安全的仪表盘,让您的员工体验未来科技!

开始之前你需要准备什么

在深入探讨之前,让我们先确保你已做好一切准备:

  • 您的计算机上已安装 Node.js
  • npm 或 yarn(哪个顺手就用哪个)

都明白了吗?太好了!那我们开始吧。

Faceio 身份验证

项目设置:第一步

步骤 1:启动您的 Next.js 项目

首先,让我们创建 Next.js 项目。打开终端并输入以下命令:



npx create-next-app@latest faceio-app
cd faceio-app


Enter fullscreen mode Exit fullscreen mode

你会被问到几个问题。以下是如何回答:

  • TypeScript?当然可以!
  • ESLint?当然!
  • Tailwind CSS?当然!
  • src/ 目录?不用了,没问题。
  • 应用路由?好的,谢谢!
  • 自定义默认导入别名?这个我们就不做了。

步骤二:准备工具

现在,让我们来安装所有需要的组件。运行以下命令来安装依赖项:



npm install @faceio/fiojs @shadcn/ui class-variance-authority clsx tailwind-merge


Enter fullscreen mode Exit fullscreen mode

步骤三:打造你的秘方

在项目根目录下创建一个名为 .env.local 的文件。我们将在这里保存我们的FACEIO应用 ID:



NEXT_PUBLIC_FACEIO_APP_ID=your-super-secret-faceio-app-id


Enter fullscreen mode Exit fullscreen mode

请务必将“your-super-secret-faceio-app-id”替换为您实际的FACEIO应用程序ID。请妥善保管!

步骤 4:文件结构

您的项目结构应如下所示:



faceio-app/
├── app/
│   ├── layout.tsx
│   ├── page.tsx
│   └── components/
│       ├── FaceAuth.tsx
│       └── EmployeeDashboard.tsx
├── public/
├── .env.local
├── next.config.js
├── package.json
├── tsconfig.json
└── tailwind.config.js


Enter fullscreen mode Exit fullscreen mode

步骤 5:优化 Tailwind CSS

是时候给 Tailwind 来个大改造了。用以下配置更新你的 tailwind.config.js 文件:



/** @type {import('tailwindcss').Config} */
module.exports = {
  darkMode: ["class"],
  content: [
    './app/**/*.{ts,tsx}',
  ],
  theme: {
    container: {
      center: true,
      padding: "2rem",
      screens: {
        "2xl": "1400px",
      },
    },
    extend: {
      colors: {
        border: "hsl(var(--border))",
        input: "hsl(var(--input))",
        ring: "hsl(var(--ring))",
        background: "hsl(var(--background))",
        foreground: "hsl(var(--foreground))",
        primary: {
          DEFAULT: "hsl(var(--primary))",
          foreground: "hsl(var(--primary-foreground))",
        },
        secondary: {
          DEFAULT: "hsl(var(--secondary))",
          foreground: "hsl(var(--secondary-foreground))",
        },
        destructive: {
          DEFAULT: "hsl(var(--destructive))",
          foreground: "hsl(var(--destructive-foreground))",
        },
        muted: {
          DEFAULT: "hsl(var(--muted))",
          foreground: "hsl(var(--muted-foreground))",
        },
        accent: {
          DEFAULT: "hsl(var(--accent))",
          foreground: "hsl(var(--accent-foreground))",
        },
        popover: {
          DEFAULT: "hsl(var(--popover))",
          foreground: "hsl(var(--popover-foreground))",
        },
        card: {
          DEFAULT: "hsl(var(--card))",
          foreground: "hsl(var(--card-foreground))",
        },
      },
      borderRadius: {
        lg: "var(--radius)",
        md: "calc(var(--radius) - 2px)",
        sm: "calc(var(--radius) - 4px)",
      },
      keyframes: {
        "accordion-down": {
          from: { height: 0 },
          to: { height: "var(--radix-accordion-content-height)" },
        },
        "accordion-up": {
          from: { height: "var(--radix-accordion-content-height)" },
          to: { height: 0 },
        },
      },
      animation: {
        "accordion-down": "accordion-down 0.2s ease-out",
        "accordion-up": "accordion-up 0.2s ease-out",
      },
    },
  },
  plugins: [require("tailwindcss-animate")],
}


Enter fullscreen mode Exit fullscreen mode

构建仪表盘的核心

步骤 1:构建 FaceAuth 组件

让我们来创建本次演示的主角——FaceAuth 组件。新建一个文件 app/components/FaceAuth.tsx,并将以下代码粘贴到该文件中:



import { useEffect } from 'react';
import faceIO from '@faceio/fiojs';
import { Button, Card, CardHeader, CardTitle, CardContent } from '@shadcn/ui';
import { useToast } from '@shadcn/ui';

interface FaceAuthProps {
  onSuccessfulAuth: (data: any) => void;
}

const FaceAuth: React.FC<FaceAuthProps> = ({ onSuccessfulAuth }) => {
  const { toast } = useToast();

  useEffect(() => {
    const faceio = new faceIO(process.env.NEXT_PUBLIC_FACEIO_APP_ID);

    const enrollNewUser = async () => {
      try {
        const userInfo = await faceio.enroll({
          locale: 'auto',
          payload: {
            email: 'employee@example.com',
            pin: '12345',
          },
        });
        toast({
          title: "Success!",
          description: "You're now enrolled in the facial recognition system!",
        });
        console.log('User Enrolled!', userInfo);
      } catch (errCode) {
        toast({
          title: "Oops!",
          description: "Enrollment failed. Please try again.",
          variant: "destructive",
        });
        console.error('Enrollment Failed', errCode);
      }
    };

    const authenticateUser = async () => {
      try {
        const userData = await faceio.authenticate();
        toast({
          title: "Welcome back!",
          description: "Authentication successful.",
        });
        console.log('User Authenticated!', userData);
        onSuccessfulAuth({
          name: 'John Doe',
          position: 'Software Developer',
          department: 'Engineering',
          photoUrl: 'https://example.com/john-doe.jpg',
        });
      } catch (errCode) {
        toast({
          title: "Authentication failed",
          description: "Please try again or enroll.",
          variant: "destructive",
        });
        console.error('Authentication Failed', errCode);
      }
    };

    const enrollBtn = document.getElementById('enroll-btn');
    const authBtn = document.getElementById('auth-btn');

    if (enrollBtn) enrollBtn.onclick = enrollNewUser;
    if (authBtn) authBtn.onclick = authenticateUser;

    return () => {
      if (enrollBtn) enrollBtn.onclick = null;
      if (authBtn) authBtn.onclick = null;
    };
  }, [toast, onSuccessfulAuth]);

  return (
    <Card className="w-full max-w-md mx-auto">
      <CardHeader>
        <CardTitle>Facial Authentication</CardTitle>
      </CardHeader>
      <CardContent className="space-y-4">
        <Button id="enroll-btn" variant="outline" className="w-full">
          Enroll New Employee
        </Button>
        <Button id="auth-btn" variant="default" className="w-full">
          Authenticate
        </Button>
      </CardContent>
    </Card>
  );
};

export default FaceAuth;


Enter fullscreen mode Exit fullscreen mode

步骤 2:构建员工仪表盘组件

现在,我们来创建员工将看到的仪表盘。创建 app/components/EmployeeDashboard.tsx 文件:



import { useState } from 'react';
import { Card, CardHeader, CardTitle, CardContent } from '@shadcn/ui';
import { Button, Avatar, Badge, Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@shadcn/ui';
import FaceAuth from './FaceAuth';

interface EmployeeData {
  name: string;
  position: string;
  department: string;
  photoUrl: string;
}

const EmployeeDashboard: React.FC = () => {
  const [isAuthenticated, setIsAuthenticated] = useState(false);
  const [employeeData, setEmployeeData] = useState<EmployeeData | null>(null);

  const handleSuccessfulAuth = (data: EmployeeData) => {
    setIsAuthenticated(true);
    setEmployeeData(data);
  };

  const mockAttendanceData = [
    { date: '2024-07-14', timeIn: '09:00 AM', timeOut: '05:30 PM' },
    { date: '2024-07-13', timeIn: '08:55 AM', timeOut: '05:25 PM' },
    { date: '2024-07-12', timeIn: '09:05 AM', timeOut: '05:35 PM' },
  ];

  return (
    <div className="space-y-6">
      {!isAuthenticated ? (
        <FaceAuth onSuccessfulAuth={handleSuccessfulAuth} />
      ) : (
        <>
          <Card>
            <CardHeader>
              <CardTitle>Employee Profile</CardTitle>
            </CardHeader>
            <CardContent className="flex items-center space-x-4">
              <Avatar className="h-20 w-20" src={employeeData?.photoUrl} alt={employeeData?.name} />
              <div>
                <h2 className="text-2xl font-bold">{employeeData?.name}</h2>
                <p className="text-gray-500">{employeeData?.position}</p>
                <Badge variant="outline">{employeeData?.department}</Badge>
              </div>
            </CardContent>
          </Card>

          <Card>
            <CardHeader>
              <CardTitle>Quick Actions</CardTitle>
            </CardHeader>
            <CardContent className="space-y-4">
              <Button className="w-full">Check-in</Button>
              <Button className="w-full" variant="secondary">Request Leave</Button>
            </CardContent>
          </Card>

          <Card>
            <CardHeader>
              <CardTitle>Attendance Records</CardTitle>
            </CardHeader>
            <CardContent>
              <Table>
                <TableHeader>
                  <TableRow>
                    <TableHead>Date</TableHead>
                    <TableHead>Time In</TableHead>
                    <TableHead>Time Out</TableHead>
                  </TableRow>
                </TableHeader>
                <TableBody>
                  {mockAttendanceData.map((record, index) => (
                    <TableRow key={index}>
                      <TableCell>{record.date}</TableCell>
                      <TableCell>{record.timeIn}</TableCell>
                      <TableCell>{record.timeOut}</TableCell>
                    </TableRow>
                  ))}
                </TableBody>
              </Table>
            </CardContent>
          </Card>
        </>
      )}
    </div>
  );
};

export default EmployeeDashboard;


Enter fullscreen mode Exit fullscreen mode

第三步:整合所有内容

最后,让我们更新主页,展示一下我们的成果。更新 app/page.tsx:



import EmployeeDashboard from './components/EmployeeDashboard';

export default function Home() {
  return (
    <main className="flex min-h-screen flex-col items-center justify-center p-4">
      <EmployeeDashboard />
    </main>
  );
}


Enter fullscreen mode Exit fullscreen mode

现在,让我们来设置包裹整个应用程序的布局。添加以下代码:app/layout.tsx



import './globals.css'
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'

const inter = Inter({ subsets: ['latin'] })

export const metadata: Metadata = {
  title: 'Employee Dashboard with Facial Authentication',
  description: 'A cutting-edge employee dashboard featuring facial recognition for secure authentication and efficient workplace management.',
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <header className="bg-primary text-white p-4">
          <h1 className="text-2xl font-bold">Faceio Solutions</h1>
        </header>
        <main className="container mx-auto p-4">
          {children}
        </main>
        <footer className="bg-gray-100 text-center p-4 mt-8">
          <p>&copy; 2024 Faceio . All rights reserved.</p>
        </footer>
      </body>
    </html>
  )
}


Enter fullscreen mode Exit fullscreen mode

这种布局就像房屋的框架——它为整个应用程序提供了结构。它包括带有公司名称的页眉、显示仪表盘的主内容区域和页脚。此外,它还通过元数据设置了一些 SEO 优化功能!

FACEIO 集成的关键隐私和安全实践

隐私设计

  • 使用访问控制、用户同意和退出选项来保护隐私。

有意义的同意

  • 确保用户了解数据收集情况。
  • 赋予用户数据选择和控制的自由。
  • 允许随时撤销同意和删除数据。

最佳实践

  • 务必获得明确且适当的同意,尤其是对于未成年人。
  • 让用户能够轻松找到并理解同意请求。
  • 避免自动注册和未经授权的注册。
  • 在收集生物识别数据之前通知用户。
  • 遵守法律规定的数据隐私要求。

数据安全

  • 账户删除时,用户数据也会被删除。
  • 保持严格的数据保留和销毁规范。
  • 定期实施和审查安全措施。

更多详情,请参阅FACEIO最佳实践。

FACEIO 集成的关键安全考虑因素

安全设计

  • 应用程序安全对于维护用户信任至关重要。
  • 遵循 FACEIO 的安全最佳实践来降低风险。

核心安全功能

  1. 拒绝弱密码

    • 避免使用弱密码,例如 0000 或 1234。
    • 默认值:否。
  2. 防止重复注册

    • 阻止用户多次注册。
    • 默认值:否。
  3. 防范深度伪造技术

    • 检测并阻止欺骗攻击。
    • 默认值:否。
  4. 禁止未成年人入学

    • 禁止 18 岁以下用户注册。
    • 默认值:否。
  5. 需要输入PIN码进行身份验证

    • 每次验证都需要输入PIN码。
    • 默认值:是。
  6. 强制执行唯一密码

    • 确保每个用户的PIN码都是唯一的。
    • 默认值:否。
  7. 忽略被遮挡的脸

    • 在光线昏暗或部分遮挡的情况下丢弃面孔。
    • 默认值:是。
  8. 拒绝缺少标头

    • 阻止缺少正确 HTTP 标头的实例化。
    • 默认值:是。
  9. 限制实例化

    • 仅限特定领域和国家/地区。
    • 默认值:否。
  10. 启用 Webhooks

    • 通知后端 FACEIO 事件。
    • 默认值:否。

更多详情,请参阅FACEIO安全最佳实践。

实际应用:它可以在哪些方面使用?

现在我们已经构建了这个超棒的仪表盘,你可能会想:“在实际应用中,我该如何使用它呢?” 让我告诉你,它的应用场景可谓无穷无尽!以下仅列举几个例子:

  1. 办公室管理:告别老式打卡机!这套系统可以彻底改变您追踪考勤、控制办公室不同区域的访问权限以及管理员工信息的方式。

  2. 安全系统:想象一下,您的办公室像诺克斯堡一样安全,却无需承担任何麻烦。这套人脸识别系统可以成为强大安全协议的基石。

  3. 客户服务自助服务终端:想象一下——顾客走到自助服务终端前,终端立即识别出他们,并提供个性化服务。这不再是科幻小说里的情节了!

接下来是什么?天空才是极限!

恭喜你,技术达人!你刚刚搭建了一个配备人脸识别功能的尖端员工仪表盘。但为什么就此止步呢?这套系统的优势在于它的灵活性。以下是一些将其提升到更高层次的建议:

  • 实现重要更新的实时通知
  • 为人力资源部门增加详细的报告功能。
  • 与其他系统(例如工资系统或项目管理工具)集成

记住,在科技世界里,唯一的限制就是你的想象力(或许还有你的咖啡因摄入量)。

那么,您觉得怎么样?准备好让您的工作场所迈向未来了吗?不妨试试这个项目,然后告诉我进展如何。我很想了解您的体验,您添加的任何酷炫功能,或者您在过程中遇到的任何挑战。

祝您编程愉快,也希望您的面部识别系统永远不会把您误认为是办公室里的植物!

文章来源:https://dev.to/vyan/building-a-secure-employee-dashboard-with-facial-authentication-a-compressive-nextjs-tutorial-2c4g