浏览代码

24-322 Switching to NgRx for authentication

ngrx
Nils Dittberner 8 年前
父节点
当前提交
bae3653b7a
共有 13 个文件被更改,包括 147 次插入54 次删除
  1. +2
    -2
      src/app/app.module.ts
  2. +9
    -3
      src/app/auth/auth-guard.service.ts
  3. +24
    -18
      src/app/auth/auth.service.ts
  4. +26
    -0
      src/app/auth/ngrx/auth.actions.ts
  5. +35
    -0
      src/app/auth/ngrx/auth.reducers.ts
  6. +3
    -3
      src/app/core/header/header.component.html
  7. +15
    -7
      src/app/core/header/header.component.ts
  8. +14
    -0
      src/app/ngrx/app.reducers.ts
  9. +2
    -2
      src/app/recipes/recipe-detail/recipe-detail.component.ts
  10. +13
    -6
      src/app/shared/auth.interceptor.ts
  11. +0
    -9
      src/app/shopping-list/ngrx/shopping-list.reducers.ts
  12. +2
    -2
      src/app/shopping-list/shopping-edit/shopping-edit.component.ts
  13. +2
    -2
      src/app/shopping-list/shopping-list.component.ts

+ 2
- 2
src/app/app.module.ts 查看文件

@@ -9,7 +9,7 @@ import { SharedModule } from './shared/shared.module';
import { ShoppingListModule } from './shopping-list/shopping-list.module';
import { AuthModule } from './auth/auth.module';
import { CoreModule } from './core/core.module';
import { shoppingListReducer } from './shopping-list/ngrx/shopping-list.reducers';
import { appReducers } from './ngrx/app.reducers';

@NgModule({
declarations: [
@@ -23,7 +23,7 @@ import { shoppingListReducer } from './shopping-list/ngrx/shopping-list.reducers
ShoppingListModule,
AuthModule,
CoreModule,
StoreModule.forRoot({shoppingList: shoppingListReducer})
StoreModule.forRoot(appReducers)
],
bootstrap: [AppComponent]
})


+ 9
- 3
src/app/auth/auth-guard.service.ts 查看文件

@@ -1,14 +1,20 @@
import { CanActivate } from "@angular/router";
import { ActivatedRouteSnapshot, RouterStateSnapshot } from "@angular/router/src/router_state";
import { Injectable } from "@angular/core";
import { AuthService } from "./auth.service";
import { Store } from "@ngrx/store";
import "rxjs/add/operator/map";

import * as fromApp from '../ngrx/app.reducers';
import * as fromAuth from './ngrx/auth.reducers';

@Injectable()
export class AuthGuard implements CanActivate {
constructor(private authService: AuthService) {}
constructor(private store: Store<fromApp.AppState>) {}

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
return this.authService.isAuthenticated();
return this.store.select('auth').map((authState: fromAuth.State) => {
return authState.authenticated;
});
}
}

+ 24
- 18
src/app/auth/auth.service.ts 查看文件

@@ -1,15 +1,30 @@
import * as firebase from 'firebase';
import { Router } from '@angular/router';
import { Injectable } from '@angular/core';
import { Store } from '@ngrx/store';

import * as fromApp from '../ngrx/app.reducers';
import * as AuthActions from './ngrx/auth.actions';

