get full name information, make sure its displayed in the UI.

added a white on transparent banner image.
This commit is contained in:
Jason Kulatunga 2022-11-03 22:24:30 -07:00
parent c0e996dc74
commit bcb3f58d6e
15 changed files with 81 additions and 18 deletions

View File

@ -79,12 +79,13 @@ cd frontend
npm run dist -- -c sandbox
# In terminal #2, run the following
docker build -t fasten-couchdb -f docker/couchdb/Dockerfile .
docker run --rm -it -p 5984:5984 -v `pwd`/.couchdb/data:/opt/couchdb/data -v `pwd`/.couchdb/config:/opt/couchdb/etc/local.d fasten-couchdb
# In terminal #3, run the following
go mod vendor
go run backend/cmd/fasten/fasten.go start --config ./config.dev.yaml --debug
# In terminal #3, run the following
docker build -t fasten-couchdb -f docker/couchdb/Dockerfile .
docker run --rm -it -p 5984:5984 -v `pwd`/.couchdb/data:/opt/couchdb/data -v `pwd`/.couchdb/config:/opt/couchdb/etc/local.d fasten-couchdb
```
Now you can open a browser to `http://localhost:9090` to see the Fasten UI.

View File

@ -57,6 +57,8 @@ type couchDbUser struct {
Type string `json:"type"`
Roles []string `json:"roles"`
Password string `json:"password"`
FullName string `json:"full_name"`
}
func (cr *couchdbRepository) CreateUser(ctx context.Context, user *models.User) error {
@ -67,6 +69,8 @@ func (cr *couchdbRepository) CreateUser(ctx context.Context, user *models.User)
Type: "user",
Roles: []string{},
Password: user.Password,
FullName: user.FullName,
}
db := cr.client.DB(ctx, "_users")
_, err := db.Put(ctx, newUser.ID, newUser)
@ -97,6 +101,19 @@ func (cr *couchdbRepository) VerifyUser(ctx context.Context, user *models.User)
}
log.Printf("SESSION INFO: %v", session)
//TODO: return session info
//lookup the user in the user database using admin creds
adminDb := cr.client.DB(ctx, "_users")
userRow := adminDb.Get(ctx, kivik.UserPrefix+session.Name)
userDoc := map[string]interface{}{}
err = userRow.ScanDoc(&userDoc)
if err != nil {
return err
}
if userFullName, hasUserFullName := userDoc["full_name"]; hasUserFullName {
user.FullName = userFullName.(string)
}
return nil
}

View File

@ -1,6 +1,7 @@
package models
type User struct {
FullName string `json:"full_name"`
Username string `json:"username"`
Password string `json:"password"`
}

View File

@ -13,6 +13,7 @@ import (
func AuthSignup(c *gin.Context) {
databaseRepo := c.MustGet("REPOSITORY").(database.DatabaseRepository)
appConfig := c.MustGet("CONFIG").(config.Interface)
var user models.User
if err := c.ShouldBindJSON(&user); err != nil {
@ -25,7 +26,10 @@ func AuthSignup(c *gin.Context) {
return
}
c.JSON(http.StatusOK, gin.H{"success": true})
//TODO: we can derive the encryption key and the hash'ed user from the responseData sub. For now the Sub will be the user id prepended with hello.
userFastenToken, err := jwtGenerateFastenTokenFromUser(user, appConfig.GetString("jwt.issuer.key"))
c.JSON(http.StatusOK, gin.H{"success": true, "data": userFastenToken})
}
func AuthSignin(c *gin.Context) {
@ -49,14 +53,22 @@ func AuthSignin(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"success": true, "data": userFastenToken})
}
type UserRegisteredClaims struct {
FullName string `json:"full_name"`
jwt.RegisteredClaims
}
func jwtGenerateFastenTokenFromUser(user models.User, issuerSigningKey string) (string, error) {
log.Printf("ISSUER KEY: " + issuerSigningKey)
userClaims := jwt.RegisteredClaims{
// In JWT, the expiry time is expressed as unix milliseconds
ExpiresAt: jwt.NewNumericDate(time.Now().Add(1 * time.Hour)),
IssuedAt: jwt.NewNumericDate(time.Now()),
Issuer: "docker-fastenhealth",
Subject: user.Username,
userClaims := UserRegisteredClaims{
FullName: user.FullName,
RegisteredClaims: jwt.RegisteredClaims{
// In JWT, the expiry time is expressed as unix milliseconds
ExpiresAt: jwt.NewNumericDate(time.Now().Add(1 * time.Hour)),
IssuedAt: jwt.NewNumericDate(time.Now()),
Issuer: "docker-fastenhealth",
Subject: user.Username,
},
}
//FASTEN_JWT_ISSUER_KEY

View File

@ -61,7 +61,7 @@
<div class="az-img-user">
<img src="assets/logo/logo-text.png" alt="">
</div><!-- az-img-user -->
<h6>{{current_user}}</h6>
<h6>{{current_user_claims.full_name || current_user_claims.email || current_user_claims.sub}}</h6>
<span>Adminstrator</span>
</div><!-- az-header-profile -->

View File

@ -2,20 +2,21 @@ import { Component, OnInit } from '@angular/core';
import {FastenDbService} from '../../services/fasten-db.service';
import { Router } from '@angular/router';
import {AuthService} from '../../services/auth.service';
import {UserRegisteredClaims} from '../../models/fasten/user-registered-claims';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss']
})
export class HeaderComponent implements OnInit {
current_user: string
current_user_claims: UserRegisteredClaims
constructor(private authService: AuthService, private router: Router) { }
ngOnInit() {
try {
this.current_user = this.authService.GetCurrentUser()
this.current_user_claims = this.authService.GetCurrentUser()
} catch(e){
this.current_user = "unknown"
this.current_user_claims = new UserRegisteredClaims()
}
}

View File

@ -0,0 +1,13 @@
export class UserRegisteredClaims {
iss: string //Issuer
sub: string //Subject
aud?: string //Audience
exp: number //ExpiresAt (unix timestamp)
nbf?: number //NotBefore (unix timestamp)
iat?: number //IssuedAt (unix timestamp)
id?: string //ID
full_name: string //FullName
picture: string //Picture
email: string //Email
}

View File

@ -40,6 +40,7 @@ export class AuthSigninComponent implements OnInit {
this.authService.IdpCallback(idpType, state, code)
.then(() => this.router.navigateByUrl('/dashboard'))
.catch((err)=>{
console.error("idpCallback error:", err)
const toastNotification = new ToastNotification()
toastNotification.type = ToastType.Error
toastNotification.message = "an error occurred while signing in"

View File

@ -20,6 +20,20 @@
<form (ngSubmit)="signupSubmit()" #userForm="ngForm">
<div class="form-group">
<label>Firstname &amp; Lastname</label>
<input [(ngModel)]="newUser.full_name" name="full_name" #full_name="ngModel" required minlength="2" type="text" class="form-control" placeholder="Enter your firstname and lastname">
<div *ngIf="full_name.invalid && (full_name.dirty || full_name.touched)" class="alert alert-danger">
<div *ngIf="full_name.errors?.['required']">
Name is required.
</div>
<div *ngIf="full_name.errors?.['minlength']">
Name must be at least 4 characters long.
</div>
</div>
</div><!-- form-group -->
<div class="form-group">
<label>Username</label>
<input [(ngModel)]="newUser.username" name="username" #username="ngModel" required minlength="5" type="text" class="form-control" placeholder="Enter your username">

View File

@ -9,6 +9,7 @@ import * as Oauth from '@panva/oauth4webapi';
import {SourceState} from '../models/fasten/source-state';
import {Session} from '../models/database/session';
import * as jose from 'jose';
import {UserRegisteredClaims} from '../models/fasten/user-registered-claims';
@Injectable({
providedIn: 'root'
@ -161,7 +162,7 @@ export class AuthService {
return localStorage.getItem(this.FASTEN_JWT_LOCALSTORAGE_KEY);
}
public GetCurrentUser(): string {
public GetCurrentUser(): UserRegisteredClaims {
let authToken = this.GetAuthToken()
if(!authToken){
throw new Error("no auth token found")
@ -169,7 +170,8 @@ export class AuthService {
//parse the authToken to get user information
let jwtClaims = jose.decodeJwt(authToken)
return jwtClaims.sub
// @ts-ignore
return jwtClaims as UserRegisteredClaims
}
public async Logout(): Promise<any> {

View File

@ -63,7 +63,7 @@ export class FastenDbService extends PouchdbRepository {
}
//parse the authToken to get user information
this.current_user = this.authService.GetCurrentUser()
this.current_user = this.authService.GetCurrentUser().sub
// add JWT bearer token header to all requests
// https://stackoverflow.com/questions/62129654/how-to-handle-jwt-authentication-with-rxdb

View File

@ -20,7 +20,7 @@ export class QueueService {
if (typeof Worker !== 'undefined') {
const sourceSync = new SourceSyncMessage()
sourceSync.source = source
sourceSync.current_user = this.authService.GetCurrentUser()
sourceSync.current_user = this.authService.GetCurrentUser().sub
sourceSync.auth_token = this.authService.GetAuthToken()
sourceSync.couchdb_endpoint_base = environment.couchdb_endpoint_base
sourceSync.fasten_api_endpoint_base = environment.fasten_api_endpoint_base

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

View File

@ -1,4 +1,5 @@
export class User {
full_name?: string
username?: string
password?: string
}