Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(): Angularfire auth guards #2016

Merged
merged 13 commits into from
May 23, 2019
Merged

feat(): Angularfire auth guards #2016

merged 13 commits into from
May 23, 2019

Conversation

jamesdaniels
Copy link
Member

@jamesdaniels jamesdaniels commented Feb 22, 2019

Checklist

  • Issue number for this PR: #nnn (required)
  • Docs included?: (yes/no; required for all API/functional changes)
  • Test units included?: (yes/no; required)
  • In a clean directory, yarn install, yarn test run successfully? (yes/no; required)

Description

Allow developers to protect routes in their Angular application using Firebase authentication.

TODOs

  • Get test coverage
  • Polish the documentation

Code sample

Basic example

import { AngularFireAuthGuard } from '@angular/fire/auth-guard';

export const routes: Routes = [
    { path: '',      component: AppComponent },
    { path: 'items', component: ItemListComponent, canActivate: [AngularFireAuthGuard] },
]

Use our pre-built pipes for common tests

import { AngularFireAuthGuard, hasCustomClaim, redirectUnauthorizedTo, redirectLoggedInTo } from '@angular/fire/auth-guard';

const adminOnly = hasCustomClaim('admin');
const redirectUnauthorizedToLogin = redirectUnauthorizedTo(['login']);
const redirectLoggedInToItems = redirectLoggedInTo(['items']);
const belongsToAccount = (next) => hasCustomClaim(`account-${next.params.id}`);

export const routes: Routes = [
    { path: '',      component: AppComponent },
    { path: 'login', component: LoginComponent,        canActivate: [AngularFireAuthGuard], data: { authGuardPipe: redirectLoggedInToItems }},
    { path: 'items', component: ItemListComponent,     canActivate: [AngularFireAuthGuard], data: { authGuardPipe: redirectUnauthorizedToLogin },
    { path: 'admin', component: AdminComponent,        canActivate: [AngularFireAuthGuard], data: { authGuardPipe: adminOnly }},
    { path: 'accounts/:id', component: AdminComponent, canActivate: [AngularFireAuthGuard], data: { authGuardPipe: belongsToAccount }}
];

Increase readability with our canActivate helper

import { canActivate } from '@angular/fire/auth-guard';

export const routes: Routes = [
    { path: '',             component: AppComponent },
    { path: 'login',        component: LoginComponent,    ...canActivate(redirectLoggedInToItems) },
    { path: 'items',        component: ItemListComponent, ...canActivate(redirectUnauthorizedToLogin) },
    { path: 'admin',        component: AdminComponent,    ...canActivate(adminOnly) },
    { path: 'accounts/:id', component: AdminComponent,    ...canActivate(belongsToAccount) }
];

Compose your own pipes

import { pipe, of } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { customClaims } from '@angular/fire/auth-guard';

const editorOnly = pipe(customClaims, map(claims => claims.role === "editor"));
const redirectToProfileEditOrLogin = map(user => user ? ['profiles', user.uid, 'edit'] : ['login']);
const onlyAllowSelf = (next) => map(user => !!user && next.params.userId === user.uid);
const accountAdmin = (next) => pipe(customClaims, map(claims => claims[`account-${next.params.accountId}-role`] === "admin"));

@jamesdaniels jamesdaniels added this to the 5.2.0 milestone Feb 22, 2019
@jamesdaniels
Copy link
Member Author

@davideast feel free to start poking at this. Going to work on the test coverage and documentation in the meantime. Targeting 5.2 release.

@jamesdaniels
Copy link
Member Author

FYI this has been released for testing on @next as of 5.2.0-beta.3

@hiepxanh
Copy link
Contributor

wow, so convinent :D thank you so much

@jamesdaniels jamesdaniels requested a review from jhuleatt May 20, 2019 00:48
@jamesdaniels jamesdaniels changed the title WIP Angularfire auth guards feat(): Angularfire auth guards May 20, 2019
@jamesdaniels
Copy link
Member Author

Assigning @davideast for API review. @jhuleatt if you could give a quick code review.

@jamesdaniels
Copy link
Member Author

FYI tests and docs need more work.

docs/auth/router-guards.md Outdated Show resolved Hide resolved
src/auth-guard/auth-guard.ts Show resolved Hide resolved

it('should be injectable', () => {
expect(router).toBeTruthy();
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here's a StackOverflow answer with suggestions on ways to test auth guards. But maybe that's overkill and we just have a dummy user object and quick happy path tests for the different built-in pipes for now?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe also spy on the AngularFireAuthGuard pipe to make sure it calls the pipe provided to it with the data provided to it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'll have to put together a proper E2E for this, something I'm working on on another branch. Think I'll punt on building more robust tests for now & take it as an action item.

docs/auth/router-guards.md Show resolved Hide resolved
Copy link
Member

@davideast davideast left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking of stronger names for these, but honestly I couldn't come up with something that much better. LGTM.

@jamesdaniels jamesdaniels merged commit e32164d into master May 23, 2019
@jamesdaniels jamesdaniels deleted the auth-gaurd branch May 23, 2019 00:03
@svzi
Copy link

svzi commented May 23, 2019

Any idea when there will be a new release with the merged PR?

@jamesdaniels
Copy link
Member Author

@svzi you can give this a try now with the beta 4 release. npm i --save @angular/fire@next.

I'm hoping to release 5.2 stable early next week.

@svzi
Copy link

svzi commented May 24, 2019

@jamesdaniels Thanks a lot! But it seems like I'm missing something, or there is something not working right now. I can't compile it (based on the provided examples):

ERROR in node_modules/@angular/fire/auth-guard/auth-guard.d.ts(11,5): error TS2416: Property 'canActivate' in type 'AngularFireAuthGuard' is not assignable to the same property in base type 'CanActivate'.
  Type '(next: ActivatedRouteSnapshot, state: RouterStateSnapshot) => Observable<boolean | UrlTree>' is not assignable to type '(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => boolean | UrlTree | Observable<boolean | UrlTree> | Promise<boolean | UrlTree>'.
    Type 'Observable<boolean | UrlTree>' is not assignable to type 'boolean | UrlTree | Observable<boolean | UrlTree> | Promise<boolean | UrlTree>'.

@jamesdaniels
Copy link
Member Author

@svzi which version of typescript / Ng?

@svzi
Copy link

svzi commented May 24, 2019

@jamesdaniels Angular 7.2.0 (CLI 7.3.9) and TypeScript 3.2.2.

@jamesdaniels
Copy link
Member Author

I'll look into this. Will track here #2086

@svzi
Copy link

svzi commented May 24, 2019

Thanks a lot, appreciate your support!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants