diff options
author | crupest <crupest@outlook.com> | 2019-03-18 21:21:56 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2019-03-18 21:21:56 +0800 |
commit | 69ede25976c11f0624036251523d5f1d28811740 (patch) | |
tree | 97f461c68c2a9b3d3967afefc7b3015e80107e3d /Timeline/ClientApp/src | |
parent | e973ad02680f9d9ffdb9f7ac5aff9283484d2f46 (diff) | |
download | timeline-69ede25976c11f0624036251523d5f1d28811740.tar.gz timeline-69ede25976c11f0624036251523d5f1d28811740.tar.bz2 timeline-69ede25976c11f0624036251523d5f1d28811740.zip |
Add logout. Fix a bug.
The bug is it always goes to login page whether you have login or not before when user is presented in url.
Diffstat (limited to 'Timeline/ClientApp/src')
9 files changed, 82 insertions, 26 deletions
diff --git a/Timeline/ClientApp/src/app/user/auth.guard.ts b/Timeline/ClientApp/src/app/user/auth.guard.ts index 561a0c53..1fc7a7c0 100644 --- a/Timeline/ClientApp/src/app/user/auth.guard.ts +++ b/Timeline/ClientApp/src/app/user/auth.guard.ts @@ -1,6 +1,7 @@ import { Injectable } from '@angular/core'; import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from '@angular/router'; import { Observable } from 'rxjs'; +import { take, map } from 'rxjs/operators'; import { InternalUserService } from './internal-user-service/internal-user.service'; @@ -23,26 +24,26 @@ export abstract class AuthGuard implements CanActivate { return true; } - const { currentUserInfo } = this.internalUserService; - - if (currentUserInfo === null) { - if (authStrategy === 'requirenologin') { - return true; - } - } else { - if (authStrategy === 'requirelogin') { - return true; - } else if (authStrategy instanceof Array) { - const { roles } = currentUserInfo; - if (authStrategy.every(value => roles.includes(value))) { + return this.internalUserService.userInfo$.pipe(take(1), map(userInfo => { + if (userInfo === null) { + if (authStrategy === 'requirenologin') { return true; } + } else { + if (authStrategy === 'requirelogin') { + return true; + } else if (authStrategy instanceof Array) { + const { roles } = userInfo; + if (authStrategy.every(value => roles.includes(value))) { + return true; + } + } } - } - // reach here means auth fails - this.onAuthFailed(); - return false; + // reach here means auth fails + this.onAuthFailed(); + return false; + })); } } diff --git a/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.ts b/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.ts index 2098391e..d82e9613 100644 --- a/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.ts +++ b/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.ts @@ -3,7 +3,7 @@ import { HttpClient, HttpErrorResponse } from '@angular/common/http'; import { Router } from '@angular/router'; import { Observable, throwError, BehaviorSubject, of } from 'rxjs'; -import { map, catchError, retry, switchMap, tap } from 'rxjs/operators'; +import { map, catchError, retry, switchMap, tap, filter } from 'rxjs/operators'; import { AlreadyLoginError, BadCredentialsError, BadNetworkError, UnknownError } from './errors'; import { @@ -35,14 +35,13 @@ export const TOKEN_STORAGE_KEY = 'token'; export class InternalUserService { private token: string | null = null; - private userInfoSubject = new BehaviorSubject<UserInfo | null>(null); + private userInfoSubject = new BehaviorSubject<UserInfo | null | undefined>(undefined); - get currentUserInfo(): UserInfo | null { - return this.userInfoSubject.value; - } + readonly userInfo$: Observable<UserInfo | null> = + <Observable<UserInfo | null>>this.userInfoSubject.pipe(filter(value => value !== undefined)); - get userInfo$(): Observable<UserInfo | null> { - return this.userInfoSubject; + get currentUserInfo(): UserInfo | null | undefined { + return this.userInfoSubject.value; } private openSnackBar(snackBar: MatSnackBar, textKey: SnackBarTextKey) { @@ -129,4 +128,14 @@ export class InternalUserService { }) ); } + + logout() { + if (this.currentUserInfo === null) { + throw new Error('No login now. You can\'t logout.'); + } + + this.window.localStorage.removeItem(TOKEN_STORAGE_KEY); + this.token = null; + this.userInfoSubject.next(null); + } } diff --git a/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.html b/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.html index e156f0f8..8599a91d 100644 --- a/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.html +++ b/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.html @@ -3,3 +3,4 @@ </p> <p class="mat-body">You have been login as <span class="username">{{ userInfo.username }}</span>.</p> <p class="mat-body">Your roles are <span class="roles">{{ userInfo.roles.join(', ') }}</span>.</p> +<a mat-flat-button [routerLink]="['..','logout']">Logout</a> diff --git a/Timeline/ClientApp/src/app/user/user-logout/user-logout.component.css b/Timeline/ClientApp/src/app/user/user-logout/user-logout.component.css new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/Timeline/ClientApp/src/app/user/user-logout/user-logout.component.css diff --git a/Timeline/ClientApp/src/app/user/user-logout/user-logout.component.html b/Timeline/ClientApp/src/app/user/user-logout/user-logout.component.html new file mode 100644 index 00000000..56d96b83 --- /dev/null +++ b/Timeline/ClientApp/src/app/user/user-logout/user-logout.component.html @@ -0,0 +1 @@ +<p class="mat-body">Log out succeeded!</p> diff --git a/Timeline/ClientApp/src/app/user/user-logout/user-logout.component.spec.ts b/Timeline/ClientApp/src/app/user/user-logout/user-logout.component.spec.ts new file mode 100644 index 00000000..91369e01 --- /dev/null +++ b/Timeline/ClientApp/src/app/user/user-logout/user-logout.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { UserLogoutComponent } from './user-logout.component'; + +describe('UserLogoutComponent', () => { + let component: UserLogoutComponent; + let fixture: ComponentFixture<UserLogoutComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ UserLogoutComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(UserLogoutComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/Timeline/ClientApp/src/app/user/user-logout/user-logout.component.ts b/Timeline/ClientApp/src/app/user/user-logout/user-logout.component.ts new file mode 100644 index 00000000..24002c84 --- /dev/null +++ b/Timeline/ClientApp/src/app/user/user-logout/user-logout.component.ts @@ -0,0 +1,17 @@ +import { Component, OnInit } from '@angular/core'; +import { InternalUserService } from '../internal-user-service/internal-user.service'; + +@Component({ + selector: 'app-user-logout', + templateUrl: './user-logout.component.html', + styleUrls: ['./user-logout.component.css'] +}) +export class UserLogoutComponent implements OnInit { + + constructor(private userService: InternalUserService) { } + + ngOnInit() { + this.userService.logout(); + } + +} diff --git a/Timeline/ClientApp/src/app/user/user.module.ts b/Timeline/ClientApp/src/app/user/user.module.ts index dcb61736..50c59662 100644 --- a/Timeline/ClientApp/src/app/user/user.module.ts +++ b/Timeline/ClientApp/src/app/user/user.module.ts @@ -16,20 +16,22 @@ import { UserLoginSuccessComponent } from './user-login-success/user-login-succe import { RedirectComponent } from './redirect.component'; import { UtilityModule } from '../utilities/utility.module'; import { WINDOW } from './window-inject-token'; +import { UserLogoutComponent } from './user-logout/user-logout.component'; @NgModule({ - declarations: [UserDialogComponent, UserLoginComponent, UserLoginSuccessComponent, RedirectComponent], + declarations: [UserDialogComponent, UserLoginComponent, UserLoginSuccessComponent, RedirectComponent, UserLogoutComponent], imports: [ RouterModule.forChild([ { path: 'login', canActivate: [RequireNoLoginGuard], component: UserLoginComponent, outlet: 'user' }, { path: 'success', canActivate: [RequireLoginGuard], component: UserLoginSuccessComponent, outlet: 'user' }, + { path: 'logout', canActivate: [RequireLoginGuard], component: UserLogoutComponent, outlet: 'user' }, { path: '**', component: RedirectComponent, outlet: 'user' } ]), CommonModule, HttpClientModule, ReactiveFormsModule, BrowserAnimationsModule, MatFormFieldModule, MatProgressSpinnerModule, MatDialogModule, MatInputModule, MatButtonModule, MatSnackBarModule, UtilityModule ], - providers: [{provide: WINDOW, useValue: window}], + providers: [{ provide: WINDOW, useValue: window }], exports: [RouterModule], entryComponents: [UserDialogComponent] }) diff --git a/Timeline/ClientApp/src/app/user/user.service.ts b/Timeline/ClientApp/src/app/user/user.service.ts index e7d50dd2..6cae2d31 100644 --- a/Timeline/ClientApp/src/app/user/user.service.ts +++ b/Timeline/ClientApp/src/app/user/user.service.ts @@ -29,7 +29,7 @@ export class UserService { }); } - get currentUserInfo(): UserInfo | null { + get currentUserInfo(): UserInfo | null | undefined { return this.internalService.currentUserInfo; } |