working authentication check (via token presence in localstorage).

HTTP interceptor to always add token to header.
This commit is contained in:
Jason Kulatunga 2022-09-12 00:58:19 -04:00
parent 1a3dce77cb
commit 6aa92674bc
8 changed files with 114 additions and 11 deletions

View File

@ -0,0 +1,25 @@
package middleware
import (
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg/auth"
"github.com/gin-gonic/gin"
"net/http"
)
func RequireAuth() gin.HandlerFunc {
return func(context *gin.Context) {
tokenString := context.GetHeader("Authorization")
if tokenString == "" {
context.JSON(http.StatusUnauthorized, gin.H{"success": false, "error": "request does not contain an access token"})
context.Abort()
return
}
err := auth.ValidateToken(tokenString)
if err != nil {
context.JSON(http.StatusUnauthorized, gin.H{"success": false, "error": err.Error()})
context.Abort()
return
}
context.Next()
}
}

View File

@ -43,11 +43,14 @@ func (ae *AppEngine) Setup(logger *logrus.Entry) *gin.Engine {
api.POST("/auth/signup", handler.AuthSignup) api.POST("/auth/signup", handler.AuthSignup)
api.POST("/auth/signin", handler.AuthSignin) api.POST("/auth/signin", handler.AuthSignin)
api.POST("/source", handler.CreateSource) secure := api.Group("/secure").Use(middleware.RequireAuth())
api.GET("/source", handler.ListSource) {
api.GET("/source/raw/:sourceType/*path", handler.RawRequestSource) secure.POST("/source", handler.CreateSource)
secure.GET("/source", handler.ListSource)
secure.GET("/source/raw/:sourceType/*path", handler.RawRequestSource)
api.GET("/fhir/:sourceResourceType/*sourceResourceId", handler.RequestResourceFhir) secure.GET("/fhir/:sourceResourceType/*sourceResourceId", handler.RequestResourceFhir)
}
} }
} }

View File

