angular / angular/angularfire

[Feature Request] authCanMatchGuard + helpers

オープン
#3,544 コメント 1 件 リアクション 3 件 担当者 0 名 GitHub で見る
主要言語
TypeScript
スター
7.8k
フォーク
2.2k
平均マージ
22時間 28分
マージ済み PR(30日)
6

説明

# Feature Request - authCanMatchGuard + helpers
## Description
The current auth-guard provided with angular fire is still using the [now deprecated](https://github.com/angular/angular/pull/47924) 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](https://github.com/angular/angularfire/blob/3639e41b52c0b2963c1e24734ff8401f4d21107e/site/src/auth/route-guards.md). You will notice similarities with [the previous guard code here](https://github.com/angular/angularfire/blob/3639e41b52c0b2963c1e24734ff8401f4d21107e/src/auth-guard/auth-guard.ts). 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 extends (...a: infer P) => infer R
? (...a: [...P, ...AddPT]) => R
: never

export type AuthPipe = UnaryFunction, Observable>;
export const authCanMatchGuard: ExtendFn = (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))
```

コントリビューションガイド

コントリビューションガイドを開く

調査の方向性

まず src/auth-guard/auth-guard.ts と site/src/auth/route-guards.md を読み、その後、提案されている auth-can-match.guard.ts の実装と比較してください。機能する canMatch guard とヘルパーを AngularFire に統合し、それらの認証およびリダイレクト動作のテストを追加すれば完了です。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
angular, firebase, typescript
領域
authentication, frontend
issue の種類
機能追加
難易度
4/5
見積もり時間
3〜5日
活発さ
停滞
明瞭さ
おおむね明確
初心者へのやさしさ
35/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。