使用 Next-auth 给 Next.js 应用添加鉴权与认证

发表于 1年以前  | 总阅读数:4645 次

前言

在系统中要实现身份验证是一件比较麻烦的事情,比如集成邮箱登录,手机号登录,以及其他第三方登录等,但是有了NextAuth.js[1],一切就变得简单。正如官网说的添加身份验证,只要几分钟就可以实现。在上一篇文章中,我们使用 prisma 和 Next.js,创建了一个视频网站,但我们还没有实现用户的注册与登录,本文将继续开发视频网站,实现邮箱登录、 Github 授权登录,以及密码登录。那么,一起来看看吧!

文中涉及代码全部托管在 GitHub 仓库[2]中。

Next.js 应用接入 NextAuth

NextAuth.js 是 Next.js 应用程序的完整开源身份验证解决方案,专门为 Next.js 设计,NextAuth 的特点:

  1. 灵活且易于使用,支持 OAuth1.0 OAuth2.0 和 OpenId 链接;
  2. 灵活数据管理,可以不使用数据库,也可以选择使用 MySQL, MariaDB, Postgres, SQL Server, MongoDB 以及 SQLite。
  3. 默认安全,默认 Cookie 机制,可开启 JSON Web Token;
  4. NextAuth 推进无密码的登录机制
  5. 支持 serverless 部署

安装

首先我们使用 yarn 安装 NextAuth.js

yarn add next-auth

授权 api

要通过 NextAuth.js 获得授权, 需要先创建一个pages/api/auth/[...nextauth].ts 文件,它包含了所有全局 NextAuth.js 配置。

import NextAuth from "next-auth"
import GithubProvider from "next-auth/providers/github"

export const authOptions = {
  // 在 providers 中配置更多授权服务
  providers: [
    GithubProvider({
      clientId: process.env.GITHUB_ID,
      clientSecret: process.env.GITHUB_SECRET,
    }),
    // ...add more providers here
  ],
}

export default NextAuth(authOptions)

我们先添加一种授权登录方式,首先是使用 GITHUB 登录

Github 授权流程

Github 授权流程

我之前使用过 Nodejs 集成 Github OAuth 流程,大致要分为以上 6 个步骤,需要写不少代码和接口,但使用了 Next-auth.js, 就可以非常轻松的集成到我们的应用中,几乎不用写代码。

注册 GitHub OAuth Application

环境变量可以在 Github 开发者中申请,点击注册一个新 OAuth Application:

注册 GitHub OAuth Application

回调地址填http://localhost:3000/api/auth/callback/github

地址可以先填开发环境地址,待上前线前可以修改为正式域名地址,或者开发环境和生产环境单独申请。

复制GITHUB_ID

注册成功过后,在页面上复制 Client IDClient secrets.env 文件中


GITHUB_ID=你注册的 GITHUB_ID
GITHUB_SECRET=你注册的 GITHUB_SECRET

配置 pages/_app.ts

为了让所有页面能够获取到 Session, 我们需要在 pages/_app.ts 外层加SessionProvider

import { SessionProvider } from "next-auth/react"
export default function App({
  Component,
  pageProps: { session, ...pageProps },
}) {
  return (
    <SessionProvider session={session}>
      <Component {...pageProps} />
    </SessionProvider>
  )
}

客户端获取登录信息

然后我们就可以创建一个登录组件components/login-btn.tsx


import { useSession, signIn, signOut } from "next-auth/react"

export default function Component() {
  const { data: session } = useSession()
  if (session) {
    return (
    <>
       <span className="mr-1">session.user.email</span>
        <button onClick={() => signOut()}>登出</button>
      </>
    )
  }
  return (
      <button onClick={() => signIn()}>登录</button>
  )
}

在首页引用登录组件,就可以使用 GITHUB 来登录了,一起看来看看效果吧。

GITHUB 授权登录成功

注意:有时候会因为网络问题, GitHub 无法登录。我们可以设置 NextAuthOptionsdebugtrue,会在控制台看到以下错误信息:

GITHUB 授权登录超时

