Skip to content

Commit

Permalink
feat: implemented global middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
manchenkoff committed Apr 1, 2024
1 parent 1c186b9 commit 6322fd3
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 19 deletions.
6 changes: 6 additions & 0 deletions src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,9 @@ declare module 'nuxt/schema' {
sanctum: Partial<SanctumModuleOptions>;
}
}

declare module '#app' {
interface PageMeta {
excludeFromSanctum?: boolean;
}
}
48 changes: 31 additions & 17 deletions src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import {
import { defu } from 'defu';
import type { SanctumModuleOptions } from './types';

export default defineNuxtModule<Partial<SanctumModuleOptions>>({
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};

export default defineNuxtModule<DeepPartial<SanctumModuleOptions>>({
meta: {
name: 'nuxt-auth-sanctum',
configKey: 'sanctum',
Expand Down Expand Up @@ -40,30 +44,40 @@ export default defineNuxtModule<Partial<SanctumModuleOptions>>({
onAuthOnly: '/login',
onGuestOnly: '/',
},
globalMiddleware: {
enabled: false,
allow404WithoutAuth: true,
},
},

setup(options, nuxt) {
const resolver = createResolver(import.meta.url);

const publicConfig = nuxt.options.runtimeConfig.public;
const userModuleConfig = publicConfig.sanctum;

nuxt.options.runtimeConfig.public.sanctum = defu(
userModuleConfig as any,
options
);
const runtimeConfigOverrides =
nuxt.options.runtimeConfig.public.sanctum;

addImportsDir(resolver.resolve('./runtime/composables'));
const sanctumConfig = defu(runtimeConfigOverrides as any, options);

addRouteMiddleware({
name: 'sanctum:auth',
path: resolver.resolve('./runtime/middleware/sanctum.auth'),
});
addRouteMiddleware({
name: 'sanctum:guest',
path: resolver.resolve('./runtime/middleware/sanctum.guest'),
});
nuxt.options.runtimeConfig.public.sanctum = sanctumConfig;

addPlugin(resolver.resolve('./runtime/plugin'));
addImportsDir(resolver.resolve('./runtime/composables'));

if (sanctumConfig.globalMiddleware.enabled) {
addRouteMiddleware({
name: 'sanctum:auth:global',
path: resolver.resolve('./runtime/middleware/sanctum.global'),
global: true,
});
} else {
addRouteMiddleware({
name: 'sanctum:auth',
path: resolver.resolve('./runtime/middleware/sanctum.auth'),
});
addRouteMiddleware({
name: 'sanctum:guest',
path: resolver.resolve('./runtime/middleware/sanctum.guest'),
});
}
},
});
5 changes: 3 additions & 2 deletions src/runtime/httpFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import {
useCookie,
useRequestEvent,
useRequestHeaders,
useRequestURL,
navigateTo,
useNuxtApp,
} from '#app';
import { useSanctumUser } from './composables/useSanctumUser';
import { useRequestURL } from 'nuxt/app';
import { useSanctumConfig } from './composables/useSanctumConfig';

type Headers = HeadersInit | undefined;
Expand Down Expand Up @@ -120,7 +120,8 @@ export function createHttpClient(): $Fetch {
if (
options.redirect.onLogout === false ||
options.redirect.onLogout === currentRoute.path ||
options.redirect.onAuthOnly === currentRoute.path
options.redirect.onAuthOnly === currentRoute.path ||
options.globalMiddleware.enabled === true
) {
return;
}
Expand Down
53 changes: 53 additions & 0 deletions src/runtime/middleware/sanctum.global.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { defineNuxtRouteMiddleware, navigateTo } from '#app';
import type { RouteLocationRaw } from 'vue-router';
import { useSanctumConfig } from '../composables/useSanctumConfig';
import { useSanctumAuth } from '../composables/useSanctumAuth';

export default defineNuxtRouteMiddleware((to) => {
const options = useSanctumConfig();
const { isAuthenticated } = useSanctumAuth();

const [homePage, loginPage] = [
options.redirect.onGuestOnly,
options.redirect.onAuthOnly,
];

if (homePage === false) {
throw new Error(
'You must define onGuestOnly route when using global middleware.'
);
}

if (loginPage === false) {
throw new Error(
'You must define onAuthOnly route when using global middleware.'
);
}

if (isAuthenticated.value === true) {
if (to.path === loginPage) {
return navigateTo(homePage, { replace: true });
}

return;
}

if (to.path === loginPage || to.meta.excludeFromSanctum === true) {
return;
}

if (
options.globalMiddleware.allow404WithoutAuth &&
to.matched.length === 0
) {
return;
}

const redirect: RouteLocationRaw = { path: loginPage };

if (options.redirect.keepRequestedRoute) {
redirect.query = { redirect: to.fullPath };
}

return navigateTo(redirect, { replace: true });
});
18 changes: 18 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,20 @@ export interface RedirectOptions {
onGuestOnly: string | false;
}

/**
* Configuration of the global application-wide middleware.
*/
export interface GlobalMiddlewareOptions {
/**
* Determines whether the global middleware is enabled.
*/
enabled: boolean;
/**
* Determines whether to allow 404 pages without authentication.
*/
allow404WithoutAuth: boolean;
}

/**
* Options to be passed to the plugin.
*/
Expand Down Expand Up @@ -110,4 +124,8 @@ export interface SanctumModuleOptions {
* Behavior of the plugin redirects when user is authenticated or not.
*/
redirect: RedirectOptions;
/**
* Behavior of the global middleware.
*/
globalMiddleware: GlobalMiddlewareOptions;
}

0 comments on commit 6322fd3

Please sign in to comment.