【Next.js 项目实战系列】06-身份验证

原文链接

优快云 的排版/样式可能有问题,去我的博客查看原文系列吧,觉得有用的话,给我的点个star,关注一下吧 

上一篇【Next.js 项目实战系列】05-删除 Issue

身份验证

配置 Next-Auth

本节代码链接

具体内容可参考Authentication

Refactor NavBar

本节代码链接

# /app/Navbar.tsx

"use client";
import { Avatar, Box, DropdownMenu, Flex, Text } from "@radix-ui/themes";
import classNames from "classnames";
import { useSession } from "next-auth/react";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { AiFillBug } from "react-icons/ai";
import { Skeleton } from "@/app/components";

const NavBar = () => {
  return (
    <nav className="border-b mb-5 px-5 py-5">
      <Flex align="center" justify="between">
        <NavLinks />
        <Avator />
      </Flex>
    </nav>
  );
};

export default NavBar;

const links = [
  { label: <AiFillBug />, href: "/" },
  { label: "DashBoard", href: "/dashboard" },
  { label: "Issues", href: "/issues" },
];

const NavLinks = () => {
  const currentPath = usePathname();

  return (
    <ul className="flex gap-6 items-center">
      {links.map((link) => (
        <li key={link.href}>
          <Link
            className={classNames({
              "text-zinc-900": link.href === currentPath,
              "text-zinc-500": link.href !== currentPath,
              "hover:text-zinc-800 transaition-colors": true,
            })}
            href={link.href}
          >
            {link.label}
          </Link>
        </li>
      ))}
    </ul>
  );
};

const Avator = () => {
  const { status, data: session } = useSession();

  if (status === "loading") return <Skeleton width="3rem" />;
  if (status === "unauthenticated")
    return (
      <Link
        className="text-zinc-500 hover:text-zinc-800 transaition-colors"
        href="/api/auth/signin"
      >
        Sign In
      </Link>
    );

  return (
    <Box>
      <DropdownMenu.Root>
        <DropdownMenu.Trigger>
          <Avatar
            src={session!.user!.image!}
            fallback="?"
            size="2"
            radius="full"
            className="cursor-pointer"
            referrerPolicy="no-referrer"
          />
        </DropdownMenu.Trigger>
        <DropdownMenu.Content>
          <DropdownMenu.Label>
            <Text size="2">{session!.user!.email}</Text>
          </DropdownMenu.Label>
          <DropdownMenu.Item>
            <Link href="/api/auth/signout">Sign Out</Link>
          </DropdownMenu.Item>
        </DropdownMenu.Content>
      </DropdownMenu.Root>
    </Box>
  );
};

Secure the Application

本节代码链接

AuthOptions

首先,我们应该将 AuthOptions 放到一个单独的文件里备用

# /app/api/auth/AuthOptions.tsx

import prisma from "@/prisma/client";
import { PrismaAdapter } from "@next-auth/prisma-adapter";
import { NextAuthOptions } from "next-auth";
import Github from "next-auth/providers/github";

const authOptions: NextAuthOptions = {
  adapter: PrismaAdapter(prisma),
  providers: [
    Github({
      clientId: process.env.GITHUB_CLIENT_ID!,
      clientSecret: process.env.GITHUB_CLIENT_SECRET!,
    }),
  ],
};

export default authOptions;

保护 API 与 页面

在除 GET 外的所有 API 中都应该加上确认是否有 session 的验证

# /app/api/issues/[id]/route.tsx

  ...
+ import { getServerSession } from "next-auth";
+ import authOptions from "@/app/api/auth/AuthOptions";

  export async function PATCH(
    request: NextRequest,
    { params }: { params: { id: string } }
  ) {
+   const session = await getServerSession(authOptions);
+   if (!session) return NextResponse.json({}, { status: 401 });
    ...
  }

  export async function DELETE(
    request: NextRequest,
    { params }: { params: { id: string } }
  ) {
+   const session = await getServerSession(authOptions);
+   if (!session) return NextResponse.json({}, { status: 401 })
    ...
  }

同样,我们应该在一些页面将删除修改的组件隐藏

# /app/issues/[id]/page.tsx

+ import { getServerSession } from "next-auth";
+ import authOptions from "@/app/api/auth/AuthOptions";

  interface Props {
    params: { id: string };
  }
  const IssueDeatilPage = async ({ params }: Props) => {
+   const session = await getServerSession(authOptions);

    const issue = await prisma.issue.findUnique({
      where: { id: parseInt(params.id) },
    });

    if (!issue) notFound();

    return (
      <Grid columns={{ initial: "1", sm: "5" }} gap="5">
        <Box className="md:col-span-4">
          <IssueDetails issue={issue} />
        </Box>
+       {session && (
          <Box>
            <Flex direction="column" gap="3">
              <EditIssueButton issueId={issue.id} />
              <DeleteIssueButton issueId={issue.id} />
            </Flex>
          </Box>
        )}
      </Grid>
    );
  };
  export default IssueDeatilPage;

MiddleWare

同样我们可以使用 MiddleWare 来保护路由

export { default } from "next-auth/middleware";

export const config = {
  matcher: ["/issues/new", "/issues/edit/:id+"],
};

优快云 的排版/样式可能有问题,去我的博客查看原文系列吧,觉得有用的话,给我的点个star,关注一下吧 

 下一篇讲分配 Issue 给用户

下一篇【Next.js 项目实战系列】07-分配 Issue 给用户

内容概要:本文深入探讨了折扣店快消品定价的研究,涵盖快消品与折扣店行业的概述、定价影响因素、定价策略、定价方法、定价技巧及案例分析。快消品行业涉及日常生活用品、食品、饮料等,具有高频次和重复购买的特点。折扣店市场规模不断扩大,主要参与者包括赵一鸣、好特卖等。影响定价的因素包括成本(生产、库存、物流)、市场需求(规模、购买力、需求弹性)、竞争(对手定价策略、市场份额)、产品特性(差异化、品牌形象)、渠道与分销成本、政府政策等。定价策略分为成本导向(成本加成、目标收益)、需求导向(理解价值、需求差异)和竞争导向(随行就市、投标定价)。定价方法包括市场调研、成本加成、竞争比较和价值定价。定价技巧涵盖高价撇脂、渗透定价、价格歧视和捆绑定价。最后通过好特卖、嗨特购、零食很忙的案例分析,展示了不同折扣店的定价策略及其效果。 适合人群:从事快消品行业、折扣店运营的管理人员及对定价策略感兴趣的商业人士。 使用场景及目标:①帮助折扣店管理者了解定价的基本理论和实际操作方法;②为快消品企业提供定价决策支持,优化定价策略;③通过案例分析,提供实际操作中的经验和教训。 其他说明:折扣店在制定快消品定价时,应综合考虑多种因素,灵活运用不同的定价策略和技巧,以应对市场变化,提升竞争力。建议企业定期监控市场动态,分析消费者反馈,不断优化定价方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值