我正在构建一个应用程序,对于未经身份验证的用户来说,根本无法访问。
我写了LoggedInGuard
,但现在我必须将canActivate: [LoggedInGuard]
添加到路由器配置中的每条路由中(LoginComponent
除外)。
有没有更好的方法让这个工作?
我的文件/模块布局如下所示:
app/
AppModule
AppRoutingModule
AppComponent
authentication/
AuthenticationModule
AuthenticationRoutingModule
LoginComponent
contacts/
ContactsModule
ContactsRoutingModule
ContactListComponent
users/
UsersModule
UsersRoutingModule
UserEditComponent
...
也许可以创建两个单独的路由空间(一个用于登录,一个用于应用程序的其余部分)并仅将防护应用于应用程序的其余部分部分?< / p>
我希望有一个简单的解决方案。
提前致谢!
答案 0 :(得分:7)
我想我是以更合乎逻辑的方式做到的。我想这是一个意见。我按secured pages
和public pages
分隔了我的申请。我为每一组使用模板。因此,public component
和secure component
会将guard
放在secure template
上。
确保将[Guard]
添加到需要保护的完整路线。
因此,当我确保路线时,我将父母添加到app.routing.ts
const APP_ROUTES: Routes = [
{ path: '', redirectTo: '/home', pathMatch: 'full', },
{ path: '', component: PublicComponent, data: { title: 'Public Views' }, children: PUBLIC_ROUTES },
{ path: '', component: SecureComponent, canActivate: [Guard], data: { title: 'Secure Views' }, children: SECURE_ROUTES }
];
export const routing = RouterModule.forRoot(APP_ROUTES);
确保注意到这一行,
{ path: '', component: SecureComponent, canActivate: [Guard], data: { title: 'Secure Views' }, children: SECURE_ROUTES }
所以我创建了2个布局
/ public /所有公共组件
<强> /public/public.routes.ts 强>
/ secure /所有安全组件
<强> /secure/secure.routes.ts 强>
安全路线
请注意,这些路由现在不需要Guard
,因为它由模板父级处理。
export const SECURE_ROUTES: Routes = [
{ path: '', redirectTo: 'overview', pathMatch: 'full' },
{ path: 'items', component: ItemsComponent },
{ path: 'overview', component: OverviewComponent },
{ path: 'profile', component: ProfileComponent },
];
app.routing.ts中的主要路线
const APP_ROUTES: Routes = [
{ path: '', redirectTo: '/home', pathMatch: 'full', },
{ path: '', component: PublicComponent, data: { title: 'Public Views' }, children: PUBLIC_ROUTES },
{ path: '', component: SecureComponent, canActivate: [Guard], data: { title: 'Secure Views' }, children: SECURE_ROUTES }
];
export const routing = RouterModule.forRoot(APP_ROUTES);
在目录/ layouts中,我创建了一个
的布局<强> /layouts/secure.component.ts 强>
<强> /layouts/secure.component.html 强>
<强> /layouts/public.component.ts 强>
<强> /layouts/public.component.html 强>
所有内容都通过布局public
或secure
进行路由,[Guard]
处于安全状态。
然后我使用本地存储中的令牌处理身份验证。
@Injectable()
export class Guard implements CanActivate {
constructor(protected router: Router, protected auth: Auth ) {}
canActivate() {
if (localStorage.getItem('access_token')) {
// logged in so return true
return true;
}
// not logged in so redirect to login page
this.router.navigate(['/home']);
return false;
}
}
一旦我像这样设置我的应用程序,我将所有需要安全的路由放在安全目录和公共路径中。然后我在public.routes.ts文件或secure.routes.ts文件中创建它们各自的目录中的路由。
答案 1 :(得分:4)
通过将警卫移动到路由器事件监听器,我能够提供跨越多个模块的一组全局防护。
要为所有请求触发事件侦听器,我将其插入AppComponent。
请注意,在下面的两个示例中,您仍然可以为各个路线添加自定义防护,这些仍可以使用。
没有警卫
您可以删除对守卫的使用,而不是直接在事件监听器中实现逻辑。
import { Component, OnInit } from '@angular/core';
import { Router, RoutesRecognized } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/filter';
// I use a service to keep track of the authentication ticket.
// Replace this with whatever mechanism you use.
import { AuthenticationService } from './_services/index';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
constructor(
private router: Router,
private authService: AuthenticationService
) {}
ngOnInit() {
this.router.events
.filter(event => event instanceof RoutesRecognized)
.subscribe((event: RoutesRecognized) => {
const url = event.urlAfterRedirects;
// Public URLs don't need any kind of authorization.
if (url === '/public' || url.startsWith('/public/') || url.startsWith('/public?')) {
return;
}
// Everything else must be authenticated.
if (!this.authService.isAuthenticated()) {
// Allow for the login page to redirect back to the originally
// requested page.
this.router.navigate(['/public/login'], { queryParams: { returnUrl: state.url } });
}
});
}
}
传递给/public
的任何子页面的请求都将通过,但任何其他请求必须具有身份验证,否则它将重定向到/public/login
。
请注意重定向页面不在受保护区域,否则路由器将进入无限循环。
有警卫
下面的实现显示了我如何重用现有的警卫。只有当您需要保留它们或者它使您的代码更清洁时才会这样做。
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute, RoutesRecognized, CanActivate } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';
// Reused guards.
import { AdminGuard, AuthGuard } from './_guards/index';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
constructor(
private route: ActivatedRoute,
private router: Router,
private adminGuard: AdminGuard,
private authGuard: AuthGuard
) {}
ngOnInit() {
this.router.events
.filter(event => event instanceof RoutesRecognized)
.subscribe((event: RoutesRecognized) => {
// Public pages don't require authentication.
if (this.isSubPage(event, '/public')) {
return;
}
// All other requests MUST be done through an
// authenticated connection. The guard performs
// the redirection for us.
if (!this.callCanActivate(event, this.authGuard)) {
return;
}
// Administration pages require additional restrictions.
// The guard performs the redirection for us.
if (this.isSubPage(event, '/admin')) {
if (!this.callCanActivate(event, this.adminGuard)) {
return;
}
}
});
}
callCanActivate(event: RoutesRecognized, guard: CanActivate) {
return guard.canActivate(this.route.snapshot, event.state);
}
isSubPage(event: RoutesRecognized, parent: string) {
const url = event.urlAfterRedirects;
return (url === parent
|| url.startsWith(parent + '/')
|| url.startsWith(parent + '?'));
}
}
此示例与上面的示例相同,但为/admin
区域添加了保护,这可确保用户也具有管理权限。