login - spring登录 - 角度重定向到登录页面
spring security重定向 (5)
请不要覆盖路由器出口! 最新的路由器版本(3.0 beta)是一场噩梦。
而是使用接口CanActivate和CanDeactivate并将路由定义中的类设置为canActivate / canDeactivate。
像那样:
{ path: '', component: Component, canActivate: [AuthGuard] },
类:
@Injectable()
export class AuthGuard implements CanActivate {
constructor(protected router: Router, protected authService: AuthService)
{
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean {
if (state.url !== '/login' && !this.authService.isAuthenticated()) {
this.router.navigate(['/login']);
return false;
}
return true;
}
}
另请参阅: https://angular.io/docs/ts/latest/guide/router.html#!#can-activate-guard : https://angular.io/docs/ts/latest/guide/router.html#!#can-activate-guard
我来自Asp.Net MVC世界,在其中尝试访问未经授权的页面的用户会自动重定向到登录页面。
我正在尝试在Angular上重现此行为。 我遇到了@CanActivate装饰器,但是它导致该组件完全不呈现,也没有重定向。
我的问题如下:
- Angular是否提供实现此行为的方法?
- 如果是这样,怎么办? 这是一个好习惯吗?
- 如果没有,在Angular中处理用户授权的最佳实践是什么?
请参考此代码auth.ts文件
import { CanActivate } from '@angular/router';
import { Injectable } from '@angular/core';
import { } from 'angular-2-local-storage';
import { Router } from '@angular/router';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(public localStorageService:LocalStorageService, private router: Router){}
canActivate() {
// Imaginary method that is supposed to validate an auth token
// and return a boolean
var logInStatus = this.localStorageService.get('logInStatus');
if(logInStatus == 1){
console.log('****** log in status 1*****')
return true;
}else{
console.log('****** log in status not 1 *****')
this.router.navigate(['/']);
return false;
}
}
}
// *****And the app.routes.ts file is as follow ******//
import { Routes } from '@angular/router';
import { HomePageComponent } from './home-page/home- page.component';
import { WatchComponent } from './watch/watch.component';
import { TeachersPageComponent } from './teachers-page/teachers-page.component';
import { UserDashboardComponent } from './user-dashboard/user- dashboard.component';
import { FormOneComponent } from './form-one/form-one.component';
import { FormTwoComponent } from './form-two/form-two.component';
import { AuthGuard } from './authguard';
import { LoginDetailsComponent } from './login-details/login-details.component';
import { TransactionResolver } from './trans.resolver'
export const routes:Routes = [
{ path:'', component:HomePageComponent },
{ path:'watch', component:WatchComponent },
{ path:'teachers', component:TeachersPageComponent },
{ path:'dashboard', component:UserDashboardComponent, canActivate: [AuthGuard], resolve: { dashboardData:TransactionResolver } },
{ path:'formone', component:FormOneComponent, canActivate: [AuthGuard], resolve: { dashboardData:TransactionResolver } },
{ path:'formtwo', component:FormTwoComponent, canActivate: [AuthGuard], resolve: { dashboardData:TransactionResolver } },
{ path:'login-details', component:LoginDetailsComponent, canActivate: [AuthGuard] },
];
遵循以上令人敬畏的答案,我也想对
CanActivateChild
:保护子路由。
它可用于为子路由增加
guard
,对ACL等情况很有用
像这样
src / app / auth-guard.service.ts(摘录)
import { Injectable } from '@angular/core';
import {
CanActivate, Router,
ActivatedRouteSnapshot,
RouterStateSnapshot,
CanActivateChild
} from '@angular/router';
import { AuthService } from './auth.service';
@Injectable()
export class AuthGuard implements CanActivate, CanActivateChild {
constructor(private authService: AuthService, private router: Router) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
let url: string = state.url;
return this.checkLogin(url);
}
canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
return this.canActivate(route, state);
}
/* . . . */
}
src / app / admin / admin-routing.module.ts(摘录)
const adminRoutes: Routes = [
{
path: 'admin',
component: AdminComponent,
canActivate: [AuthGuard],
children: [
{
path: '',
canActivateChild: [AuthGuard],
children: [
{ path: 'crises', component: ManageCrisesComponent },
{ path: 'heroes', component: ManageHeroesComponent },
{ path: '', component: AdminDashboardComponent }
]
}
]
}
];
@NgModule({
imports: [
RouterModule.forChild(adminRoutes)
],
exports: [
RouterModule
]
})
export class AdminRoutingModule {}
这取自 https://angular.io/docs/ts/latest/guide/router.html#!#can-activate-guard
1. Create a guard as seen below. 2. Install ngx-cookie-service to get cookies returned by external SSO. 3. Create ssoPath in environment.ts (SSO Login redirection). 4. Get the state.url and use encodeURIComponent.
import { Injectable } from '@angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from
'@angular/router';
import { CookieService } from 'ngx-cookie-service';
import { environment } from '../../../environments/environment.prod';
@Injectable()
export class AuthGuardService implements CanActivate {
private returnUrl: string;
constructor(private _router: Router, private cookie: CookieService) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
if (this.cookie.get('MasterSignOn')) {
return true;
} else {
let uri = window.location.origin + '/#' + state.url;
this.returnUrl = encodeURIComponent(uri);
window.location.href = environment.ssoPath + this.returnUrl ;
return false;
}
}
}
最终路由器的用法
随着新路由器的推出,保护路由变得更加容易。 您必须定义充当服务的防护,并将其添加到路由。
import { Injectable } from '@angular/core';
import { CanActivate } from '@angular/router';
import { UserService } from '../../auth';
@Injectable()
export class LoggedInGuard implements CanActivate {
constructor(user: UserService) {
this._user = user;
}
canActivate() {
return this._user.isLoggedIn();
}
}
现在,将
LoggedInGuard
传递到路由,并将其添加到模块的
providers
数组。
import { LoginComponent } from './components/login.component';
import { HomeComponent } from './components/home.component';
import { LoggedInGuard } from './guards/loggedin.guard';
const routes = [
{ path: '', component: HomeComponent, canActivate: [LoggedInGuard] },
{ path: 'login', component: LoginComponent },
];
模块声明:
@NgModule({
declarations: [AppComponent, HomeComponent, LoginComponent]
imports: [HttpModule, BrowserModule, RouterModule.forRoot(routes)],
providers: [UserService, LoggedInGuard],
bootstrap: [AppComponent]
})
class AppModule {}
有关如何与最终版本一起使用的详细博客文章: https://medium.com/@blacksonic86/angular-2-authentication-revisited-611bf7373bf9 : https://medium.com/@blacksonic86/angular-2-authentication-revisited-611bf7373bf9
不推荐使用的路由器的用法
一个更强大的解决方案是扩展
RouterOutlet
并在激活路由时检查用户是否登录。这样,您不必将指令复制并粘贴到每个组件。
再加上基于子组件的重定向可能会产生误导。
@Directive({
selector: 'router-outlet'
})
export class LoggedInRouterOutlet extends RouterOutlet {
publicRoutes: Array;
private parentRouter: Router;
private userService: UserService;
constructor(
_elementRef: ElementRef, _loader: DynamicComponentLoader,
_parentRouter: Router, @Attribute('name') nameAttr: string,
userService: UserService
) {
super(_elementRef, _loader, _parentRouter, nameAttr);
this.parentRouter = _parentRouter;
this.userService = userService;
this.publicRoutes = [
'', 'login', 'signup'
];
}
activate(instruction: ComponentInstruction) {
if (this._canActivate(instruction.urlPath)) {
return super.activate(instruction);
}
this.parentRouter.navigate(['Login']);
}
_canActivate(url) {
return this.publicRoutes.indexOf(url) !== -1 || this.userService.isLoggedIn()
}
}
无论用户是否登录,
UserService
代表您的业务逻辑所在的位置。
您可以在构造函数中使用DI轻松添加它。
当用户导航到您网站上的新URL时,将使用当前指令来调用activate方法。 您可以从中获取URL并确定是否允许该URL。 如果不是,则仅重定向到登录页面。
使它起作用的最后一件事是将其传递给我们的主要组件,而不是内置组件。
@Component({
selector: 'app',
directives: [LoggedInRouterOutlet],
template: template
})
@RouteConfig(...)
export class AppComponent { }
此解决方案不能与
@CanActive
生命周期装饰器一起使用,因为如果传递给它的函数解析为false,则不会调用
RouterOutlet
的activate方法。
还写了一篇关于它的详细博客文章: https://medium.com/@blacksonic86/authentication-in-angular-2-958052c64492 : https://medium.com/@blacksonic86/authentication-in-angular-2-958052c64492