Angular2 async फ़ंक्शन को कॉल कर सकते हैं ()


83

मैं अपने ऐप में कुछ पृष्ठों तक पहुंच को प्रतिबंधित करने के लिए Angular2 राउटर गार्ड का उपयोग करने की कोशिश कर रहा हूं। मैं फायरबेस प्रमाणीकरण का उपयोग कर रहा हूं। यह जांचने के लिए कि कोई उपयोगकर्ता फायरबेस के साथ लॉग इन है, मुझे कॉलबैक के साथ ऑब्जेक्ट .subscribe()पर कॉल करना होगा FirebaseAuth। यह गार्ड के लिए कोड है:

import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { AngularFireAuth } from "angularfire2/angularfire2";
import { Injectable } from "@angular/core";
import { Observable } from "rxjs/Rx";

@Injectable()
export class AuthGuard implements CanActivate {

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

    canActivate(route:ActivatedRouteSnapshot, state:RouterStateSnapshot):Observable<boolean>|boolean {
        this.auth.subscribe((auth) => {
            if (auth) {
                console.log('authenticated');
                return true;
            }
            console.log('not authenticated');
            this.router.navigateByUrl('/login');
            return false;
        });
    }
}

जब एक पृष्ठ इस पर गार्ड है, या तो करने के लिए एक नेविगेट authenticated, या not authenticated(firebase से प्रतिक्रिया के लिए कुछ देरी प्रतीक्षा के बाद) कंसोल के लिए मुद्रित है। हालाँकि, नेविगेशन कभी पूरा नहीं होता है। साथ ही, अगर मैं लॉग इन नहीं हूं तो मैं /loginरूट पर पुनर्निर्देशित हूं । इसलिए, मेरे पास जो समस्या return trueहै वह उपयोगकर्ता के लिए अनुरोधित पृष्ठ प्रदर्शित नहीं करता है। मैं यह मान रहा हूं क्योंकि मैं एक कॉलबैक का उपयोग कर रहा हूं, लेकिन मैं यह पता लगाने में असमर्थ हूं कि यह कैसे करना है। कोई विचार?


आयात ऑब्जर्वेबल इस तरह -> 'आरएक्सजे / ऑब्जर्वेबल' से आयात {ऑब्जर्वेबल};
कार्लोस प्लिगो

जवाबों:


125

canActivateउसे पूरा करने की जरूरत है Observable:

@Injectable()
export class AuthGuard implements CanActivate {

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

    canActivate(route:ActivatedRouteSnapshot, state:RouterStateSnapshot):Observable<boolean>|boolean {
        return this.auth.map((auth) => {
            if (auth) {
                console.log('authenticated');
                return true;
            }
            console.log('not authenticated');
            this.router.navigateByUrl('/login');
            return false;
        }).first(); // this might not be necessary - ensure `first` is imported if you use it
    }
}

एक returnलापता है और मैं map()इसके बजाय उपयोग करता हूं subscribe()क्योंकि subscribe()रिटर्न ए Subscriptionनहीं हैObservable


क्या आप दिखा सकते हैं कि अन्य घटकों में इस वर्ग का उपयोग कैसे किया जाए?

पक्का नहीं आपका क्या मतलब है। आप इसका उपयोग मार्गों के साथ करते हैं, घटकों के साथ नहीं। देखें angular.io/docs/ts/latest/guide/router.html#!#guards
गुंटर Zöchbauer

मेरे मामले में ऑब्जर्वेबल नहीं चलता है। मुझे कोई कंसोल आउटपुट दिखाई नहीं देता है। हालांकि, अगर मैं सशर्त रूप से (डॉक्स में) बूलियन वापस लेता हूं, तो कंसोल लॉग हो जाता है। क्या यह एक सरल अवलोकन है?
कोर्टीपी

@cortopy अवलोकनीय authद्वारा उत्सर्जित मूल्य है (बस trueया हो सकता है false)। जब राउटर इसे सब्सक्राइब करता है तो अवलोकन योग्य है। हो सकता है कि आपके कॉन्फ़िगरेशन में कुछ गायब है।
गुंटर ज़ोचबॉयर

1
@ günter-zöchbauer हाँ, इसके लिए धन्यवाद। मुझे एहसास नहीं था कि मैं एक ग्राहक की सदस्यता ले रहा था। उत्तर के लिए बहुत बहुत धन्यवाद! यह महान काम करता है
कोर्टपीस

27

आप Observableasync तर्क भाग को संभालने के लिए उपयोग कर सकते हैं । यहाँ मैं उदाहरण के लिए परीक्षण कोड है:

import { Injectable } from '@angular/core';
import { CanActivate } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { DetailService } from './detail.service';