@ -7,6 +7,7 @@ import { MedicalSourcesComponent } from './pages/medical-sources/medical-sources
import {ResourceDetailComponent} from './pages/resource-detail/resource-detail.component'; import {ResourceDetailComponent} from './pages/resource-detail/resource-detail.component';
import {AuthSigninComponent} from './pages/auth-signin/auth-signin.component'; import {AuthSigninComponent} from './pages/auth-signin/auth-signin.component';
import {AuthSignupComponent} from './pages/auth-signup/auth-signup.component'; import {AuthSignupComponent} from './pages/auth-signup/auth-signup.component';
import {CanActivateAuthGuard} from './services/can-activate.auth-guard';
const routes: Routes = [ const routes: Routes = [
@ -14,9 +15,9 @@ const routes: Routes = [
{ path: 'auth/signup', component: AuthSignupComponent }, { path: 'auth/signup', component: AuthSignupComponent },
{ path: '', redirectTo: '/dashboard', pathMatch: 'full' }, { path: '', redirectTo: '/dashboard', pathMatch: 'full' },
{ path: 'dashboard', component: DashboardComponent }, { path: 'dashboard', component: DashboardComponent, canActivate: [ CanActivateAuthGuard] },
{ path: 'detail', component: ResourceDetailComponent }, { path: 'detail', component: ResourceDetailComponent, canActivate: [ CanActivateAuthGuard] },
{ path: 'sources', component: MedicalSourcesComponent }, { path: 'sources', component: MedicalSourcesComponent, canActivate: [ CanActivateAuthGuard] },
// { path: 'general-pages', loadChildren: () => import('./general-pages/general-pages.module').then(m => m.GeneralPagesModule) }, // { path: 'general-pages', loadChildren: () => import('./general-pages/general-pages.module').then(m => m.GeneralPagesModule) },
// { path: 'ui-elements', loadChildren: () => import('./ui-elements/ui-elements.module').then(m => m.UiElementsModule) }, // { path: 'ui-elements', loadChildren: () => import('./ui-elements/ui-elements.module').then(m => m.UiElementsModule) },
// { path: 'form', loadChildren: () => import('./form/form.module').then(m => m.FormModule) }, // { path: 'form', loadChildren: () => import('./form/form.module').then(m => m.FormModule) },

View File

@ -3,7 +3,7 @@ import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module'; import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { HttpClientModule } from '@angular/common/http'; import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { NgbModule } from "@ng-bootstrap/ng-bootstrap"; import { NgbModule } from "@ng-bootstrap/ng-bootstrap";
import { HeaderComponent } from './components/header/header.component'; import { HeaderComponent } from './components/header/header.component';
import { FooterComponent } from './components/footer/footer.component'; import { FooterComponent } from './components/footer/footer.component';
@ -18,6 +18,10 @@ import { ResourceDetailComponent } from './pages/resource-detail/resource-detail
import { AuthSignupComponent } from './pages/auth-signup/auth-signup.component'; import { AuthSignupComponent } from './pages/auth-signup/auth-signup.component';
import { AuthSigninComponent } from './pages/auth-signin/auth-signin.component'; import { AuthSigninComponent } from './pages/auth-signin/auth-signin.component';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { AuthInterceptorService } from './services/auth-interceptor.service';
import { CanActivateAuthGuard } from './services/can-activate.auth-guard';
import {FastenApiService} from './services/fasten-api.service';
@NgModule({ @NgModule({
declarations: [ declarations: [
AppComponent, AppComponent,
@ -39,7 +43,15 @@ import { FormsModule } from '@angular/forms';
NgbModule, NgbModule,
ChartsModule ChartsModule
], ],
providers: [], providers: [
FastenApiService,
{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptorService,
multi: true
},
CanActivateAuthGuard
],
bootstrap: [AppComponent] bootstrap: [AppComponent]
}) })
export class AppModule { export class AppModule {

View File

@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { AuthInterceptorService } from './auth-interceptor.service';
describe('AuthInterceptorService', () => {
let service: AuthInterceptorService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(AuthInterceptorService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@ -0,0 +1,23 @@
import { Injectable, Injector } from '@angular/core';
import { HttpInterceptor } from '@angular/common/http';
import { FastenApiService } from './fasten-api.service';
@Injectable({
providedIn: 'root'
})
export class AuthInterceptorService {
constructor(private injector: Injector) { }
intercept(req, next) {
const fastenApiService = this.injector.get(FastenApiService);
const fastenApiRequest = req.clone({
// tslint:disable-next-line:max-line-length
headers: req.headers.set('Authorization', 'Bearer ' + fastenApiService.token)
});
return next.handle(fastenApiRequest);
//TODO: check if the response is 401, if so we should always redirect to /login
}
}

View File

@ -0,0 +1,19 @@
import { Injectable } from '@angular/core';
import {CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router} from '@angular/router';
import { FastenApiService } from './fasten-api.service';
@Injectable()
export class CanActivateAuthGuard implements CanActivate {
constructor(private fastenApiService: FastenApiService, private router: Router) {
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
//check if the user is authenticated, if not, redirect to login
if (!this.fastenApiService.isAuthenticated()) {
this.router.navigate(['/auth/signin']);
}
// continue as normal
return true
}
}

View File

@ -66,8 +66,12 @@ export class FastenApiService {
} }
/*
SECURE ENDPOINTS
*/
createSource(source: Source): Observable<Source> { createSource(source: Source): Observable<Source> {
return this._httpClient.post<any>(`${this.getBasePath()}/api/source`, source) return this._httpClient.post<any>(`${this.getBasePath()}/api/secure/source`, source)
.pipe( .pipe(
map((response: ResponseWrapper) => { map((response: ResponseWrapper) => {
console.log("SOURCE RESPONSE", response) console.log("SOURCE RESPONSE", response)
@ -77,7 +81,7 @@ export class FastenApiService {
} }
getResources(resourceType: string, resourceId?: string ) { getResources(resourceType: string, resourceId?: string ) {
return this._httpClient.get<any>(`${this.getBasePath()}/api/fhir/${resourceType}/${resourceId ? resourceId : ''}`) return this._httpClient.get<any>(`${this.getBasePath()}/api/secure/fhir/${resourceType}/${resourceId ? resourceId : ''}`)
.pipe( .pipe(
map((response: ResponseWrapper) => { map((response: ResponseWrapper) => {
console.log("RESPONSE", response) console.log("RESPONSE", response)