Angular project manage access permission using keycloak - keycloak

I'm using keycloak for an angular project, I have created two realm roles(admin and member), client and two users(Irma and Sheldon).
I am a beginner,
I wanted to allow access to the client for one user(Irma) and deny for other user(Sheldon).

May I suggest for the angular side, you use a library to do the authorization, something like: https://github.com/mauriciovigolo/keycloak-angular. Once you have that setup, and you have configured your authGuard, it's just a case of protecting your URL via the roles param in your router object.
For example (taken from https://angular.io/guide/router#milestone-5-route-guards, and added in keycloak roles bit):
import { AuthGuard } from '../auth/auth.guard';
const adminRoutes: Routes = [
{
path: 'admin',
component: AdminComponent,
data: {
roles: ['admin'],
},
canActivate: [AuthGuard],
children: [
{
path: '',
children: [
{ path: 'crises', component: ManageCrisesComponent },
{ path: 'heroes', component: ManageHeroesComponent },
{ path: '', component: AdminDashboardComponent }
],
}
]
}
];
#NgModule({
imports: [
RouterModule.forChild(adminRoutes)
],
exports: [
RouterModule
]
})
export class AdminRoutingModule {}
The last piece of the puzzle will be on the keycloak server side, you have to go to your user Irma, and assign her the 'admin' role. This will allow her to access what ever paths you protect with the 'admin' role via the router above.
Hope this helps.

Related

Use more than one MongoDb collection in a single app

I have an app which uses MongoDb and I am connecting to MongoDb by calling MongooseModule.forRoot in replies.module.ts, now I have another module called replies.module.ts and I want to connect to another collection but in the same database, should I use the same method in the new module and just change the collection name? does it won't create a duplicate connection to mongo? what is the best practice for that?
Reviews module: reviews.module.ts
#Module({
imports: [
MongooseModule.forRoot('mongodb+srv://user:password#url/reviews?retryWrites=true&w=majority',),
MongooseModule.forFeature([{name: 'Review', schema: ReviewSchema}
])],
controllers: [ReviewsController],
providers: [ReviewsService]
})
Replies module: replies.module.ts
#Module({
imports: [
MongooseModule.forRoot('mongodb+srv://user:password#url/replies?retryWrites=true&w=majority',),
MongooseModule.forFeature([{name: 'Replies', schema: RepliesSchema}
])],
controllers: [RepliesController],
providers: [RepliesService]
})
I think you can do what you want by naming your connections:
app.module.ts:
#Module({
imports: [
MongooseModule.forRoot('mongodb+srv://user:password#url/reviews?retryWrites=true&w=majority', { connectionName: 'ReviewsDB' }),
MongooseModule.forRoot('mongodb+srv://user:password#url/replies?retryWrites=true&w=majority', { connectionName: 'RepliesDB' })
]})
export class AppModule implements NestModule {}
Then you can use your models, for examples in dedicatied modules:
review.module.ts :
#Module({
imports: [
MongooseModule.forFeature([{ name: Review.name, schema: ReviewSchema }], 'ReviewsDB')
],
providers: [ReviewService],
exports: [ReviewService],
})
export class ReviewModule {}
And the for replies:
reply.module.ts :
#Module({
imports: [
MongooseModule.forFeature([{ name: Reply.name, schema: ReplySchema }], 'RepliesDB')
],
providers: [ReplyService],
exports: [ReplyService],
})
export class ReplyModule {}
Do not forget to set the connection name of the wanted database in your forFeature declaration

Slashes in angular routes

Can you have slashes in angular routes to make it look like subfolders?
I've got this sort of setup
I'd like to makepages at /users/index and /users/groups etc.
In users.routing.module.ts I have:
Shell.childRoutes([
{
path: '', component: IndexComponent, data: { roles: ['Administrator'] },
children: [
{ path: 'users', component: UsersComponent, data: { roles: ['Administrator'] } },
{ path: 'groups', component: GroupsComponent, data: { roles: ['Administrator'] } },
{ path: 'roles', component: RolesComponent, data: { roles: ['Administrator'] } }
]
}
])
];
Howver,
<p><a [routerLink]="users/users">Users</a></p>
makes the link come out as NaN. WTF?
Is it possible to have URLs with slashes in them or do I have to make everything as /component?
It is Nan because you have not defined any route as users/users , try changing one route path as -
{ path: 'users/users', component: UsersComponent, data: { roles: ['Administrator'] } },

How to do a lazy loaded ionic framework app with a login page