@Injectable()
export class DetailGuard implements CanActivate {

  constructor(
    private detailService: DetailService
  ) {}

  public canActivate(): boolean|Observable<boolean> {
    if (this.detailService.tempData) {
      return true;
    } else {
      console.log('loading...');
      return new Observable<boolean>((observer) => {
        setTimeout(() => {
          console.log('done!');
          this.detailService.tempData = [1, 2, 3];
          observer.next(true);
          observer.complete();
        }, 1000 * 5);
      });
    }
  }
}

2
यह वास्तव में एक अच्छा जवाब है जिसने वास्तव में मेरी मदद की। भले ही मेरे पास एक समान प्रश्न था, लेकिन स्वीकृत जवाब से मेरी समस्या हल नहीं हुई। इसने किया
कोंस्टेंटिन

दरअसल, यह सही जवाब है !!! एक async फ़ंक्शन को कॉल करने के लिए canActivate विधि का उपयोग करने का एक अच्छा तरीका है।
डैनिलो


13

आप एक वादा के रूप में सच | झूठ को वापस कर सकते हैं।

import {Injectable} from '@angular/core';
import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot} from '@angular/router';
import {Observable} from 'rxjs';
import {AuthService} from "../services/authorization.service";

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

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
  return new Promise((resolve, reject) => {
  this.authService.getAccessRights().then((response) => {
    let result = <any>response;
    let url = state.url.substr(1,state.url.length);
    if(url == 'getDepartment'){
      if(result.getDepartment){
        resolve(true);
      } else {
        this.router.navigate(['login']);
        resolve(false);
      }
    }

     })
   })
  }
}

1
वह नया प्रॉमिस ऑब्जेक्ट मुझे बचाता है: डी थैंक्स।
canmustu

धन्यवाद। यह समाधान तब तक इंतजार करता है जब तक कि एप कॉल का जवाब नहीं देता है और फिर रीडायरेक्ट होता है।
फिलिप कुल

यह स्पष्ट प्रॉमिस कंस्ट्रक्टर एंटीपैटर्न ( stackoverflow.com/questions/23803743/… ) के उदाहरण जैसा दिखता है । कोड का उदाहरण getAccessRights () पहले से ही एक वादा देता है, इसलिए मैं सीधे इसे वापस करने की कोशिश करता हूं return this.authService.getAccessRights().then...और बिना परिणाम के बूलियन परिणाम वापस करता हूं resolve
रोब

6

सबसे लोकप्रिय उत्तर पर विस्तार करने के लिए। AngularFire2 के लिए प्रामाणिक API में कुछ बदलाव हैं। यह एक AngularFire2 AuthGuard प्राप्त करने के लिए नया हस्ताक्षर है:

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { AngularFireAuth } from 'angularfire2/auth';
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';

@Injectable()
export class AuthGuardService implements CanActivate {

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

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):Observable<boolean>|boolean {
    return this.auth.authState.map(User => {
      return (User) ? true : false;
    });
  }
}

नोट: यह एक काफी भोली परीक्षा है। यदि आप उपयोगकर्ता के कुछ और विस्तृत पहलू के खिलाफ परीक्षण करना चाहते हैं, तो आप यह देखने के लिए उपयोगकर्ता उदाहरण को सांत्वना दे सकते हैं। लेकिन कम से कम उन लोगों के खिलाफ मार्गों की रक्षा में मदद करनी चाहिए जो लॉग इन नहीं हैं।


5

AngularFire के सबसे हाल के संस्करण में, निम्नलिखित कोड काम करता है (सर्वश्रेष्ठ उत्तर से संबंधित)। "पाइप" विधि के उपयोग पर ध्यान दें।

import { Injectable } from '@angular/core';
import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot} from '@angular/router';
import {AngularFireAuth} from '@angular/fire/auth';
import {map} from 'rxjs/operators';
import {Observable} from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class AuthGuardService implements CanActivate {

  constructor(private afAuth: AngularFireAuth, private router: Router) {
  }

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    return this.afAuth.authState.pipe(
      map(user => {
        if(user) {
          return true;
        } else {
          this.router.navigate(['/login']);
          return false;
        }
      })
    );
  }
}


मेरे पास isLoggedIn () के बाद 1 और XHR कॉल है, और XHR का परिणाम 2nd XHR कॉल में उपयोग किया जाता है। 2 ajax कॉल कैसे करें जो 1 परिणाम के लिए स्वीकार करेगा? आपके द्वारा दिया गया उदाहरण बहुत आसान है, क्या आप मुझे बता सकते हैं कि यदि मेरे पास एक और अजाक्स भी है तो मैं मानचित्र का उपयोग कैसे कर सकता हूं।
प्रतिक

