Nuxt3-Admin 登錄系統(tǒng)開發(fā)(Nuxt-auth)

我們可以根據(jù)自己的項(xiàng)目需求,來定制我們自己的授權(quán)登錄系統(tǒng)。這里我推薦使用Nuxt-auth,一個(gè)包裝了 React的 Next-auth的開源項(xiàng)目授權(quán)框架。Nuxt3版本的使用的是Sidebase

安裝

npm i -D @sidebase/nuxt-auth

項(xiàng)目配置

Nuxt auth 新版本提供了 localauthjs 兩種模式
local 模式,提供全自定義授權(quán)規(guī)則,需要自己開發(fā)相應(yīng)的授權(quán)接口,官方提供的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, // 自動(dòng)開啟全局鑒權(quán),如果沒有登錄自動(dòng)跳到登錄頁(yè)面 
        },
   }
})

新增 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: "賬戶密碼錯(cuò)誤",
            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 : {}
如果系統(tǒng)需要自定義授權(quán)登錄頁(yè),需要重寫系統(tǒng)默認(rèn)的page.signIn的值。

新增首頁(yè) 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/,系統(tǒng)將自動(dòng)自動(dòng)檢測(cè)session是否存在,如果沒有或已過期,將會(huì)自動(dòng)重定向地址到 http://localhost:3000/login,這時(shí)候我們新增登錄代碼到 login.vue 頁(yè)面。

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>

完成之后,刷新頁(yè)面,輸入賬號(hào):admin, 密碼:admin。如果不會(huì)將會(huì)攔截并提示賬號(hào)密碼錯(cuò)誤,點(diǎn)擊登錄將跳轉(zhuǎn)到 http://localhost:3000/,頁(yè)面效果如下,我們可以使用getSession 方法來獲取用戶登錄的信息。

image.png

點(diǎn)擊 Sign out 系統(tǒng)將自動(dòng)清除session并且返回到登錄頁(yè)面。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容