I have an app that is working great, but I want to move it behind a login page. The various modules are lazy-loaded and have been working great. However, when I change the app to always go to the login page first (where I will check login status and redirect to the app if logged in), I get an error about routes.
app-routing.module.ts
import { NgModule } from '#angular/core';
import { PreloadAllModules, RouterModule, Routes } from '#angular/router';
const routes: Routes = [
{ path: '', loadChildren: './login/login.module#LoginPageModule' }
// this next line was how the app routed before I tried adding the login page
// { path: '', loadChildren: './tabs/tabs.module#TabsPageModule' }
];
#NgModule({
imports: [
RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })
],
exports: [RouterModule]
})
export class AppRoutingModule {}
login.router.module.ts
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { LoginPage } from './login.page';
const routes: Routes = [
{ path: '', component: LoginPage },
];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class LoginRoutingModule { }
login.page.ts
import { ChangeDetectionStrategy, Component } from '#angular/core';
import { Router } from '#angular/router';
import { Store } from '#ngrx/store';
import { AppState } from '../_store/store/app.store';
import { filter } from 'rxjs/operators';
#Component({
selector: 'app-login',
templateUrl: 'login.page.html',
styleUrls: ['login.page.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class LoginPage {
constructor(private router: Router, private store: Store<AppState>) {
this.userSubscription = this.store.select(state => state.users.user).pipe(
filter(user => !!user)
).subscribe(user => {
if (user) {
// THIS IS WHERE THE ERROR HAPPENS
this.router.navigate(['/tabs']);
}
});
}
}
this.router.navigate(['/tabs']); is where the error happens:
ERROR Error: Uncaught (in promise): Error: Cannot match any routes.
URL Segment: 'tabs/behaviors' Error: Cannot match any routes. URL
Segment: 'tabs/behaviors'
I'm sure I'm missing something really obvious here. First attempt at lazy loading all the modules. I'm pretty certain I need to reference the tabs module in the login.page file somehow, or in the login.router.module. Any help would be greatly appreciated. The state check for user status works great, I've verified that all of that is working, it is just where it attempts to navigate if user is found.
Try to change to
const routes: Routes = [
{ path: '', redirectTo: 'login', pathMatch: 'full' },
{ path: 'login', loadChildren: './login/login.module#LoginPageModule' }
{ path: 'tabs', loadChildren: './tabs/tabs.module#TabsPageModule' }
];
With this code this.router.navigate(['/tabs']); you are routing to tabs, but you don't have it declare it. This is for the app.routing.ts file. Don't understand why you have the login.router.ts file.
So after following a suggestion above, and that giving me the same error, and finding no help in the docs for either angular or ionic, I went on a multi-hour change every combination of routings I could and finally something worked.
These are the routes in the app-routing.module.ts
{ path: 'login', loadChildren: './login/login.module#LoginPageModule' },
{ path: 'tabs', loadChildren: './tabs/tabs.module#TabsPageModule' },
{ path: '', redirectTo: 'login', pathMatch: 'full' },
This is the tabs.router.module.ts before the change that made it work:
{ path: 'tabs', component: TabsPage, children: [ .... ] },
{ path: '', redirectTo: 'tabs/behaviors', pathMatch: 'full' }
This is it now:
{ path: '', component: TabsPage, children: [ ... ] },
That's it. Finally figured it out when accidentally typing in the browser .com:8100/tabs/tabs/behaviors worked. Removing the path: 'tabs' in the tabs routing module fixed it. /tabs goes to the tabs routing, and then /behaviors is the child. My code had added a 2nd layer of /tabs in between the 1st and the /behavior.

PageNotFound route in root routes triggered after outsourcing routes to component

