OK… Really try hard and still don’t understand how the thing got connected for the auth… if in the user table I add a column call roles and put admin in there, and also in getCurrentUser part, in the select section add roles, that works… I can view the admin page. However it is not the one I want and I don’t know what I need to modify to make it works now…
Play around a little bit and it looks like I still don’t understand how the thing got connected…
Here is the change I made right now
in api/src/lib/auth.js, my hasRole function was looks like following:
export const hasRole = (roles) => {
if (!isAuthenticated()) {
return false
}
const currentUserRoles = context.currentUser?.userRole['name']
if (typeof roles === 'string') {
if (typeof currentUserRoles === 'string') {
// roles to check is a string, currentUser.roles is a string
return currentUserRoles === roles
} else if (Array.isArray(currentUserRoles)) {
// roles to check is a string, currentUser.roles is an array
return currentUserRoles?.some((allowedRole) => roles === allowedRole)
}
}
if (Array.isArray(roles)) {
if (Array.isArray(currentUserRoles)) {
// roles to check is an array, currentUser.roles is an array
return currentUserRoles?.some((allowedRole) =>
roles.includes(allowedRole)
)
} else if (typeof currentUserRoles === 'string') {
// roles to check is an array, currentUser.roles is a string
return roles.some((allowedRole) => currentUserRoles === allowedRole)
}
}
// roles not found
return false
}
And then in web\src\Routes.js file I change to following…
// In this file, all Page components from 'src/pages` are auto-imported. Nested
// directories are supported, and should be uppercase. Each subdirectory will be
// prepended onto the component name.
//
// Examples:
//
// 'src/pages/HomePage/HomePage.js' -> HomePage
// 'src/pages/Admin/BooksPage/BooksPage.js' -> AdminBooksPage
import { Router, Route, Set, Private } from '@redwoodjs/router'
import AppHeaderLayout from 'src/layouts/AppHeaderLayout'
import { useAuth } from './auth'
const Routes = () => {
return (
<Router useAuth={useAuth}>
<Set wrap={AppHeaderLayout}>
<Private unauthenticated="forbidden" hasRole={'ADMIN'}>
<Route path="/admin" page={AdminPage} name="admin" />
</Private>
<Route path="/forbidden" page={ForbiddenPage} name="forbidden" />
<Route path="/login" page={LoginPage} name="login" />
<Route path="/signup" page={SignupPage} name="signup" />
<Route path="/forgot-password" page={ForgotPasswordPage} name="forgotPassword" />
<Route path="/reset-password" page={ResetPasswordPage} name="resetPassword" />
<Route path="/about" page={AboutPage} name="about" />
<Route path="/" page={HomePage} name="home" />
</Set>
<Route notfound page={NotFoundPage} />
</Router>
)
}
export default Routes
Now the problem becomes… everyone can view the admin page now… either my currentUser was change from ADMIN to USER…
OK… just check the Private tag again and I realized there is no hasRole properties… that probably why everyone can view the page… back to beginning…
And also because this issue… I also want to know is it a good practice to seperate the User and Role Table or just adding the column said… roles in User table… it looks like the second way redwood more prefer and not that complicated?
Hi @vincentz without being able to spend time on this, it looks like the way you set your DB models up (role to many users) is conflicting with the logic for hasRole (in api/src/lib/auth.js)
My recommendation is to follow along in this document (maybe starting a new project just to learn), using the example code as reference:
Once you get that working, I think you’ll have a better understanding about how to get your project working.
Lastly, if you’re jumping straight in RBAC, there are a lot of fundamentals you’re building on. Is it possible you can think about this incrementally? E.g. just use isAuthenticated for private content at the start of your project. Then, as you continue to develop and add, incrementally add RBAC. Just an idea if helpful.