From f48294ad4e04e1ede6ea631951d783e520b9cacd Mon Sep 17 00:00:00 2001 From: Kabin Date: Mon, 9 Dec 2024 12:31:21 +0545 Subject: [PATCH] feat: implement feature to verify role while log in --- packages/vue-user/src/store.ts | 5 +++ packages/vue-user/src/supertokens/helper.ts | 49 +++++++++++++++++++++ packages/vue-user/src/supertokens/index.ts | 2 + packages/vue-user/src/types/config.ts | 1 + packages/vue-user/src/views/Login.vue | 9 +++- 5 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 packages/vue-user/src/supertokens/helper.ts diff --git a/packages/vue-user/src/store.ts b/packages/vue-user/src/store.ts index ce02d28b3..a05dc9d0b 100644 --- a/packages/vue-user/src/store.ts +++ b/packages/vue-user/src/store.ts @@ -51,6 +51,10 @@ const useUserStore = defineStore("user", () => { "sFrontToken=; Max-Age=0; path=/; domain=" + location.hostname; }); + removeUser(); + }; + + const removeUser = () => { localStorage.removeItem(USER_KEY); }; @@ -83,6 +87,7 @@ const useUserStore = defineStore("user", () => { getUser, login, logout, + removeUser, resetPassword, requestPasswordReset, setUser, diff --git a/packages/vue-user/src/supertokens/helper.ts b/packages/vue-user/src/supertokens/helper.ts new file mode 100644 index 000000000..5aa0296ac --- /dev/null +++ b/packages/vue-user/src/supertokens/helper.ts @@ -0,0 +1,49 @@ +import Session from "supertokens-web-js/recipe/session"; +import { UserRoleClaim } from "supertokens-web-js/recipe/userroles"; + +import logout from "./logout"; +import useUserStore from "../store"; + +export async function verifySessionRoles(claims: string[]): Promise { + if (await Session.doesSessionExist()) { + let errorCount = 0; + + const validationErrors = await Session.validateClaims({ + overrideGlobalClaimValidators: (globalValidators) => { + const validators = claims.map((claim) => + UserRoleClaim.validators.includes(claim), + ); + + return [...globalValidators, ...validators]; + }, + }); + + if (validationErrors.length === 0) { + return true; + } + + for (const err of validationErrors) { + if (err.validatorId === UserRoleClaim.id) { + // user roles claim check failed + errorCount += 1; + } else { + // some other claim check failed (from the global validators list) + } + } + + if (errorCount < claims.length) { + // some user roles claim check passed + return true; + } else { + const userStore = useUserStore(); + + const { removeUser } = userStore; + // all user roles claim check failed + removeUser(); + await logout(); + } + } + // either a session does not exist, or one of the validators failed. + // so we do not allow access to this page. + return false; +} diff --git a/packages/vue-user/src/supertokens/index.ts b/packages/vue-user/src/supertokens/index.ts index d89b574d6..067315c67 100644 --- a/packages/vue-user/src/supertokens/index.ts +++ b/packages/vue-user/src/supertokens/index.ts @@ -4,6 +4,7 @@ import Session from "supertokens-web-js/recipe/session"; import ThirdPartyEmailPassword from "supertokens-web-js/recipe/thirdpartyemailpassword"; import googleSignIn from "./google-signin"; +import { verifySessionRoles } from "./helper"; import login from "./login"; import logout from "./logout"; import requestPasswordReset from "./request-password-reset"; @@ -66,4 +67,5 @@ export { resetPassword, signup, verifyEmail, + verifySessionRoles, }; diff --git a/packages/vue-user/src/types/config.ts b/packages/vue-user/src/types/config.ts index 8f1d58bcf..201dc6239 100644 --- a/packages/vue-user/src/types/config.ts +++ b/packages/vue-user/src/types/config.ts @@ -19,6 +19,7 @@ interface DzangolabVueUserConfig { }; routes?: RouteOverrides; socialLogins?: string[]; + supportedRoles?: string[]; } declare module "@dzangolab/vue3-config" { diff --git a/packages/vue-user/src/views/Login.vue b/packages/vue-user/src/views/Login.vue index 3fa2e5978..19127737b 100644 --- a/packages/vue-user/src/views/Login.vue +++ b/packages/vue-user/src/views/Login.vue @@ -46,6 +46,7 @@ import GoogleLogin from "../components/GoogleLogin.vue"; import LoginForm from "../components/LoginForm.vue"; import { useTranslations } from "../index"; import useUserStore from "../store"; +import { verifySessionRoles } from "../supertokens"; import type { LoginCredentials } from "../types"; import type { AppConfig } from "@dzangolab/vue3-config"; @@ -81,7 +82,13 @@ const handleSubmit = async (credentials: LoginCredentials) => { }); if (user.value) { - router.push({ name: "home" }); + if ( + config && + config.user?.supportedRoles && + (await verifySessionRoles(config.user?.supportedRoles)) + ) { + router.push({ name: "home" }); + } } loading.value = false;