原因是访问 GitHub 需要代理,需要将代理设置为全局模式,并且设置请求 timeout 时间,将超时时间延长。

GithubProvider({
  clientId: process.env.GITHUB_ID,
  clientSecret: process.env.GITHUB_SECRET,
  httpOptions: {
    timeout: 50000,
  },
}),

登录成功后,我们看下页面打印出来的数据,包含 GitHub 登录账户的基本信息。

通过控制台我们可以发现,useSession 其实就是访问了http://localhost:3000/api/auth/session接口获取信息,这部分是在客户端实现的,那么在服务端可以获取到用户授权信息吗?

SSR 页面获取登录信息

回到我们要开发的视频网站,还缺少个人视频管理页面,这个页面必须是当前登录用户才能访问,没授权,是不能访问的。

新建pages/me.tsx,用于用户管理自己的视频。


import { authOptions } from "@/pages/api/auth/[...nextauth]";
import { unstable_getServerSession } from "next-auth/next";

export default function Page() {
  return <div>个人中心</div>;
}

export async function getServerSideProps(context) {
  const session = await unstable_getServerSession(
    context.req,
    context.res,
    authOptions
  );

  if (!session) {
    return {
      redirect: {
        destination: "/",
        permanent: false,
      },
    };
  }

  return {
    props: {
      session,
    },
  };
}

此时访问 http://localhost:3000/me 若没有授权登录,则将自动跳转到首页。

看打印出的session值,其中没有 Userid,而我们的视频表关联的是 UserId ,因此我们需要将用户的授权信息同步到我们的数据表中。

Prisma 适配

next-auth.js 为 prisma 提供了适配器,我们只需要按官网给出的步骤依次执行

1 . 安装 prisma 适配器

yarn add @next-auth/prisma-adapter

2 . 在 NextAuth.js 配置 prisma 适配器

import NextAuth, { NextAuthOptions } from "next-auth";
import EmailProvider from "next-auth/providers/email";
import GithubProvider from "next-auth/providers/github";
import prisma from "@/lib/prisma";
+ import { PrismaAdapter } from "@next-auth/prisma-adapter";

export const authOptions: NextAuthOptions = {
  //debug: true,
+  adapter: PrismaAdapter(prisma),
  providers: [
    // OAuth authentication providers...
    GithubProvider({
      clientId: process.env.GITHUB_ID,
      clientSecret: process.env.GITHUB_SECRET,
    }),
  ],
+  callbacks: {
+    session: async ({ session, token, user }) => {
+      if (session?.user) {
+        session.user.id = user.id;
+      }
+      return session;
+    },
+  },
};

export default NextAuth(authOptions);

添加 callbacks 函数,将 user``id 赋值给 session 中的 user``id,方便后面接口中可以直接获取用户 id

3 . 添加 prisma Schema 中添加模型

model Account {
  id                 String  @id @default(cuid())
  userId             String
  type               String
  provider           String
  providerAccountId  String
  refresh_token      String?  @db.Text
  access_token       String?  @db.Text
  expires_at         Int?
  token_type         String?
  scope              String?
  id_token           String?  @db.Text
  session_state      String?

  user User @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([provider, providerAccountId])
}

model Session {
  id           String   @id @default(cuid())
  sessionToken String   @unique
  userId       String
  expires      DateTime
  user         User     @relation(fields: [userId], references: [id], onDelete: Cascade)
}

model User {
  id            String    @id @default(cuid())
  name          String?
  email         String?   @unique
  emailVerified DateTime?
  image         String?
  accounts      Account[]
  sessions      Session[]
}

model VerificationToken {
  identifier String
  token      String   @unique
  expires    DateTime

  @@unique([identifier, token])
}

当我们将这些模型粘贴到 Schema 后,会看到 VSCode 中有错误提示

Prisma Schema 错误提示

原因是我们之前设计的用户表 idInt 类型,跟当前的 Sring 类型不匹配,解决办法是将 Int 改成 String,最好的做法是所有表中的 id 类型改成统一。