@Injectable()
export class AuthService {
token: string;

constructor(private router: Router) {}
constructor(private router: Router, private store: Store<fromApp.AppState>) {}

signupUser(email: string, password: string) {
firebase.auth().createUserWithEmailAndPassword(email, password).catch(
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(
user => {
this.store.dispatch(new AuthActions.Signup());
firebase.auth().currentUser.getIdToken()
.then(
(token: string) => {
this.store.dispatch(new AuthActions.SetToken(token));
}
);

}
)
.catch(
error => console.log(error)
);
}
@@ -18,10 +33,13 @@ export class AuthService {
firebase.auth().signInWithEmailAndPassword(email, password)
.then(
response => {
this.store.dispatch(new AuthActions.Signin());
this.router.navigate(['/']);
firebase.auth().currentUser.getIdToken()
.then(
(token: string) => this.token = token
(token: string) => {
this.store.dispatch(new AuthActions.SetToken(token));
}
);
}
)
@@ -32,19 +50,7 @@ export class AuthService {

logout() {
firebase.auth().signOut();
this.token = null;
this.store.dispatch(new AuthActions.Logout());
this.router.navigate(['/']);
}

getToken() {
firebase.auth().currentUser.getIdToken()
.then(
(token: string) => this.token = token
);
return this.token;
}

isAuthenticated() {
return this.token != null;
}
}

+ 26
- 0
src/app/auth/ngrx/auth.actions.ts 查看文件

@@ -0,0 +1,26 @@
import { Action } from '@ngrx/store';

export const SIGNUP = 'SIGNUP';
export const SIGNIN = 'SIGNIN';
export const LOGOUT = 'LOGOUT';
export const SET_TOKEN = 'SET_TOKEN';

export class Signup implements Action {
readonly type = SIGNUP;
}

export class Signin implements Action {
readonly type = SIGNIN;
}

export class Logout implements Action {
readonly type = LOGOUT;
}

export class SetToken implements Action {
readonly type = SET_TOKEN;

constructor(public payload: string) {}
}

export type AuthActions = Signup | Signin | Logout | SetToken;

+ 35
- 0
src/app/auth/ngrx/auth.reducers.ts 查看文件

@@ -0,0 +1,35 @@
import * as AuthActions from './auth.actions';

export interface State {
token: string;
authenticated: boolean;
}

const initialState: State = {
token: null,
authenticated: false
};

export function authReducers(state = initialState, action: AuthActions.AuthActions) {
switch (action.type) {
case AuthActions.SIGNUP:
case AuthActions.SIGNIN:
return {
...state,
authenticated: true
};
case AuthActions.LOGOUT:
return {
...state,
token: null,
authenticated: false
};
case AuthActions.SET_TOKEN:
return {
...state,
token: action.payload
};
default:
return state;
}
}

+ 3
- 3
src/app/core/header/header.component.html 查看文件

@@ -10,12 +10,12 @@
<li routerLinkActive="active"><a routerLink="/shopping-list">Shopping List</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<ng-template [ngIf]="!isAuthenticated()">
<ng-template [ngIf]="!(authState | async).authenticated">
<li><a routerLink="/signup">Register</a></li>
<li><a routerLink="/signin">Login</a></li>
</ng-template>
<li><a style="cursor: pointer;" (click)="onLogout()" *ngIf="isAuthenticated()">Logout</a></li>
<li class="dropdown" appDropdown *ngIf="isAuthenticated()">
<li><a style="cursor: pointer;" (click)="onLogout()" *ngIf="(authState | async).authenticated">Logout</a></li>
<li class="dropdown" appDropdown *ngIf="(authState | async).authenticated">
<a style="cursor: pointer;" class="dropdown-toggle" role="button">Manage <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a style="cursor: pointer;" (click)="onSaveData()">Save</a></li>


+ 15
- 7
src/app/core/header/header.component.ts 查看文件

@@ -1,14 +1,26 @@
import { Component } from "@angular/core";
import { Component, OnInit } from "@angular/core";
import { Store } from "@ngrx/store";
import { Observable } from "rxjs/Observable";

import { DataStorageService } from "../../shared/data-storage.service";
import { AuthService } from "../../auth/auth.service";
import * as fromApp from '../../ngrx/app.reducers';
import * as fromAuth from '../../auth/ngrx/auth.reducers';

@Component({
selector: 'app-header',
templateUrl: './header.component.html'
})
export class HeaderComponent {
export class HeaderComponent implements OnInit {
authState: Observable<fromAuth.State>;

constructor(private dataStorageService: DataStorageService,
private authService: AuthService,
private store: Store<fromApp.AppState>) {}

constructor(private dataStorageService: DataStorageService, private authService: AuthService) {}
ngOnInit() {
this.authState = this.store.select('auth')
}

onSaveData() {
this.dataStorageService.storeRecipes().subscribe(
@@ -25,8 +37,4 @@ export class HeaderComponent {
onLogout() {
this.authService.logout();
}

isAuthenticated() {
return this.authService.isAuthenticated();
}
}

+ 14
- 0
src/app/ngrx/app.reducers.ts 查看文件

@@ -0,0 +1,14 @@
import { ActionReducerMap } from '@ngrx/store/src/models';

import * as fromShoppingList from '../shopping-list/ngrx/shopping-list.reducers'
import * as fromAuth from '../auth/ngrx/auth.reducers'

export interface AppState {
shoppingList: fromShoppingList.State,
auth: fromAuth.State
}

export const appReducers: ActionReducerMap<AppState> = {
shoppingList: fromShoppingList.shoppingListReducer,
auth: fromAuth.authReducers
};

+ 2
- 2
src/app/recipes/recipe-detail/recipe-detail.component.ts 查看文件

@@ -5,7 +5,7 @@ import { Store } from '@ngrx/store';
import { Recipe } from '../recipe.model';
import { RecipeService } from '../recipe.service';
import * as ShoppingListActions from '../../shopping-list/ngrx/shopping-list.actions';
import * as fromShoppingList from '../../shopping-list/ngrx/shopping-list.reducers';
import * as fromApp from '../../ngrx/app.reducers';

@Component({
selector: 'app-recipe-detail',
@@ -19,7 +19,7 @@ export class RecipeDetailComponent implements OnInit {
constructor(private recipeService: RecipeService,
private route: ActivatedRoute,
private router: Router,
private store: Store<fromShoppingList.AppState>) { }
private store: Store<fromApp.AppState>) { }

ngOnInit() {
this.route.params.subscribe(


+ 13
- 6
src/app/shared/auth.interceptor.ts 查看文件

@@ -1,16 +1,23 @@
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http'
import { Observable } from 'rxjs/Observable';
import { Injectable } from '@angular/core';
import { AuthService } from '../auth/auth.service';
import { Store } from "@ngrx/store";
import "rxjs/add/operator/switchMap";
import "rxjs/add/operator/take";

import * as fromApp from '../ngrx/app.reducers';
import * as fromAuth from '../auth/ngrx/auth.reducers';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private authService: AuthService) {}
constructor(private store: Store<fromApp.AppState>) {}

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const copiedReq = req.clone({
params: req.params.set('auth', this.authService.getToken())
});
return next.handle(copiedReq);
return this.store.select('auth')
.take(1)
.switchMap((authState: fromAuth.State) => {
const copiedReq = req.clone({params: req.params.set('auth', authState.token)});
return next.handle(copiedReq);
});
}
}

+ 0
- 9
src/app/shopping-list/ngrx/shopping-list.reducers.ts 查看文件

@@ -2,21 +2,12 @@ import * as ShoppingListActions from './shopping-list.actions';

import { Ingredient } from '../../shared/ingredient.model';

export interface AppState {
shoppingList: State
}

export interface State {
ingredients: Ingredient[];
editedIngredient: Ingredient;
editedIngredientIndex: number;
}

export const ADD_INGREDIENT = 'ADD_INGREDIENT';
export const ADD_INGREDIENTS = 'ADD_INGREDIENTS';
export const UPDATE_INGREDIENT = 'UPDATE_INGREDIENT';
export const DELETE_INGREDIENT = 'DELETE_INGREDIENT';

const initialState: State = {
ingredients: [
new Ingredient('Banana', 10)


+ 2
- 2
src/app/shopping-list/shopping-edit/shopping-edit.component.ts 查看文件

@@ -5,7 +5,7 @@ import { Store } from '@ngrx/store';

import { Ingredient } from '../../shared/ingredient.model';
import * as ShoppingListActions from '../ngrx/shopping-list.actions';
import * as fromShoppingList from '../ngrx/shopping-list.reducers';
import * as fromApp from '../../ngrx/app.reducers'

@Component({
selector: 'app-shopping-edit',
@@ -18,7 +18,7 @@ export class ShoppingEditComponent implements OnInit, OnDestroy {
editMode = false;
editedItem: Ingredient;

constructor(private store: Store<fromShoppingList.AppState>) { }
constructor(private store: Store<fromApp.AppState>) { }

ngOnInit() {
this.subscription = this.store.select('shoppingList').subscribe(


+ 2
- 2
src/app/shopping-list/shopping-list.component.ts 查看文件

@@ -4,7 +4,7 @@ import { Observable } from 'rxjs/Observable';

import { Ingredient } from '../shared/ingredient.model';
import * as ShoppingListActions from './ngrx/shopping-list.actions';
import * as fromShoppingList from './ngrx/shopping-list.reducers';
import * as fromApp from '../ngrx/app.reducers'

@Component({
selector: 'app-shopping-list',
@@ -14,7 +14,7 @@ import * as fromShoppingList from './ngrx/shopping-list.reducers';
export class ShoppingListComponent implements OnInit {
shoppingListState: Observable<{ingredients: Ingredient[]}>;

constructor(private store: Store<fromShoppingList.AppState>) { }
constructor(private store: Store<fromApp.AppState>) { }

ngOnInit() {
this.shoppingListState = this.store.select('shoppingList');


正在加载...
取消
保存