Angular2 - 成功登录后重定向到调用的URL

57

我已经使用Angular 2.1.0搭建并运行了我的应用程序。

路由通过路由守卫进行保护,即canActivate。

当将浏览器指向受保护的区域(如“localhost:8080/customers”)时,我会像预期的那样被重定向到登录页面。

但是,在成功登录后,我希望被重定向回调用URL(在本例中为“/customers”)。

处理登录的代码如下:

login(event, username, password) {
  event.preventDefault();
  var success = this.loginService.login(username, password);
  if (success) {
    console.log(this.router);
    this.router.navigate(['']);
  } else {
    console.log("Login failed, display error to user");
  }
}

问题在于,我不知道如何从登录方法内部获取调用URL的控制权。

我确实找到了一个相关问题(和答案),但无法真正理解它。 Angular2登录后重定向


这个答案可能有用:https://dev59.com/vlkS5IYBdhLWcg3wVlTC#59008239 - AmirReza-Farahlagha
3个回答

90

在Angular文档中有一个教程:Milestone 5: Route guards。实现此目的的一种可能方式是使用您的AuthGuard来检查您的登录状态并将URL存储在AuthService上。

AuthGuard

import { Injectable }       from '@angular/core';
import {
  CanActivate, Router,
  ActivatedRouteSnapshot,
  RouterStateSnapshot
}                           from '@angular/router';
import { AuthService }      from './auth.service';

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private authService: AuthService, private router: Router) {}

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
    let url: string = state.url;

    return this.checkLogin(url);
  }

  checkLogin(url: string): boolean {
    if (this.authService.isLoggedIn) { return true; }

    // Store the attempted URL for redirecting
    this.authService.redirectUrl = url;

    // Navigate to the login page with extras
    this.router.navigate(['/login']);
    return false;
  }
}

AuthService或者你的LoginService

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Router } from '@angular/router';

@Injectable()
export class AuthService {
  isLoggedIn: boolean = false;    
  // store the URL so we can redirect after logging in
  public redirectUrl: string;

  constructor (
   private http: Http,
   private router: Router
  ) {}

  login(username, password): Observable<boolean> {
    const body = {
      username,
      password
    };
    return this.http.post('api/login', JSON.stringify(body)).map((res: Response) => {
      // do whatever with your response
      this.isLoggedIn = true;
      if (this.redirectUrl) {
        this.router.navigate([this.redirectUrl]);
        this.redirectUrl = null;
      }
    }
  }

  logout(): void {
    this.isLoggedIn = false;
  }
}

我认为这将让你了解事物是如何工作的,当然你可能需要根据你的代码进行适应。


我真的需要很快休息一下。我已经在angular.io上读了那一页很多次,却错过了一个如此明显的例子...不管怎样,非常感谢,这确实解决了我的问题 :)我找到了另一种解决方案,使用相同的方式存储window.location.pathname,但是你提供的解决方案似乎更像是Angular的做法。 - Anders Bergquist
1
@AndersBergquist 我理解那种感觉,我总是一遍又一遍地阅读文档,并学习新的东西。 - Fabio Antunes
@FabioAntunes,我在上面的示例中看到你没有使用任何特定的存储方式,例如本地存储或其他(我不确定是否真的建议使用它)。当页面刷新时,“isLoggedIn”将为false,并且将在重定向时再次进行“api/login”调用。你有什么安全处理刷新的建议吗? - super cool
为什么页面会被刷新?同时,isLogged只是一个布尔值。在真实的应用程序中,您需要执行更多操作,例如调用API来检查用户是否已登录,并且在每个API请求中,如果我们收到401错误,则确保将用户重定向到登录页面或类似操作。 - Fabio Antunes
3
我会使用 this.router.navigateByUrl(this.redirectUrl); 来支持查询参数,否则这些参数会被截断。 - Pankaj
但是我们在 routerLink 中提供重定向 URL 的位置在哪里呢?这是静态重定向,那有什么意义呢? - Sujoy

10

这段代码将处理你的请求:

export class AuthGuard implements CanActivate {
  constructor(private authService: AuthService,
              private router: Router) {
  }

  canActivate(next: ActivatedRouteSnapshot,
              state: RouterStateSnapshot): Observable<boolean> {
    return this.authService.isVerified
      .take(1)
      .map((isVerified: boolean) => {
        if (!isVerified) {
          this.router.navigate(['/login'], {queryParams: {returnUrl: state.url}});
          return false;
          // return true;
        }
        return true;
      });
  }
}

但请注意,URL参数将不会随着URL一起传递!

您可以在这里找到一个不错的教程: http://jasonwatmore.com/post/2016/12/08/angular-2-redirect-to-previous-url-after-login-with-auth-guard


3
我看到的答案都是正确的。 但回答你的问题最好的方式是使用returnUrl。 像这样:
export class AuthGuardService implements CanActivate {

  constructor(private auth: AuthenticationService, private router: Router) { }

  canActivate(next: ActivatedRouteSnapshot,
    _state: import('@angular/router').RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    let isLoggedIn = false;
    const idToken = next && next.queryParamMap.get('id_token');
    try {
      const expiresAt = idToken && JSON.parse(window.atob(idToken.split('.')[1])).exp * 1000;
      if (idToken && expiresAt) {
        isLoggedIn = true;
        localStorage.setItem('id_token', idToken);
        localStorage.setItem('expires_at', String(expiresAt));
      } else {
        isLoggedIn = this.auth.isLoggedIn();
      }
    } catch (e) {
      console.error(e);
      isLoggedIn = this.auth.isLoggedIn();
    }
    if (!isLoggedIn) {
      //this section is important for you:
      this.router.navigate(['/login'], { queryParams: { returnUrl: _state.url }});
    }
    return isLoggedIn;
  }
}

这个导航会创建一个带有“returnUrl”参数的URL,现在您可以从参数中读取“returnUrl”。
祝好运。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接