3 . 迁移 Schema,生成表

npx prisma migrate dev

执行完成后,我们刷新页面,重新登录页面,来看下效果

session 包含 userId

session 中已经有了 id,这里我测试了下,将我 Github 默认邮箱改成另一个,也不会影响注册用户表中的信息,因为 Account 表中的唯一值是provider + providerAccountId

服务端渲染我的视频

session 中可以获取 userId,那么我们就可以在 getServerSideProps 获取当前用户的视频了。

export async function getServerSideProps(context) {
  const session = await unstable_getServerSession(
    context.req,
    context.res,
    authOptions
  );

  if (!session) {
    return {
      redirect: {
        destination: "/",
        permanent: false,
      },
    };
  }

  const data = await prisma.video.findMany({
    where: {
      authorId: session.user.id,
    },
    include: { author: true },
  });

  return {
    props: {
      session,
      data: makeSerializable(data),
    },
  };
}

这里有个问题,当我们获取 user.id 的时候, typescript 会提示错误,因为默认的 User 类型中是不包含 id

TS 校验提示

所以我们需要重写下 next-auth 中 Session 的接口,新建 types/next-auth.d.ts 输入以下代码,就可以继承默认的 Session TS 类型接口了


import NextAuth, { DefaultSession } from "next-auth";

declare module "next-auth" {
  interface Session {
    user: {
      id: string;
    } & DefaultSession["user"];
  }
}

添加完成后,在页面中使用 useSession, unstable_getServerSession 等获取到的 Session 不会 TS 类型报错了。

邮箱授权登录

有了 Github 授权登录,并且关联了数据库,那要加上邮箱授权登录,便是轻而易举。

首先安装 nodemailer,用于 Node.js 发送邮件

yarn add nodemailer

然后在 pages/api/auth/[...nextauth].ts引入并且配置 EmailProvider

import EmailProvider from "next-auth/providers/email";

export const authOptions: NextAuthOptions = {
  //debug: true,
  adapter: PrismaAdapter(prisma),
  providers: [
    EmailProvider({
      server: process.env.EMAIL_SERVER,
      from: process.env.EMAIL_FROM,
      //maxAge: 24 * 60 * 60, // 设置邮箱链接失效时间,默认24小时
    }),
    // OAuth authentication providers...
    GithubProvider({
      clientId: process.env.GITHUB_ID,
      clientSecret: process.env.GITHUB_SECRET,
    }),
  ],
  // ...
}

然后在 .env 文件中配置环境变量

EMAIL_SERVER=smtp://username:password@smtp.example.com:587
EMAIL_FROM=NextAuth <noreply@example.com>

这里的 EMAIL_SERVER 中的 username 就是发件邮箱的账号,而 password 并不是邮箱密码,需要在邮箱设置中开启,这里我以 163 邮箱为例

163 邮箱设置

登录邮箱后,在邮箱设置中开启 POP3/SMTP/IMAP 服务,点击开启,这里会需要短信验证,验证会有一个授权密码,这个授权码就是 password, 最后面的服务地址和端口需要根据你最终选择的 POP3/SMTP/IMAP 服务来配置,下图是 126 邮箱的服务器配置。

126邮箱服务器信息

配置完成后刷新浏览器就可以使用邮箱来完成登录了,登录的邮箱账号不能是发送邮件服务的账号,比如我设置的是发送邮件服务是 163 邮箱,那我注册的时候使用 QQ 邮箱。

使用邮箱登录界面

点击 “sign in with Email” 后,你就会收到如下邮件,在邮箱中点击链接,便会自动授权登录成功。

收到默认邮件模板

登录成功后的,Session 中的信息跟我 Github 账号登录的信息是一致的,因为在数据库中,邮箱地址是唯一值。

邮箱登录成功

更改邮件模板

有些同学会说,发送的邮件主题太丑了,我们可以定制吗?

放心,Next-auth 帮我们考虑到了 , EmailProvider 支持自定义模板,我们需要配置 sendVerificationRequest 函数

