Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

[Feature Request] authCanMatchGuard + helpers

Aperta
#3,544 1 commento 3 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
35/100
Tipo di issue
Funzionalità
Chiarezza
Abbastanza chiara
Stato di attività
Ferma
Stack tecnologico
angular, firebase, typescript

Direzione di ricerca

Leggi prima src/auth-guard/auth-guard.ts e site/src/auth/route-guards.md, quindi confrontali con l'implementazione proposta di auth-can-match.guard.ts. Il lavoro è completato quando il guard canMatch funzionale e gli helper sono integrati in AngularFire e vengono aggiunti test per il loro comportamento di autenticazione e reindirizzamento.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

Feature Request - authCanMatchGuard + helpers

Description

The current auth-guard provided with angular fire is still using the now deprecated class based approach and targets the canActivate property on route definitions.

To freshen things up a bit, I have generated a new guard which utilizes the new functional approach and targets the newer canMatch route definition property. This has the added benefit of preventing components from being unnecessarily loaded which seems to work well and should be more performant.

I based the new code off of the previous implementation documented here. You will notice similarities with the previous guard code here. Would love to see this incorporated into the AngularFire package but honestly I'm too lazy to write tests 😅 so if someone would be interested in owning that and collaborating, I'd be happy to open up a PR.

Code

auth-can-match.guard.ts

import { inject } from '@angular/core';
import { Auth, user, User } from '@angular/fire/auth';
import { CanMatchFn, Route, Router, UrlSegment } from '@angular/router';
import { Observable, of, pipe, UnaryFunction } from 'rxjs';
import { map, switchMap, take } from 'rxjs/operators';

/** Utility type to allow for adding an additional property to the CanMatchFn type */
type ExtendFn<BaseFnT, AddPT extends any[]> = BaseFnT extends (...a: infer P) => infer R
  ? (...a: [...P, ...AddPT]) => R
  : never

export type AuthPipe = UnaryFunction<Observable<User | null>, Observable<boolean | string | any[]>>;
export const authCanMatchGuard: ExtendFn<CanMatchFn, [authPipe: AuthPipe]> = (route, segments, authPipe?) => {
  const auth = inject(Auth)
  const user$ = user(auth)
  const router = inject(Router)

  const authPipeFactory = authPipe
    ? authPipe
    : loggedIn

  return user$
    .pipe(
      take(1),
      authPipeFactory,
      map(can => {
        if (typeof can === 'boolean') {
          return can;
        } else if (Array.isArray(can)) {
          return router.createUrlTree(can)
        } else {
          return router.parseUrl(can)
        }
      })
    )
}

/** canMatch helper to be used with spread operator to make route definitions more concise.
 * @example
 * const redirectUnauthorizedToLogin = redirectUnauthorizedTo(['login'])
 * ...
 * export const routes: Routes = [
 *  {
 *    ...authCanMatch(redirectUnauthorizedToLogin)
 *    path: 'authProtectedRoute'
 *  },
 */
export const authCanMatch = (authPipe: AuthPipe) =>
  ({ canMatch: [(route: Route, segments: UrlSegment[]) => authCanMatchGuard(route, segments, authPipe)] })

/** Predefined auth guard helper pipes. So friendly & helpful 😍 */
export const loggedIn: AuthPipe = map(user => !!user)
export const isNotAnonymous: AuthPipe = map(user => !!user && !user.isAnonymous)
export const idTokenResult = switchMap((user: User | null) => user ? user.getIdTokenResult() : of(null))
export const emailVerified: AuthPipe = map(user => !!user && user.emailVerified)
export const customClaims = pipe(idTokenResult, map(idTokenResult => idTokenResult ? idTokenResult.claims : []))
export const hasCustomClaim: (claim: string) => AuthPipe =
  // eslint-disable-next-line no-prototype-builtins
  (claim) => pipe(customClaims, map(claims => claims.hasOwnProperty(claim)))
export const redirectUnauthorizedTo: (redirect: string | any[]) => AuthPipe =
  (redirect) => pipe(loggedIn, map(loggedIn => loggedIn || redirect))
export const redirectLoggedInTo: (redirect: string | any[]) => AuthPipe =
  (redirect) => pipe(loggedIn, map(loggedIn => loggedIn && redirect || true))
Lingua principale
TypeScript
Stelle
7.8k
Fork
2.2k
Merge medio
3g 6h
PR unite (30g)
5

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di angular/angularfire

Tutte le issue di angular/angularfire

Issue simili

Altre issue su TypeScript

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.