auth stuff

This commit is contained in:
2021-06-18 14:07:08 +02:00
parent 677ed3dfd0
commit 79d31e1817
15 changed files with 208 additions and 13 deletions

View File

@ -1,11 +1,15 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router'; import { RouterModule, Routes } from '@angular/router';
import { LoginComponent } from './login/login.component';
import { LogoutComponent } from './logout/logout.component';
import { TestOutputComponent } from './test-output/test-output.component'; import { TestOutputComponent } from './test-output/test-output.component';
const routes: Routes = [ const routes: Routes = [
{ path: 'test', component: TestOutputComponent } { path: 'test', component: TestOutputComponent },
{ path: 'logout', component: LogoutComponent },
{ path: 'login', component: LoginComponent }
] ]
@NgModule({ @NgModule({

View File

@ -17,13 +17,20 @@ import { MatCardModule } from '@angular/material/card';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { ErrorHandlerInterceptor } from './error-handler.interceptor'; import { ErrorHandlerInterceptor } from './error-handler.interceptor';
import { AuthHandlerInterceptor } from './auth-handler.interceptor'; import { AuthHandlerInterceptor } from './auth-handler.interceptor';
import { LogoutComponent } from './logout/logout.component';
import { LoginComponent } from './login/login.component';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatInputModule } from '@angular/material/input';
@NgModule({ @NgModule({
declarations: [ declarations: [
AppComponent, AppComponent,
NavigationComponent, NavigationComponent,
MessagesComponent, MessagesComponent,
TestOutputComponent TestOutputComponent,
LogoutComponent,
LoginComponent
], ],
imports: [ imports: [
BrowserModule, BrowserModule,
@ -36,7 +43,10 @@ import { AuthHandlerInterceptor } from './auth-handler.interceptor';
MatIconModule, MatIconModule,
MatListModule, MatListModule,
MatCardModule, MatCardModule,
AppRoutingModule AppRoutingModule,
FormsModule,
ReactiveFormsModule,
MatInputModule
], ],
providers: [ providers: [
{ provide: HTTP_INTERCEPTORS, useClass: ErrorHandlerInterceptor, multi: true }, { provide: HTTP_INTERCEPTORS, useClass: ErrorHandlerInterceptor, multi: true },

View File

@ -15,9 +15,10 @@ export class AuthHandlerInterceptor implements HttpInterceptor {
constructor(private tokenService: TokenService, private messageService: MessageService) {} constructor(private tokenService: TokenService, private messageService: MessageService) {}
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> { intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
if (request.url.includes('api.hv.nober.de')) { const token = localStorage.getItem(TokenService.Id_Token_Key)
if (request.url.includes('api.hv.nober.de') && token) {
const clone = request.clone({ const clone = request.clone({
setHeaders: { Authorization: `Bearer ${this.tokenService.getToken()}`} setHeaders: { Authorization: `Bearer ${token}`}
}) })
return next.handle(clone) return next.handle(clone)
} }

View File

View File

@ -0,0 +1,23 @@
<mat-card>
<mat-card-content>
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<h2>Log In</h2>
<mat-error *ngIf="loginInvalid">
The username and password were not recognized
</mat-error>
<mat-form-field class="full-width-input">
<input matInput placeholder="Username" formControlName="username" required>
<mat-error>
Please provide a valid email address
</mat-error>
</mat-form-field>
<mat-form-field class="full-width-input">
<input matInput type="password" placeholder="Password" formControlName="password" required>
<mat-error>
Please provide a valid password
</mat-error>
</mat-form-field>
<button mat-raised-button color="primary">Login</button>
</form>
</mat-card-content>
</mat-card>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { LoginComponent } from './login.component';
describe('LoginComponent', () => {
let component: LoginComponent;
let fixture: ComponentFixture<LoginComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ LoginComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,51 @@
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { MessageService } from '../message.service';
import { TokenService } from '../token.service';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
form: FormGroup;
public loginInvalid = false;
private formSubmitAttempt = false;
private returnUrl: string;
constructor(private fb: FormBuilder,
private route: ActivatedRoute,
private router: Router,
private tokenService: TokenService,
private messageService: MessageService) {
this.returnUrl = this.route.snapshot.queryParams.returnUrl || '/'
this.form = this.fb.group({
username: ['', Validators.required],
password: ['', Validators.required]
})
}
ngOnInit(): void {
}
async onSubmit(): Promise<void> {
this.loginInvalid = false;
this.formSubmitAttempt = false;
if (this.form.valid) {
try {
const username = this.form.get('username')?.value;
const password = this.form.get('password')?.value;
await this.tokenService.login(username, password);
} catch (err) {
this.loginInvalid = true;
}
} else {
this.formSubmitAttempt = true;
}
}
}

View File

@ -0,0 +1,17 @@
<section class="mat-typography">
<mat-card class="defaultCard">
<mat-card-header>
<mat-card-title>
Logout
</mat-card-title>
</mat-card-header>
<mat-card-content>
<div>
<h2>Good bye</h2>
</div>
</mat-card-content>
</mat-card>
</section>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { LogoutComponent } from './logout.component';
describe('LogoutComponent', () => {
let component: LogoutComponent;
let fixture: ComponentFixture<LogoutComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ LogoutComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(LogoutComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,19 @@
import { Component, OnInit } from '@angular/core';
import { MessageService } from '../message.service';
import { TokenService } from '../token.service';
@Component({
selector: 'app-logout',
templateUrl: './logout.component.html',
styleUrls: ['./logout.component.css']
})
export class LogoutComponent implements OnInit {
constructor(private messageService: MessageService) { }
ngOnInit(): void {
localStorage.removeItem(TokenService.Id_Token_Key)
this.messageService.add("Token removed from local storage")
}
}

View File

@ -6,6 +6,8 @@
<mat-toolbar>Menu</mat-toolbar> <mat-toolbar>Menu</mat-toolbar>
<mat-nav-list> <mat-nav-list>
<a mat-list-item href="/test">Mein Test</a> <a mat-list-item href="/test">Mein Test</a>
<a mat-list-item href="/login">Login</a>
<a mat-list-item href="/logout">Logout</a>
</mat-nav-list> </mat-nav-list>
</mat-sidenav> </mat-sidenav>
<mat-sidenav-content> <mat-sidenav-content>

View File

@ -12,7 +12,7 @@ import { TestOutput } from './testOutput';
export class TestOutputService { export class TestOutputService {
constructor(private messageService: MessageService, private http: HttpClient) { } constructor(private messageService: MessageService, private http: HttpClient) { }
getTestOutput(): Promise<TestOutput> { async getTestOutput(): Promise<TestOutput> {
this.messageService.add(`TestOutputService: fetch test output`); this.messageService.add(`TestOutputService: fetch test output`);
return this.http.get<TestOutput>(`${serviceBaseUrl}/v1/test`).toPromise() return this.http.get<TestOutput>(`${serviceBaseUrl}/v1/test`).toPromise()
} }

View File

@ -1,20 +1,33 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { MessageService } from './message.service'; import { MessageService } from './message.service';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { UserCreds } from './userCreds'
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class TokenService { export class TokenService {
private token: String; public static Id_Token_Key : string = "id_token";
constructor(private messageService: MessageService) { constructor(private http: HttpClient, private messageService: MessageService) {
this.messageService.add("TokenService started, token created") this.messageService.add("TokenService started, token created")
this.token = "abc"
if (! localStorage.getItem(TokenService.Id_Token_Key)) {
localStorage.setItem(TokenService.Id_Token_Key, "abc")
this.messageService.add("Token set in local storage")
}
} }
getToken(): String {
this.messageService.add("Providing token to other service") async login(login: string, password: string) {
return this.token this.messageService.add(`TokenService: trying to login and obtain token`);
const userCreds : UserCreds = {
"application": "hv2",
"login": login,
"password": password
}
const token = await this.http.post<String>("https://authservice.hottis.de/token", userCreds).toPromise()
this.messageService.add(`Token is ${JSON.stringify(token, undefined, 4)}`)
} }
} }

View File

@ -0,0 +1,5 @@
export interface UserCreds {
application: string
login: string
password: string
}