import EmailProvider from "next-auth/providers/email";
...
providers: [
  EmailProvider({
    server: process.env.EMAIL_SERVER,
    from: process.env.EMAIL_FROM,
    sendVerificationRequest({
      identifier: email,
      url,
      provider: { server, from },
    }) {
      /* your function */
    },
  }),
]

邮件模板函数可能会很大,可以将 sendVerificationRequest 提取为单独文件,然后再引入;


import { createTransport } from "nodemailer";
import { SendVerificationRequestParams } from "next-auth/providers/email";
import { Theme } from "next-auth";

export async function sendVerificationRequest(
  params: SendVerificationRequestParams
) {
  const { identifier, url, provider, theme } = params;
  const { host } = new URL(url);
  const transport = createTransport(provider.server);
  const result = await transport.sendMail({
    to: identifier,
    from: provider.from,
    subject: `${host} 注册认证`,
    text: text({ url, host }),
    html: html({ url, host, theme }),
  });
  const failed = result.rejected.concat(result.pending).filter(Boolean);
  if (failed.length) {
    throw new Error(`Email(s) (${failed.join(", ")}) could not be sent`);
  }
}

/**
 *使用HTML body 代替正文内容
 */
function html(params: { url: string; host: string; theme: Theme }) {
  const { url, host, theme } = params;
  //由于使用
  const escapedHost = host.replace(/\./g, "&#8203;.");

  return `
<body>
  <div style="background:#f2f5f7;display: flex;justify-content: center;align-items: center; height:200px">欢迎注册${escapedHost},点击<a href="${url}" target="_blank">登录</a></div>
</body>
`;
}

/** 不支持HTML 的邮件客户端会显示下面的文本信息 */
function text({ url, host }: { url: string; host: string }) {
  return `欢迎注册 ${host}\n点击${url}登录\n\n`;
}

当然这里我简化了模板代码, 在真实场景中,我们也可以替换 HTML 文件来实现。

密码登录

密码登录 Next-auth 是不鼓励使用的,因为与密码相关的固有安全风险以及与支持用户名和密码具有额外复杂性。

使用密码登录需要使用 CredentialsProvider

import NextAuth, { NextAuthOptions } from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import prisma from "@/lib/prisma";
import { PrismaAdapter } from "@next-auth/prisma-adapter";

export const authOptions: NextAuthOptions = {
  //debug: true,
  adapter: PrismaAdapter(prisma),
  providers: [
    CredentialsProvider({
      // 登录按钮显示 (e.g. "Sign in with Credentials")
      name: "Credentials",
      // credentials 用于配置登录页面的表单
      credentials: {
       email: {
          label: "邮箱",
          type: "text",
          placeholder: "请输入邮箱",
        },
        password: {
          label: "密码",
          type: "password",
          placeholder: "请输入密码",
        },
      },
      async authorize(credentials, req) {
        console.log(credentials);
        // TODO
        // const maybeUser= await prisma.user.findFirst({where:{
        //   email: credentials.email,
        //  }})

        // 根据 credentials 我们查询数据库中的信息
        const user = {
          id: "1",
          name: "xiaoma",
          email: "xiaoma@example.com",
        };

        if (user) {
          // 返回的对象将保存才JWT 的用户属性中
          return user;
        } else {
          // 如果返回null,则会显示一个错误,建议用户检查其详细信息。
          return null;
          // 跳转到错误页面,并且携带错误信息 http://localhost:3000/api/auth/error?error=用户名或密码错误
          //throw new Error("用户名或密码错误");
        }
      },
    }),
  ],
  session: {
    strategy: "jwt",
  },
  jwt: {
    secret: "test",
  },
  callbacks: {
    async jwt({ token, user, account, profile, isNewUser }) {
      if (user) {
        token.id = user.id;
      }
      return token;
    },
    session: async ({ session, token, user }) => {
      if (session?.user && token) {
        session.user.id = token.id as string;
      }
      return session;
    },
  },
};

export default NextAuth(authOptions);