my routes used to work fine when they were all together, the notfound route
{ path: '**', component: PageNotFoundComponent}
was at the last place to capture any other not defined paths.
After I moved the recipe routes to its own module these are never called. Instead, the pagenotfound is called.
Everything works fine if I remove the PageNotFoundComponent route from the root routes. Any ideas regarding whats going on here?
This is the root app routing module:
import { Routes, RouterModule } from '#angular/router';
import { NgModule, OnInit } from '#angular/core';
import { ShoppingListComponent } from './shopping-list/shopping-list.component';
import { PageNotFoundComponent } from './errors/page-not-found/page-not-found.component';
import { AuthComponent } from './auth/auth.component';
const appRoutes: Routes = [
{ path: '', redirectTo: 'recipes', pathMatch: 'full' },
{ path: 'shopping-list', component: ShoppingListComponent },
{ path: 'auth', component: AuthComponent },
{ path: '**', component: PageNotFoundComponent}
];
#NgModule({
imports: [RouterModule.forRoot(appRoutes)],
exports: [RouterModule]
})
export class AppRoutingModule {
OnInit() {
console.log(appRoutes);
}
}
This is the child recipe routing module:
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { RecipesComponent } from './recipes.component';
import { AuthGuard } from '../auth/auth.guard';
import { RecipeStartComponent } from './recipe-start/recipe-start.component';
import { RecipeEditComponent } from './recipe-edit/recipe-edit.component';
import { RecipeDetailComponent } from './recipe-detail/recipe-detail.component';
import { RecipesResolverService } from './recipes-resolver.service';
const routes: Routes = [
{
path: 'recipes', component: RecipesComponent, canActivate: [AuthGuard] , children: [
{ path: '', component: RecipeStartComponent },
{ path: 'new', component: RecipeEditComponent },
{
path: ':id',
component: RecipeDetailComponent,
resolve: [RecipesResolverService]
},
{
path: ':id/edit',
component: RecipeEditComponent,
resolve: [RecipesResolverService]
},
]
}
];
#NgModule({
declarations: [
],
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class RecipesRoutingModule {
}
Thanks for taking the time to get this far, any idea would be appreciated.
The problem was that the wildcard route ('**') always should be at the end of your routes list because of the way it works.
It watches all the routes before it, and checks if any given URL, that the user is searching on matches those.
Since you've outsourced your recipes paths, and probably imported them into app.module, those paths get concatenated after the original path list that you have in your app-routing.module.
Therefore your paths in the recipe routing module end up being AFTER the wildcard route ('**'), so they get ignored by it. That's why searching on any URL listed in the recipe routing module will reroute the user to the wild card path, to your PageNotFoundComponent.
Great solution tho.
I solved the problem lazy loading all the routes and then adding the PageNotFound route '**' at the end, hope this helps anyone that faced the same problem:
import { Routes, RouterModule } from '#angular/router';
import { NgModule } from '#angular/core';
import { PageNotFoundComponent } from './errors/page-not-found/page-not-found.component';
// If new and :id children were inverted that would make angular take new as id
// ant that would break the app, the order of the routes is very important
// that's why the 404 PageNotFoundComponent goes the last one
const appRoutes: Routes = [
{ path: '', redirectTo: 'recipes', pathMatch: 'full' },
{ path: 'recipes', loadChildren: () => import('./recipes/recipes.module').then(m => m.RecipesModule) },
{ path: 'shopping-list', loadChildren: () => import('./shopping-list/shopping-list.module').then( m => m.ShoppingListModule) },
{ path: 'auth', loadChildren: () => import('./auth/auth.module').then( m => m.AuthModule) },
{ path: '**', component: PageNotFoundComponent }
];
#NgModule({
imports: [RouterModule.forRoot(appRoutes)],
exports: [RouterModule]
})
export class AppRoutingModule {
}

Angular 2: Too many components in a module?

I'm a currently working on a sign up forms, which has multiple steps and various conditional forms depending on the account type. The module has almost 30 components (a mix of children and parent components) and all of these are imported into the module file. This is making the entire Angular 2 site run really slow, especially after navigating to the sign up forms and then to another route.
Is it possible that there are too many components/service/providers in a module that it's impacting the performance of the site negatively? Is it recommended to break down the multi-step sign up application forms to multiple modules?
import { CommonModule } from '#angular/common';
import { RouterModule } from '#angular/router';
import { NgModule } from '#angular/core';
import { ReactiveFormsModule } from '#angular/forms';
... all the other imports of components/service for this module
export const routes = [{
path: '',
component: parentComponent,
canActivate: [AuthGuard],
resolve: {
someData: someDataResolver
},
children: [
{ path: '', redirectTo: '0', pathMatch: 'full' },
{ path: '0',
component: someComponent1,
resolve: {
someData1: someData1Resolver
}
},
... a bunch more children routes/components
{ path: '20',
component: someComponent20,
resolve: {
someData20: someData1Resolver
}
}
]
}]
#NgModule({
declarations: [ ... ],
entryComponents: [ ... ],
imports: [ ... ],
providers: [ ... ],
})
export default class SampleModule {
static routes = routes
}
Components number in a module matters only on first load time(or page refresh), then they are loaded in memory. Look for issue in other place