change login to form + remember me, 2fa

This commit is contained in:
_Bastler 2021-05-19 19:26:51 +02:00
parent e3de9fad0d
commit 5304409ea4
6 changed files with 97 additions and 88 deletions

View File

@ -3,8 +3,6 @@ import {Routes, RouterModule} from '@angular/router';
import {AuthGuard, AuthUpdateGuard, AuthenticatedGuard, AnonymousGuard} from './auth/auth.guard'; import {AuthGuard, AuthUpdateGuard, AuthenticatedGuard, AnonymousGuard} from './auth/auth.guard';
import {ImprintComponent, PrivacyPolicyComponent, TermsOfServiceComponent} from './pages/general/general.component'; import {ImprintComponent, PrivacyPolicyComponent, TermsOfServiceComponent} from './pages/general/general.component';
import {LoginComponent} from './pages/login/login.component';
import {LoginTotpComponent} from './pages/login-totp/login-totp.component';
import {FormLoginComponent} from './pages/form-login/form-login.component'; import {FormLoginComponent} from './pages/form-login/form-login.component';
import {FormLoginTotpComponent} from './pages/form-login-totp/form-login-totp.component'; import {FormLoginTotpComponent} from './pages/form-login-totp/form-login-totp.component';
import {PasswordComponent} from './pages/password/password.component'; import {PasswordComponent} from './pages/password/password.component';
@ -30,8 +28,8 @@ const routes: Routes = [
{path: 'imprint', component: ImprintComponent, canActivate: [AuthUpdateGuard]}, {path: 'imprint', component: ImprintComponent, canActivate: [AuthUpdateGuard]},
{path: 'privacy-policy', component: PrivacyPolicyComponent, canActivate: [AuthUpdateGuard]}, {path: 'privacy-policy', component: PrivacyPolicyComponent, canActivate: [AuthUpdateGuard]},
{path: 'terms-of-service', component: TermsOfServiceComponent, canActivate: [AuthUpdateGuard]}, {path: 'terms-of-service', component: TermsOfServiceComponent, canActivate: [AuthUpdateGuard]},
{path: 'login', component: LoginComponent, canActivate: [AnonymousGuard]}, {path: 'login', component: FormLoginComponent, canActivate: [AnonymousGuard]},
{path: 'login/totp', component: LoginTotpComponent, canActivate: [AnonymousGuard]}, {path: 'login/totp', component: FormLoginTotpComponent, canActivate: [AnonymousGuard]},
{path: 'service-login', component: FormLoginComponent, canActivate: [AnonymousGuard]}, {path: 'service-login', component: FormLoginComponent, canActivate: [AnonymousGuard]},
{path: 'service-login/totp', component: FormLoginTotpComponent, canActivate: [AnonymousGuard]}, {path: 'service-login/totp', component: FormLoginTotpComponent, canActivate: [AnonymousGuard]},
{path: 'password', component: PasswordComponent, canActivate: [AnonymousGuard]}, {path: 'password', component: PasswordComponent, canActivate: [AnonymousGuard]},

View File

@ -1,28 +1,24 @@
<form [formGroup]="form"> <form action="{{apiUrl}}/auth/formlogin/totp" method="POST" #totpForm>
<form ngNoForm action="{{apiUrl}}/auth/formlogin/totp" method="POST"> <mat-card>
<mat-card> <mat-card-content>
<mat-card-content> <h2>{{'security.2fa.totp.external' | i18n}}<mat-icon style="font-size: 1em;">open_in_new
<h2>{{'security.2fa.totp.external' | i18n}}<mat-icon style="font-size: 1em;">open_in_new </mat-icon>
</mat-icon></h2> </h2>
<mat-error *ngIf="loginInvalid"> <mat-error *ngIf="loginInvalid">
{{'security.2fa.totp.invalid' | i18n}} {{'security.2fa.totp.invalid' | i18n}}
</mat-error>
<mat-form-field>
<input id="code" name="code" matInput placeholder="{{'security.2fa.totp.code' | i18n}}" required>
<mat-error>
{{'security.2fa.totp.missing' | i18n}}
</mat-error> </mat-error>
<mat-form-field> </mat-form-field>
<input id="code" name="code" matInput placeholder="{{'security.2fa.totp.code' | i18n}}" </mat-card-content>
formControlName="code" required> <mat-card-actions>
<mat-error> <button type="submit" mat-raised-button color="primary" (click)="totpForm.submit()"
{{'security.2fa.totp.missing' | i18n}} [disabled]="totpForm.invalid">{{'security.2fa.totp.login' | i18n}}<mat-icon style="font-size: 1em;">
</mat-error> open_in_new
</mat-form-field> </mat-icon></button>
<mat-slide-toggle id="keep" name="keep" formControlName="keep"> </mat-card-actions>
{{'security.2fa.totp.keepSession' | i18n}} </mat-card>
</mat-slide-toggle>
</mat-card-content>
<mat-card-actions>
<button type="submit" mat-raised-button color="primary"
[disabled]="form.invalid">{{'security.2fa.totp.login' | i18n}}<mat-icon style="font-size: 1em;">open_in_new
</mat-icon></button>
</mat-card-actions>
</mat-card>
</form>
</form> </form>

View File

@ -1,7 +1,8 @@
import { Component, OnInit } from '@angular/core'; import {Component, OnInit} from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import {FormBuilder, FormGroup, Validators} from '@angular/forms';
import {ActivatedRoute} from '@angular/router';
import { environment } from '../../../environments/environment'; import {environment} from '../../../environments/environment';
@Component({ @Component({
selector: 'app-form-login-totp', selector: 'app-form-login-totp',
@ -10,16 +11,17 @@ import { environment } from '../../../environments/environment';
}) })
export class FormLoginTotpComponent implements OnInit { export class FormLoginTotpComponent implements OnInit {
form: FormGroup; loginInvalid: boolean;
public loginInvalid: boolean; apiUrl = environment.apiUrl;
public apiUrl = environment.apiUrl;
constructor(private formBuilder: FormBuilder) { } constructor(
private route: ActivatedRoute) {}
async ngOnInit() { async ngOnInit() {
this.form = this.formBuilder.group({ this.route.queryParams.subscribe(params => {
code: ['', Validators.required], if(params['error'] || params['error'] == '') {
keep : [''] this.loginInvalid = true;
}
}); });
} }

View File

@ -1,37 +1,34 @@
<form [formGroup]="form"> <form action="{{apiUrl}}/auth/login" method="POST" #loginForm>
<form ngNoForm action="{{apiUrl}}/auth/formlogin" method="POST"> <mat-card>
<mat-card> <mat-card-content>
<mat-card-content> <h2>{{'login.external' | i18n}}<mat-icon style="font-size: 1em;">open_in_new
<h2>{{'login.external' | i18n}}<mat-icon style="font-size: 1em;">open_in_new </mat-icon>
</mat-icon> </h2>
</h2> <mat-error *ngIf="loginInvalid">
<mat-error *ngIf="loginInvalid"> {{'login.invalid' | i18n}}
{{'login.invalid' | i18n}} </mat-error>
<mat-form-field>
<input id="username" name="username" matInput placeholder="{{'username' | i18n}}" required>
<mat-error>
{{'username.missing' | i18n}}
</mat-error> </mat-error>
<mat-form-field> </mat-form-field>
<input id="username" name="username" matInput placeholder="{{'username' | i18n}}" <mat-form-field>
formControlName="username" required> <input id="password" name="password" matInput type="password" placeholder="{{'password' | i18n}}"
<mat-error> required>
{{'username.missing' | i18n}} <mat-error>
</mat-error> {{'password.invalid.hint' | i18n}}
</mat-form-field> </mat-error>
<mat-form-field> </mat-form-field>
<input id="password" name="password" matInput type="password" placeholder="{{'password' | i18n}}" <mat-slide-toggle id="keep" name="keep">
formControlName="password" required> {{'login.keepSession' | i18n}}
<mat-error> </mat-slide-toggle>
{{'password.invalid.hint' | i18n}} </mat-card-content>
</mat-error> <mat-card-actions>
</mat-form-field> <button type="submit" (click)="loginForm.submit()" mat-raised-button color="primary" [disabled]="loginForm.invalid">{{'login.external' |
<mat-slide-toggle id="keep" name="keep" formControlName="keep"> i18n}}<mat-icon style="font-size: 1em;">open_in_new
{{'login.keepSession' | i18n}} </mat-icon></button>
</mat-slide-toggle> <a routerLink="/password" mat-raised-button color="warn">{{'password.forgot' | i18n}}</a>
</mat-card-content> </mat-card-actions>
<mat-card-actions> </mat-card>
<button type="submit" mat-raised-button color="primary"
[disabled]="form.invalid">{{'login.external' | i18n}}<mat-icon style="font-size: 1em;">open_in_new
</mat-icon></button>
<a routerLink="/password" mat-raised-button color="warn">{{'password.forgot' | i18n}}</a>
</mat-card-actions>
</mat-card>
</form>
</form> </form>

View File

@ -1,7 +1,7 @@
import { Component, OnInit } from '@angular/core'; import {Component, ElementRef, OnInit, ViewChild} from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import {ActivatedRoute, Router} from '@angular/router';
import { environment } from '../../../environments/environment'; import {environment} from '../../../environments/environment';
@Component({ @Component({
selector: 'app-form-login', selector: 'app-form-login',
@ -10,20 +10,33 @@ import { environment } from '../../../environments/environment';
}) })
export class FormLoginComponent implements OnInit { export class FormLoginComponent implements OnInit {
form: FormGroup; @ViewChild('loginForm') loginForm: ElementRef;
public loginInvalid: boolean; loginInvalid: boolean;
public apiUrl = environment.apiUrl; apiUrl = environment.apiUrl;
targetRoute : string;
constructor(private formBuilder: FormBuilder) { } constructor(
private router: Router,
private route: ActivatedRoute) {}
async ngOnInit() { async ngOnInit() {
this.form = this.formBuilder.group({ this.route.queryParams.subscribe(params => {
username: ['', Validators.required], if(params['target']) {
password: ['', Validators.required], this.targetRoute = params['target'];
keep : [''] this.router.navigate([], {queryParams: {target: null}, queryParamsHandling: 'merge'});
}
if(params['error'] || params['error'] == '') {
this.loginInvalid = true;
}
}); });
}
ngAfterViewInit(): void {
if(this.targetRoute) {
this.loginForm.nativeElement.action = this.loginForm.nativeElement.action + "?forward=" + window.location.origin + this.targetRoute;
}
} }
} }

View File

@ -16,11 +16,14 @@
<ng-container matColumnDef="name"> <ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef mat-sort-header="name"> {{'service.name' | i18n}} </th> <th mat-header-cell *matHeaderCellDef mat-sort-header="name"> {{'service.name' | i18n}} </th>
<td mat-cell *matCellDef="let service" class="text-center"> <td mat-cell *matCellDef="let service" class="text-center">
<a href="{{service.url}}" [target]="service.sameSite ? '_self' : '_blank'" mat-button color="accent"> <a *ngIf="service.url" href="{{service.url}}" [target]="service.sameSite ? '_self' : '_blank'" mat-button color="accent">
<strong>{{'services.' + service.name + '.title' | i18n}}</strong> <strong>{{'services.' + service.name + '.title' | i18n}}</strong>
<mat-icon *ngIf="!service.sameSite" inline="true"> <mat-icon *ngIf="!service.sameSite" inline="true">
open_in_new</mat-icon> open_in_new</mat-icon>
</a> </a>
<a *ngIf="!service.url" mat-button disabled>
<strong>{{'services.' + service.name + '.title' | i18n}}</strong>
</a>
<div><small>{{'services.' + service.name + '.subtitle' | i18n}}</small></div> <div><small>{{'services.' + service.name + '.subtitle' | i18n}}</small></div>
</td> </td>
</ng-container> </ng-container>