上面代码中,我们首先需要开启 JWT 模式,在 authorize 方法中我们可以根据用户所填的表单信息进行数据库查询,由于我们的数据库中没有密码字段,所以上面的代码中直接返回了一个固定 user 信息,那真实的流程应该是:邮箱登录——> 设置密码——>密码登录

实现效果:

密码登录界面

自定义登录页面

有同学会说,这个页面怎么这么丑,既有中文也有英文呢?显然在国内是不合适的, Next-auth 帮我们考虑到了,它支持配置自定义页面。

pages/api/auth/[...nextauth].ts 添加 pages 参数就可以实现自定义

pages: {
    signIn: '/auth/login',
},

自定义界面 ,可配置 signInsignOuterrorverifyRequestnewUser,在这里,我们只配置登录页面。

登录页面的 dom 结构可以参考默认的 dom 结构, 直接复制出来就可以了。

查看默认登录界面dom

我们可以看到 form 表单中,有个默认的隐藏域,提交了 csrfToken 的值,那么这个值该如何获取呢?


import { getCsrfToken } from "next-auth/react"

export default function SignIn({ csrfToken }) {
  return (
    <form method="post" action="/api/auth/signin/email">
      <input name="csrfToken" type="hidden" defaultValue={csrfToken} />
      <label>
        Email address
        <input type="email" id="email" name="email" />
      </label>
      <button type="submit">Sign in with Email</button>
    </form>
  )
}

export async function getServerSideProps(context) {
  const csrfToken = await getCsrfToken(context)
  return {
    props: { csrfToken },
  }
}

csrfToken 可以通过导出的 getCsrfToken 方法获取,并且赋值给隐藏域 csrfToken,在提交表单的时候,就会自动提交该值。

最后我们来看下实现效果:

自定义登录页面

是不是有国内 App 的风格了呢?这里我使用了 @chakra-ui/react 实现代码也很简单,这里就不贴了,感兴趣的小伙伴可以直接看我的 github。

还有些小伙伴会问,登录页面能否能做成弹窗呢?当然也可以。

import { signIn } from "next-auth/react";

export default function Login() {
  return (
      <button
        onClick={() =>
          signIn("credentials", {
            email: "xiaoma@example.com",
            password: "1234",
          })
        }
      >
        登录
      </button>
  );
}

界面我们可以完全自定义,写成一个组件,只需要调用内置的 signIn 方法即可,它会帮我们自动添加 csrfToken 值。

小结

思考:国内 app 使用手机短信验证登录已经成为主流,结合前面的文章,我们该如何修改表,使用哪个 providers 来实现?相信你已经有了答案。

本文通过 NextAuth.js, 给我们的视频网站实现了邮箱登录、 Github 授权登录,以及密码登录。你学会了吗?若对你有帮助,记得帮我点赞。

后续

接下来我将继续分享 Next.js 相关的实战文章,欢迎各位关注我的《Next.js 全栈开发实战》 专栏。

  • 使用 React query 给 Next.js 应用全局状态管理
  • 使用 i18next 实现 Next.js 应用国际化
  • 使用 Playwright 进行 Next.js 应用的端到端测试
  • 使用 Github actions 给 Next.js 应用创建 CI/CD
  • 使用 Docker 部署 Next.js 应用
  • 将 Next.js 应用部署到腾讯云 serverless

你对哪块内容比较感兴趣呢?欢迎在评论区留言,感谢您的阅读。

[1]Next-auth.js: https://next-auth.js.org/

[2]GitHub 仓库代码: https://github.com/maqi1520/next-prisma-video-app

本文由哈喽比特于1年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/Juu2nh9K3jDjaKkkpw4brw

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:1年以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:1年以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:1年以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:1年以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:1年以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:1年以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:1年以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:1年以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:1年以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:1年以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:1年以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:1年以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:1年以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:1年以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:1年以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:1年以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:1年以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:1年以前  |  398次阅读  |  详细内容 »
 相关文章
Android插件化方案 5年以前  |  237267次阅读
vscode超好用的代码书签插件Bookmarks 2年以前  |  8105次阅读
 目录