【问题标题】:Http Error Handling is not working with map in AngularHttp错误处理不适用于Angular中的地图
【发布时间】:2018-01-15 21:00:32
【问题描述】:

我是 Angular 新手,我正在开发一个使用 Angular 5 作为前端,Laravel5.5 作为后端的项目。

我想要做什么: 我正在执行基于令牌的身份验证,以检查是否正确的用户正在向后端发送请求,如果令牌未通过身份验证,它将引发异常并且用户将被重定向到登录页面。

我做了什么: 我按照 Youtube 上的教程使用 Authguard 来验证用户,下面是我的代码。

auth.guard.ts

import {Injectable} from "@angular/core";
import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot} from "@angular/router";
import {UserService} from "../_services/user.service";
import {Observable} from "rxjs/Rx";

@Injectable()
export class AuthGuard implements CanActivate {

constructor(private _router: Router, private _userService: UserService) {
}

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):  Observable<boolean> | boolean {
    let currentUser = JSON.parse(localStorage.getItem('currentUser'));
    console.log("AuthGuard.ts:  "+ currentUser);
    if (currentUser == null) {
        this._router.navigate(['/login'], {queryParams: {returnUrl: state.url}});
        return false;
    }
    else{
        let response = this._userService.verify().map(
            data => {
                console.log("This is the data returned in authguard: "+data)
                if (data !== null) {
                    // logged in so return true
                    // console.log("Not null");
                    return true;
                }
                // error when verify so redirect to login page with the return url
                this._router.navigate(['/login'], {queryParams: {returnUrl: state.url}});
                return false;
            },
            error => {
                console.log('myerror');
                // error when verify so redirect to login page with the return url
                this._router.navigate(['/login'], {queryParams: {returnUrl: state.url}});
                return false;
            });

        console.log("response : "+ typeof response);
        return response;
    }
}
}

在教程中他们使用订阅而不是地图,但我做了一些研究,发现我们不能将订阅与 Observable 一起使用。

我的代码虽然显示了订阅错误并将用户重定向到登录页面,但订阅它不会返回 true 或 false,因此即使凭据正确,用户也不会重定向到下一页。

这是验证功能的代码。

user.service.ts

import {Injectable} from "@angular/core";
import { HttpClient , HttpHeaders , HttpErrorResponse } from '@angular/common/http';
import {User} from "../_models/index";
import { Observable } from 'rxjs';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';

interface DataResponse { status: string; }

@Injectable()
export class UserService {

constructor(private http: HttpClient) {
}

verify(): Observable<any>  {
    let currentUser = JSON.parse(localStorage.getItem('currentUser'));
    let headers = new HttpHeaders({'Authorization': 'Bearer ' + currentUser.token});
    let abc = this.http.get<DataResponse>('http://127.0.0.1:8000/api/auth/verify', {headers:headers}).map(response =>{ 
                                                                                                        // console.log("hjsdgjd:  "+response.status ); 
                                                                                                            response
                                                                                                    })
                                                                                                    .catch(this.errorHandler);
    console.log("abc:  " + abc);
    return abc;
}
errorHandler(error: HttpErrorResponse){
    console.log('some thing');
    return Observable.throw(error.message);
}
}

这是我修改令牌时的console

【问题讨论】:

  • @SurjitSD:感谢您希望在这里改进问题。但是,没有印刷原因将 Laravel 和 Angular 等软件名称包装为粗体或斜体。它们是专有名词,因此只需修正大小写,否则请按原样保留它们。过多的格式使事情更难阅读,而不是更容易。

标签: angular authentication error-handling angular5 auth-guard


【解决方案1】:

我不知道您是否按照教程进行操作,是否自己进行了一些更改,但无论如何,您的代码在很多层面上都是错误的。

关于subscribe,我不知道你从哪里找到你不能用Observable,因为这是你在使用observables时应该知道的第一个运算符。

让我重写你的代码并解释你做错了什么:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):  Observable<boolean> | boolean {

  let currentUser: any;

  // You need to surround your parsing with a try catch, in case it goes wrong
  try {
    currentUser = JSON.parse(localStorage.getItem('currentUser'));
  } catch { return false; }

  console.log("AuthGuard.ts:  " + currentUser);

  // Use falsy values, they cover more cases (such as empty or undefined)
  if(!currentUser) {
    this._router.navigate(['/login'], { queryParams: { returnUrl: state.url } });
    return false;
  }
  else {
    // You will subscribe to your Observable, because you have to do something with the response
    this._userService.verify().subscribe(data => {

      console.log("This is the data returned in authguard: " + data)

      // This time, use truthy values (opposite of falsy)
      if (data) {
        // logged in so return true
        // console.log("Not null");
        return true;
      }
      // Empty response 
      this._router.navigate(['/login'], { queryParams: { returnUrl: state.url } });
      return false;
    },
    error => {
      console.log('myerror');
      // error when verify so redirect to login page with the return url
      this._router.navigate(['/login'], { queryParams: { returnUrl: state.url } });
      return false;
    });

  // Don' return anything here : this will be returned before your HTTP call ends, and return a falsy value ('return false;')
  // console.log("response : " + typeof response);
  // return response;
  }
}

【讨论】:

  • 顺便说一下,你不应该对每个警卫都进行http调用。您应该在用户登录时制作一个,然后将令牌存储在会话存储中。否则你的应用程序会很重,而且对用户不友好。接下来,当您使用相同的令牌进行 HTTP 调用时,检查令牌是否正确有什么意义?您的用户检查逻辑应该在您的后端,而不是您的前端
  • 感谢您的回复,我说订阅不适用于 Observable 是错误的,我想说的是订阅不适用于 Observable。因为当我使用它时,它给出了一个语法错误,说 type subscribe is not assignable to type Observable.
  • 现在谈谈为什么要对每个警卫进行 http 调用的评论。如果我在本地存储中更改我的令牌并提交我无权的请求怎么办。
  • 它运作良好,相信我。你只是在你的代码中做错了:在最后几行,你返回了订阅,而你的方法要求一个布尔值,或者一个布尔值的 Observable。我删除了那部分,它应该可以工作。 What if I change my token in the local storage and submit a request that i'm not authorized to => 那么你的后端应该返回带有错误代码的正确响应,我相信它是 403 或 401
  • 我确实遵循了您的代码,现在我只是返回 true 或 false,但是在提供正确的凭据后它不会将用户重定向到下一页。 :( 当我提供正确的凭据时,控制台中没有错误
【解决方案2】:

我通过使用拦截器解决了这个问题。

它的作用: 它从前端获取 http 请求,并将标头(包含令牌)附加到请求中,然后再将其发送到后端。然后它从后端获取响应,检查响应是否有错误,如果有错误则将用户重定向到登录页面。

这是我的拦截器代码。

AuthorizationInterceptor.ts

import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpErrorResponse } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { Router } from '@angular/router';

import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/of';
import 'rxjs/add/observable/throw';

@Injectable()
export class AuthorizationInterceptor implements HttpInterceptor
{
constructor(private _router: Router) { }

    private handleAuthError(err: HttpErrorResponse): Observable<any> {
        //handle your auth error or rethrow
        console.log('server error : ', err);
        if (err.status === 401 || err.status === 403) {
            //navigate /delete cookies or whatever
            localStorage.removeItem('currentUser');
            this._router.navigate(['/login']);
            // if you've caught / handled the error, you don't want to rethrow it unless you also want downstream consumers to have to handle it as well.
            // return Observable.of(err.message);
        }
        return Observable.throw(err);
    }

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>
{
    // console.log('resquest passing from interceptor....', req, next);
    var authReq;

    let currentUser = JSON.parse(localStorage.getItem('currentUser'));
    // console.log("In the Interceptor: " + req);
    if (currentUser) {

        // Clone the request to add the new header.
        req = req.clone({headers: req.headers.set('Authorization', 'Bearer ' + currentUser.token)});
        // console.log("Authentication Request:  " + authReq);
        // shortcut for above...
        // const authReq = req.clone({setHeaders: {Authorization: authHeader}});

        // Pass on the cloned request instead of the original request.
    }

 return next.handle(req).catch(x => this.handleAuthError(x));
}
}

注意:不要忘记在 module.ts 文件中导入拦截器。 请参阅This 构建拦截器指南。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-09
    • 2018-11-30
    • 2012-11-16
    • 2016-07-12
    • 2017-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多