Nuxt3-Admin 登录系统开发(Nuxt-auth)

我们可以根据自己的项目需求,来定制我们自己的授权登录系统。这里我推荐使用Nuxt-auth,一个包装了 React的 Next-auth的开源项目授权框架。Nuxt3版本的使用的是Sidebase

安装

npm i -D @sidebase/nuxt-auth

项目配置

Nuxt auth 新版本提供了 localauthjs 两种模式
local 模式,提供全自定义授权规则,需要自己开发相应的授权接口,官方提供的local 模式 的 参考源码,本文将主要介绍Nuxt-auth自带的 authjs 模式

nuxt.config.ts

export default defineNuxtConfig({
    modules: ['@sidebase/nuxt-auth'],
    auth: {
        provider: {
            type: 'authjs'
        },
        session: {
          // Whether to refresh the session every time the browser window is refocused.
          enableRefreshOnWindowFocus: true,
            // Whether to refresh the session every `X` milliseconds. Set this to `false` to turn it off.             The session will only be refreshed if a session already exists.
          enableRefreshPeriodically: 5000,
        },
        globalAppMiddleware: {
          isEnabled: true, // 自动开启全局鉴权,如果没有登录自动跳到登录页面 
        },
   }
})

新增 server/api/auth/[...].ts

// file: ~/server/api/auth/[...].ts
import CredentialsProvider from "next-auth/providers/credentials";
import { NuxtAuthHandler } from "#auth";

export default NuxtAuthHandler({
  // A secret string you define, to ensure correct encryption
  secret: useRuntimeConfig().private.NUXT_SECRET,
  providers: [
    // @ts-expect-error You need to use .default here for it to work during SSR. May be fixed via Vite at some point
    CredentialsProvider.default({
      // The name to display on the sign in form (e.g. 'Sign in with...')
      name: "Credentials",
      // The credentials is used to generate a suitable form on the sign in page.
      // You can specify whatever fields you are expecting to be submitted.
      // e.g. domain, username, password, 2FA token, etc.
      // You can pass any HTML attribute to the <input> tag through the object.
      credentials: {
        username: {
          label: "Username",
          type: "text",
          placeholder: "(hint: jsmith)",
        },
        password: {
          label: "Password",
          type: "password",
          placeholder: "(hint: hunter2)",
        },
      },
      authorize(credentials: any) {
        // You need to provide your own logic here that takes the credentials
        // submitted and returns either a object representing a user or value
        // that is false/null if the credentials are invalid.
        // NOTE: THE BELOW LOGIC IS NOT SAFE OR PROPER FOR AUTHENTICATION!

        const user = {
          id: "1",
          name: "J Smith",
          username: "admin",
          password: "admin",
        };

        if (
          credentials?.username === user.username &&
          credentials?.password === user.password
        ) {
          // Any object returned will be saved in `user` property of the JWT
          return user;
        } else {
          // eslint-disable-next-line no-console
          console.error(
            "Warning: Malicious login attempt registered, bad credentials provided"
          );

          // If you return null then an error will be displayed advising the user to check their details.
          throw createError({
            statusMessage: "账户密码错误",
            statusCode: 302,
          });

          // You can also Reject this callback with an Error thus the user will be sent to the error page with the error message as a query parameter
        }
      },
    }),
  ],
  pages: {
    signIn: "/login", 
  },
});

注意
pages : {}
如果系统需要自定义授权登录页,需要重写系统默认的page.signIn的值。

新增首页 pages/index.vue

<template>
  <div>
    <section>Login Dashboard</section>
    <section>{{ session }}</section>
    <section>
      <el-button @click="signOut"> Sign out </el-button>
    </section>
  </div>
</template>

<script setup lang="ts">
const {
  status,
  data,
  lastRefreshedAt,
  getCsrfToken,
  getProviders,
  getSession,
  signIn,
  signOut
} = useAuth()
const session = await getSession()
</script>

访问 http://localhost:3000/,系统将自动自动检测session是否存在,如果没有或已过期,将会自动重定向地址到 http://localhost:3000/login,这时候我们新增登录代码到 login.vue 页面。

definePageMeta({
  auth: {
    unauthenticatedOnly: true,
    navigateAuthenticatedTo: '/'
  }
})

const {
  status,
  data,
  lastRefreshedAt,
  getCsrfToken,
  getProviders,
  getSession,
  signIn,
  signOut
} = useAuth()

const state = reactive({
  showPassword: false,
  form: {
    username: 'admin',
    password: 'admin'
  }
})
const form = ref(state.form)

const logIn = async (e) => {
  e.preventDefault()
  const { error, url } = await signIn('credentials', {
    callbackUrl: '/',
    redirect: false,
    username: state.form.username,
    password: state.form.password
  })
  if (error) {
    ElMessage.error(error)
  } else {
    // No error, continue with the sign in, e.g., by following the returned redirect:
    return navigateTo('/', { replace: true })
  }
}

绑定登录事件

     <div class="w-full text-center">
        <el-button
            class="w-[90%]"
            round
            type="primary"
            size="large"
            @click="logIn"
          >Sign In</el-button>
       </div>

完成之后,刷新页面,输入账号:admin, 密码:admin。如果不会将会拦截并提示账号密码错误,点击登录将跳转到 http://localhost:3000/,页面效果如下,我们可以使用getSession 方法来获取用户登录的信息。

image.png

点击 Sign out 系统将自动清除session并且返回到登录页面。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。