2

मेरे मामले में मुझे अलग-अलग व्यवहार को संभालने की ज़रूरत थी जो प्रतिक्रिया स्थिति त्रुटि पर निर्भर करता है। यह मेरे लिए RxJS 6+ के साथ काम करता है:

@Injectable()
export class AuthGuard implements CanActivate {

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

  public canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean> | boolean {
    return this.auth.pipe(
      tap({
        next: val => {
          if (val) {
            console.log(val, 'authenticated');
            return of(true); // or if you want Observable replace true with of(true)
          }
          console.log(val, 'acces denied!');
          return of(false); // or if you want Observable replace true with of(true)
        },
        error: error => {
          let redirectRoute: string;
          if (error.status === 401) {
            redirectRoute = '/error/401';
            this.router.navigateByUrl(redirectRoute);
          } else if (error.status === 403) {
            redirectRoute = '/error/403';
            this.router.navigateByUrl(redirectRoute);
          }
        },
        complete: () => console.log('completed!')
      })
    );
  }
}

कुछ मामलों में यह काम नहीं कर सकता है, कम से कम ऑपरेटर का nextहिस्सा । इसे निकालें और नीचे की तरह पुराना अच्छा जोड़ें :tapmap

  public canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean> | boolean {
    return this.auth.pipe(
      map((auth) => {
        if (auth) {
          console.log('authenticated');
          return true;
        }
        console.log('not authenticated');
        this.router.navigateByUrl('/login');
        return false;
      }),
      tap({
        error: error => {
          let redirectRoute: string;
          if (error.status === 401) {
            redirectRoute = '/error/401';
            this.router.navigateByUrl(redirectRoute);
          } else if (error.status === 403) {
            redirectRoute = '/error/403';
            this.router.navigateByUrl(redirectRoute);
          }
        },
        complete: () => console.log('completed!')
      })
    );
  }

0

कार्यान्वयन का दूसरा तरीका दिखाने के लिए। प्रलेखन के अनुसार , और अन्य उत्तरों द्वारा उल्लिखित प्रकार के कैनएक्टिनेट भी एक वादा हो सकता है जो बूलियन का समाधान करता है।

नोट : दिखाया गया उदाहरण कोणीय 11 में लागू किया गया है, लेकिन कोणीय 2+ संस्करणों पर लागू होता है।

उदाहरण:

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

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

  canActivate(
    route: ActivatedRouteSnapshot, state: RouterStateSnapshot
  ): Observable < boolean | UrlTree > | Promise < boolean | UrlTree > | boolean | UrlTree {
    return this.checkAuthentication();
  }

  async checkAuthentication(): Promise < boolean > {
    // Implement your authentication in authService
    const isAuthenticate: boolean = await this.authService.isAuthenticated();
    return isAuthenticate;
  }

  canActivateChild(
    childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot
  ): Observable < boolean | UrlTree > | Promise < boolean | UrlTree > | boolean | UrlTree {
    return this.canActivate(childRoute, state);
  }
}


0

async प्रतीक्षा का उपयोग कर रहे हैं ... आप के समाधान के वादे की प्रतीक्षा करते हैं

async getCurrentSemester() {
    let boolReturn: boolean = false
    let semester = await this.semesterService.getCurrentSemester().toPromise();
    try {

      if (semester['statusCode'] == 200) {
        boolReturn = true
      } else {
        this.router.navigate(["/error-page"]);
        boolReturn = false
      }
    }
    catch (error) {
      boolReturn = false
      this.router.navigate(["/error-page"]);
    }
    return boolReturn
  }

यहाँ मेरा गौड़ गौर है (@angular v7.2)

async canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    let security: any = null
    if (next.data) {
      security = next.data.security
    }
    let bool1 = false;
    let bool2 = false;
    let bool3 = true;

    if (this.webService.getCookie('token') != null && this.webService.getCookie('token') != '') {
      bool1 = true
    }
    else {
      this.webService.setSession("currentUrl", state.url.split('?')[0]);
      this.webService.setSession("applicationId", state.root.queryParams['applicationId']);
      this.webService.setSession("token", state.root.queryParams['token']);
      this.router.navigate(["/initializing"]);
      bool1 = false
    }
    bool2 = this.getRolesSecurity(next)
    if (security && security.semester) {
      // ----  watch this peace of code
      bool3 = await this.getCurrentSemester()
    }

    console.log('bool3: ', bool3);

    return bool1 && bool2 && bool3
  }

मार्ग है

    { path: 'userEvent', component: NpmeUserEvent, canActivate: [AuthGuard], data: {  security: { semester: true } } },
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.