首页  >  文章  >  web前端  >  使用面部身份验证构建安全的员工仪表板:综合 Next.js 教程

使用面部身份验证构建安全的员工仪表板:综合 Next.js 教程

WBOY
WBOY原创
2024-07-18 18:16:41615浏览

您准备好彻底改变您的工作场所管理了吗?在这个综合教程中,我们将深入研究如何创建一个利用面部身份验证的最先进的员工仪表板。我们将使用 Web 开发中一些最热门的工具:Next.js、FACEIO 和 Shadcn UI。在本指南结束时,您将拥有一个时尚、安全的仪表板,让您的员工感觉他们生活在未来!

在我们开始之前您需要什么

在我们开始之前,让我们确保你已经把所有的事情都安排好了:

  • 您的计算机上安装了 Node.js
  • npm 或yarn(无论哪个都能让你的船漂浮)

明白了吗?伟大的!让我们开始这场演出吧。

Faceio Authentication

设置您的项目:第一步

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

首先,让我们创建 Next.js 项目。打开你的终端并输入这些神奇的单词:

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

系统会问您几个问题。以下是如何回答这些问题:

  • 打字稿?哎呀,是的!
  • ESLint?绝对!
  • Tailwind CSS?你打赌!
  • src/目录?不,我们很好。
  • 应用程序路由器?是的,请!
  • 自定义默认导入别名?我们会把这个传下去。

第 2 步:收集你的工具

现在,让我们去获取我们需要的所有好东西。运行此命令来安装我们的依赖项:

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

第三步:准备你的秘方

在项目的根目录中创建一个名为 .env.local 的文件。这是我们保存秘密 FACEIO 应用 ID 的地方:

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

请记住将“your-super-secret-faceio-app-id”替换为您的实际 FACEIO 应用程序 ID。确保安全!

第四步:文件结构

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

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

第 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")],
}

构建仪表板的核心

第 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;

第 2 步:构建 EmployeeDashboard 组件

现在,让我们创建员工将看到的仪表板。创建 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;

第三步:将它们整合在一起

最后,让我们更新一下我们的主页,以展示我们的辛劳。更新 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>
  );
}

现在,让我们设置包裹整个应用程序的布局。添加此代码: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>
  )
}

这种布局就像房子的框架 - 它为您的整个应用程序提供结构。它包括带有您公司名称的标题、将显示仪表板的主要内容区域和页脚。另外,它还利用元数据设置了一些 SEO 魔法!

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

隐私设计

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

有意义的同意

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

最佳实践

  • 获得明确且适当的同意,尤其是对于未成年人。
  • 使同意请求易于查找和理解。
  • 避免自动注册和未经授权的注册。
  • 收集生物识别数据之前通知用户。
  • 遵守法律数据隐私要求。

数据安全

  • 删除帐户时删除用户数据。
  • 保持强有力的数据保留和处理实践。
  • 定期实施和审查安全保障措施。

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

FACEIO 集成的关键安全注意事项

安全设计

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

核心安全功能

  1. 拒绝弱 PIN

    • 防止 0000 或 1234 等弱 PIN。
    • 默认:否。
  2. 防止重复注册

    • 阻止用户多次注册。
    • 默认:否。
  3. 防止深度赝品

    • 检测并阻止欺骗尝试。
    • 默认:否。
  4. 禁止未成年人报名

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

    • 每次身份验证都需要 PIN 码。
    • 默认:是。
  6. 强制使用唯一的 PIN

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

    • 丢弃光线不佳或部分遮挡的面孔。
    • 默认:是。
  8. 拒绝丢失的标头

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

    • 限制特定域和国家。
    • 默认:否。
  10. 启用 Webhooks

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

更多详细信息,请参阅 FACEIO 安全最佳实践。

实际应用:您可以在哪里使用它?

现在我们已经构建了这个很棒的仪表板,您可能想知道,“我可以在现实世界中的哪里使用它?”好吧,让我告诉你,可能性是无限的!这里只是一些想法:

  1. 办公室管理:告别老式打孔卡!该系统可以彻底改变您跟踪出勤、控制对办公室不同区域的访问以及管理员工信息的方式。

  2. 安全系统:想象一个世界,您的办公室位于诺克斯堡,但没有任何麻烦。该面部识别系统可以成为强大安全协议的基石。

  3. 客户服务亭:想象一下 - 客户走到服务亭,它立即识别出他们,并提供个性化服务。这不再是科幻小说了!

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

恭喜你,技术奇才!您刚刚构建了一个具有面部身份验证功能的尖端员工仪表板。但为什么停在这里呢?该系统的优点在于其灵活性。以下是一些将其提升到新水平的想法:

  • 对重要更新实施实时通知
  • 为 HR 添加详细的报告功能
  • 与薪资或项目管理工具等其他系统集成

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

那么,你觉得怎么样?您准备好将您的工作场所带入未来了吗?尝试一下这个项目,让我知道进展如何。我很想听听您的经历、您添加的任何很酷的功能,或者您在此过程中面临的任何挑战。

祝您编码愉快,愿您的面部识别永远不会将您误认为是办公室植物!

以上是使用面部身份验证构建安全的员工仪表板:综合 Next.js 教程的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn