0

我是 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,因此即使凭据正确,用户也不会重定向到下一页。

这是验证功能的代码。

用户服务.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);
}
}

这是我修改令牌时的控制台

错误

4

2 回答 2

0

我不知道您是否遵循了本教程以及您是否自己进行了一些更改,但无论如何,您的代码在许多层面上都是错误的。

关于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;
  }
}
于 2018-01-15T07:42:56.907 回答
0

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

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

这是我的拦截器代码。

授权拦截器.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文件中导入拦截器。有关构建拦截器的信息,请参阅指南。

于 2018-01-15T13:00:32.350 回答