Browse Source

SPA: override with compose settings (environment variables) configuration in spa angular settings service.

pull/49/merge
PLAINCONCEPTS\ccanizares 8 years ago
parent
commit
2e84154e37
22 changed files with 301 additions and 91 deletions
  1. +4
    -4
      docker-compose.override.yml
  2. +35
    -0
      src/Services/Ordering/Ordering.API/Infrastructure/Auth/AuthorizationHeaderParameterOperationFilter.cs
  3. +2
    -1
      src/Services/Ordering/Ordering.API/Startup.cs
  4. +6
    -6
      src/Web/WebMVC/Startup.cs
  5. +15
    -0
      src/Web/WebSPA/eShopOnContainers.WebSPA/AppSettings.cs
  6. +6
    -1
      src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/app.component.ts
  7. +19
    -7
      src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/basket/basket-status/basket-status.component.ts
  8. +29
    -8
      src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/basket/basket.service.ts
  9. +12
    -1
      src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.component.ts
  10. +12
    -6
      src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.service.ts
  11. +9
    -2
      src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/orders/orders.component.ts
  12. +11
    -5
      src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/orders/orders.service.ts
  13. +6
    -0
      src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/configuration.model.ts
  14. +38
    -0
      src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/services/configuration.service.ts
  15. +47
    -36
      src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/services/security.service.ts
  16. +24
    -0
      src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/services/storage.service.ts
  17. +5
    -1
      src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/shared.module.ts
  18. +0
    -6
      src/Web/WebSPA/eShopOnContainers.WebSPA/Program.cs
  19. +9
    -1
      src/Web/WebSPA/eShopOnContainers.WebSPA/Server/Controllers/HomeController.cs
  20. +4
    -1
      src/Web/WebSPA/eShopOnContainers.WebSPA/Startup.cs
  21. +4
    -0
      src/Web/WebSPA/eShopOnContainers.WebSPA/appsettings.json
  22. +4
    -5
      src/Web/WebSPA/eShopOnContainers.WebSPA/project.json

+ 4
- 4
docker-compose.override.yml View File

@ -21,11 +21,11 @@ services:
webspa: webspa:
environment: environment:
- CatalogUrl=http://catalog.api:5101
- OrderingUrl=http://ordering.api:5102
- CatalogUrl=http://10.0.75.1:5101
- OrderingUrl=http://10.0.75.1:5102
#- IdentityUrl=http://13.88.8.119:5105 #Remote: VM Needs to have public access at 5105. #- IdentityUrl=http://13.88.8.119:5105 #Remote: VM Needs to have public access at 5105.
- IdentityUrl=http://10.0.75.1:5105 #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105. - IdentityUrl=http://10.0.75.1:5105 #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105.
- BasketUrl=http://basket.api:5103
- BasketUrl=http://10.0.75.1:5103
ports: ports:
- "5104:5104" - "5104:5104"
@ -40,7 +40,7 @@ services:
catalog.api: catalog.api:
environment: environment:
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word - ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word
- ExternalCatalogBaseUrl=http://10.0.75.1:5101 #Local
- ExternalCatalogBaseUrl=http://10.0.75.1:5101 #Local
#- ExternalCatalogBaseUrl=http://13.88.8.119:5101 #Remote #- ExternalCatalogBaseUrl=http://13.88.8.119:5101 #Remote
ports: ports:
- "5101:5101" - "5101:5101"


+ 35
- 0
src/Services/Ordering/Ordering.API/Infrastructure/Auth/AuthorizationHeaderParameterOperationFilter.cs View File

@ -0,0 +1,35 @@
using Microsoft.AspNetCore.Mvc.Authorization;
using Swashbuckle.Swagger.Model;
using Swashbuckle.SwaggerGen.Generator;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Auth
{
public class AuthorizationHeaderParameterOperationFilter : IOperationFilter
{
public void Apply(Operation operation, OperationFilterContext context)
{
var filterPipeline = context.ApiDescription.ActionDescriptor.FilterDescriptors;
var isAuthorized = filterPipeline.Select(filterInfo => filterInfo.Filter).Any(filter => filter is AuthorizeFilter);
var allowAnonymous = filterPipeline.Select(filterInfo => filterInfo.Filter).Any(filter => filter is IAllowAnonymousFilter);
if (isAuthorized && !allowAnonymous)
{
if (operation.Parameters == null)
operation.Parameters = new List<IParameter>();
operation.Parameters.Add(new NonBodyParameter
{
Name = "Authorization",
In = "header",
Description = "access token",
Required = true,
Type = "string"
});
}
}
}
}

+ 2
- 1
src/Services/Ordering/Ordering.API/Startup.cs View File

@ -4,6 +4,7 @@
using Autofac; using Autofac;
using Autofac.Extensions.DependencyInjection; using Autofac.Extensions.DependencyInjection;
using Infrastructure; using Infrastructure;
using Infrastructure.Auth;
using Infrastructure.AutofacModules; using Infrastructure.AutofacModules;
using Infrastructure.Filters; using Infrastructure.Filters;
using Infrastructure.Services; using Infrastructure.Services;
@ -41,7 +42,6 @@
public IServiceProvider ConfigureServices(IServiceCollection services) public IServiceProvider ConfigureServices(IServiceCollection services)
{ {
// Add framework services. // Add framework services.
services.AddMvc(options => services.AddMvc(options =>
{ {
options.Filters.Add(typeof(HttpGlobalExceptionFilter)); options.Filters.Add(typeof(HttpGlobalExceptionFilter));
@ -57,6 +57,7 @@
services.AddSwaggerGen(); services.AddSwaggerGen();
services.ConfigureSwaggerGen(options => services.ConfigureSwaggerGen(options =>
{ {
options.OperationFilter<AuthorizationHeaderParameterOperationFilter>();
options.DescribeAllEnumsAsStrings(); options.DescribeAllEnumsAsStrings();
options.SingleApiVersion(new Swashbuckle.Swagger.Model.Info() options.SingleApiVersion(new Swashbuckle.Swagger.Model.Info()
{ {


+ 6
- 6
src/Web/WebMVC/Startup.cs View File

@ -25,13 +25,13 @@ namespace Microsoft.eShopOnContainers.WebMVC
.SetBasePath(env.ContentRootPath) .SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) // Settings for the application .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) // Settings for the application
.AddEnvironmentVariables(); // override settings with environment variables set in compose. .AddEnvironmentVariables(); // override settings with environment variables set in compose.
//if (env.IsDevelopment())
//{
// // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
// builder.AddUserSecrets();
//}
if (env.IsDevelopment())
{
// For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
builder.AddUserSecrets();
}
Configuration = builder.Build(); Configuration = builder.Build();
} }


+ 15
- 0
src/Web/WebSPA/eShopOnContainers.WebSPA/AppSettings.cs View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace eShopOnContainers.WebSPA
{
public class AppSettings
{
public string CatalogUrl { get; set; }
public string OrderingUrl { get; set; }
public string IdentityUrl { get; set; }
public string BasketUrl { get; set; }
}
}

+ 6
- 1
src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/app.component.ts View File

@ -5,6 +5,7 @@ import { Subscription } from 'rxjs/Subscription';
import { DataService } from './shared/services/data.service'; import { DataService } from './shared/services/data.service';
import { SecurityService } from './shared/services/security.service'; import { SecurityService } from './shared/services/security.service';
import { ConfigurationService } from './shared/services/configuration.service';
/* /*
* App Component * App Component
@ -20,13 +21,17 @@ export class AppComponent implements OnInit {
private Authenticated: boolean = false; private Authenticated: boolean = false;
subscription: Subscription; subscription: Subscription;
constructor(private titleService: Title, private securityService: SecurityService) {
constructor(private titleService: Title, private securityService: SecurityService, private configurationService: ConfigurationService) {
this.Authenticated = this.securityService.IsAuthorized; this.Authenticated = this.securityService.IsAuthorized;
} }
ngOnInit() { ngOnInit() {
console.log('app on init'); console.log('app on init');
this.subscription = this.securityService.authenticationChallenge$.subscribe(res => this.Authenticated = res); this.subscription = this.securityService.authenticationChallenge$.subscribe(res => this.Authenticated = res);
//Get configuration from server environment variables:
console.log('configuration');
this.configurationService.load();
} }
public setTitle(newTitle: string) { public setTitle(newTitle: string) {


+ 19
- 7
src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/basket/basket-status/basket-status.component.ts View File

@ -4,6 +4,7 @@ import { Subscription } from 'rxjs/Subscription';
import { BasketService } from '../basket.service'; import { BasketService } from '../basket.service';
import { BasketWrapperService } from '../../shared/services/basket.wrapper.service'; import { BasketWrapperService } from '../../shared/services/basket.wrapper.service';
import { SecurityService } from '../../shared/services/security.service'; import { SecurityService } from '../../shared/services/security.service';
import { ConfigurationService } from '../../shared/services/configuration.service';
@Component({ @Component({
selector: 'esh-basket-status', selector: 'esh-basket-status',
@ -17,7 +18,7 @@ export class BasketStatusComponent implements OnInit {
badge: number = 0; badge: number = 0;
constructor(private service: BasketService, private basketEvents: BasketWrapperService, private authService: SecurityService) { }
constructor(private service: BasketService, private basketEvents: BasketWrapperService, private authService: SecurityService, private configurationService: ConfigurationService) { }
ngOnInit() { ngOnInit() {
// Subscribe to Add Basket Observable: // Subscribe to Add Basket Observable:
@ -25,7 +26,8 @@ export class BasketStatusComponent implements OnInit {
item => { item => {
this.service.setBasket(item).subscribe(res => { this.service.setBasket(item).subscribe(res => {
this.service.getBasket().subscribe(basket => { this.service.getBasket().subscribe(basket => {
this.badge = basket.items.length;
if (basket)
this.badge = basket.items.length;
}); });
}); });
}); });
@ -33,20 +35,30 @@ export class BasketStatusComponent implements OnInit {
// Subscribe to Drop Basket Observable: // Subscribe to Drop Basket Observable:
this.basketDroppedSubscription = this.service.basketDroped$.subscribe(res => { this.basketDroppedSubscription = this.service.basketDroped$.subscribe(res => {
this.badge = 0; this.badge = 0;
console.log('dropped event fired');
}); });
// Subscribe to login and logout observable // Subscribe to login and logout observable
this.authSubscription = this.authService.authenticationChallenge$.subscribe(res => { this.authSubscription = this.authService.authenticationChallenge$.subscribe(res => {
this.service.getBasket().subscribe(basket => { this.service.getBasket().subscribe(basket => {
this.badge = basket.items.length;
if (basket != null)
this.badge = basket.items.length;
}); });
}); });
// Init: // Init:
this.service.getBasket().subscribe(basket => {
this.badge = basket.items.length;
});
if (this.configurationService.isReady) {
this.service.getBasket().subscribe(basket => {
if (basket != null)
this.badge = basket.items.length;
});
} else {
this.configurationService.settingsLoaded$.subscribe(x => {
this.service.getBasket().subscribe(basket => {
if (basket != null)
this.badge = basket.items.length;
});
});
}
} }
} }

+ 29
- 8
src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/basket/basket.service.ts View File

@ -7,6 +7,8 @@ import { SecurityService } from '../shared/services/security.service';
import { IBasket } from '../shared/models/basket.model'; import { IBasket } from '../shared/models/basket.model';
import { IBasketItem } from '../shared/models/basketItem.model'; import { IBasketItem } from '../shared/models/basketItem.model';
import { BasketWrapperService } from '../shared/services/basket.wrapper.service'; import { BasketWrapperService } from '../shared/services/basket.wrapper.service';
import { ConfigurationService } from '../shared/services/configuration.service';
import { StorageService } from '../shared/services/storage.service';
import 'rxjs/Rx'; import 'rxjs/Rx';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
@ -14,11 +16,11 @@ import 'rxjs/add/observable/throw';
import { Observer } from 'rxjs/Observer'; import { Observer } from 'rxjs/Observer';
import 'rxjs/add/operator/map'; import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch'; import 'rxjs/add/operator/catch';
import { Subject } from 'rxjs/Subject';
import { Subject } from 'rxjs/Subject';
@Injectable() @Injectable()
export class BasketService { export class BasketService {
private basketUrl: string = 'http://eshopcontainers:5103';
private basketUrl: string = '';
basket: IBasket = { basket: IBasket = {
buyerId: '', buyerId: '',
items: [] items: []
@ -28,16 +30,23 @@ export class BasketService {
private basketDropedSource = new Subject(); private basketDropedSource = new Subject();
basketDroped$ = this.basketDropedSource.asObservable(); basketDroped$ = this.basketDropedSource.asObservable();
constructor(private service: DataService, private authService: SecurityService, private basketEvents: BasketWrapperService, private router: Router) {
constructor(private service: DataService, private authService: SecurityService, private basketEvents: BasketWrapperService, private router: Router, private configurationService: ConfigurationService, private storageService: StorageService) {
this.basket.items = []; this.basket.items = [];
// Init: // Init:
if (this.authService.IsAuthorized) { if (this.authService.IsAuthorized) {
if (this.authService.UserData) { if (this.authService.UserData) {
this.basket.buyerId = this.authService.UserData.sub; this.basket.buyerId = this.authService.UserData.sub;
this.getBasket().subscribe(basket => {
this.basket = basket;
});
if (this.configurationService.isReady) {
this.basketUrl = this.configurationService.serverSettings.basketUrl;
this.loadData();
}
else {
this.configurationService.settingsLoaded$.subscribe(x => {
this.basketUrl = this.configurationService.serverSettings.basketUrl;
this.loadData();
});
}
} }
} }
@ -45,7 +54,7 @@ export class BasketService {
this.dropBasket(); this.dropBasket();
}); });
} }
setBasket(item): Observable<boolean> { setBasket(item): Observable<boolean> {
this.basket.items.push(item); this.basket.items.push(item);
return this.service.post(this.basketUrl + '/', this.basket).map((response: Response) => { return this.service.post(this.basketUrl + '/', this.basket).map((response: Response) => {
@ -55,12 +64,24 @@ export class BasketService {
getBasket(): Observable<IBasket> { getBasket(): Observable<IBasket> {
return this.service.get(this.basketUrl + '/' + this.basket.buyerId).map((response: Response) => { return this.service.get(this.basketUrl + '/' + this.basket.buyerId).map((response: Response) => {
if (response.status === 204) {
return null;
}
return response.json(); return response.json();
}); });
} }
dropBasket() { dropBasket() {
this.basket.items = [];
this.service.delete(this.basketUrl + '/' + this.basket.buyerId); this.service.delete(this.basketUrl + '/' + this.basket.buyerId);
this.basketDropedSource.next(); this.basketDropedSource.next();
} }
private loadData() {
this.getBasket().subscribe(basket => {
if (basket != null)
this.basket.items = basket.items;
});
}
} }

+ 12
- 1
src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.component.ts View File

@ -1,5 +1,6 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { CatalogService } from './catalog.service'; import { CatalogService } from './catalog.service';
import { ConfigurationService } from '../shared/services/configuration.service';
import { ICatalog } from '../shared/models/catalog.model'; import { ICatalog } from '../shared/models/catalog.model';
import { ICatalogItem } from '../shared/models/catalogItem.model'; import { ICatalogItem } from '../shared/models/catalogItem.model';
import { ICatalogType } from '../shared/models/catalogType.model'; import { ICatalogType } from '../shared/models/catalogType.model';
@ -20,9 +21,19 @@ export class CatalogComponent implements OnInit {
typeSelected: number; typeSelected: number;
paginationInfo: IPager; paginationInfo: IPager;
constructor(private service: CatalogService, private basketService: BasketWrapperService) { }
constructor(private service: CatalogService, private basketService: BasketWrapperService, private configurationService: ConfigurationService) { }
ngOnInit() { ngOnInit() {
if (this.configurationService.isReady) {
this.loadData();
}else{
this.configurationService.settingsLoaded$.subscribe(x => {
this.loadData();
});
}
}
loadData() {
this.getBrands(); this.getBrands();
this.getCatalog(10, 0); this.getCatalog(10, 0);
this.getTypes(); this.getTypes();


+ 12
- 6
src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.service.ts View File

@ -2,6 +2,7 @@ import { Injectable } from '@angular/core';
import { Response } from '@angular/http'; import { Response } from '@angular/http';
import { DataService } from '../shared/services/data.service'; import { DataService } from '../shared/services/data.service';
import { ConfigurationService } from '../shared/services/configuration.service';
import { ICatalog } from '../shared/models/catalog.model'; import { ICatalog } from '../shared/models/catalog.model';
import { ICatalogBrand } from '../shared/models/catalogBrand.model'; import { ICatalogBrand } from '../shared/models/catalogBrand.model';
import { ICatalogType } from '../shared/models/catalogType.model'; import { ICatalogType } from '../shared/models/catalogType.model';
@ -14,11 +15,16 @@ import 'rxjs/add/operator/map';
@Injectable() @Injectable()
export class CatalogService { export class CatalogService {
private catalogUrl: string = 'http://eshopcontainers:5101/api/v1/catalog/items';
private brandUrl: string = 'http://eshopcontainers:5101/api/v1/catalog/catalogbrands';
private typesUrl: string = 'http://eshopcontainers:5101/api/v1/catalog/catalogtypes';
constructor(private service: DataService) {
private catalogUrl: string = '';
private brandUrl: string = '';
private typesUrl: string = '';
constructor(private service: DataService, private configurationService: ConfigurationService) {
this.configurationService.settingsLoaded$.subscribe(x => {
this.catalogUrl = this.configurationService.serverSettings.catalogUrl + '/api/v1/catalog/items';
this.brandUrl = this.configurationService.serverSettings.catalogUrl + '/api/v1/catalog/catalogbrands';
this.typesUrl = this.configurationService.serverSettings.catalogUrl + '/api/v1/catalog/catalogtypes';
});
} }
getCatalog(pageIndex: number, pageSize: number, brand: number, type: number): Observable<ICatalog> { getCatalog(pageIndex: number, pageSize: number, brand: number, type: number): Observable<ICatalog> {
@ -45,4 +51,4 @@ export class CatalogService {
return response.json(); return response.json();
}); });
}; };
}
}

+ 9
- 2
src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/orders/orders.component.ts View File

@ -1,6 +1,7 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { OrdersService } from './orders.service'; import { OrdersService } from './orders.service';
import { IOrder } from '../shared/models/order.model'; import { IOrder } from '../shared/models/order.model';
import { ConfigurationService } from '../shared/services/configuration.service';
@Component({ @Component({
selector: 'esh-orders', selector: 'esh-orders',
@ -10,10 +11,16 @@ import { IOrder } from '../shared/models/order.model';
export class OrdersComponent implements OnInit { export class OrdersComponent implements OnInit {
orders: IOrder[]; orders: IOrder[];
constructor(private service: OrdersService) { }
constructor(private service: OrdersService, private configurationService: ConfigurationService) { }
ngOnInit() { ngOnInit() {
this.getOrders();
if (this.configurationService.isReady) {
this.getOrders()
} else {
this.configurationService.settingsLoaded$.subscribe(x => {
this.getOrders();
});
}
} }


+ 11
- 5
src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/orders/orders.service.ts View File

@ -5,6 +5,7 @@ import { DataService } from '../shared/services/data.service';
import { IOrder } from '../shared/models/order.model'; import { IOrder } from '../shared/models/order.model';
import { IOrderItem } from '../shared/models/orderItem.model'; import { IOrderItem } from '../shared/models/orderItem.model';
import { SecurityService } from '../shared/services/security.service'; import { SecurityService } from '../shared/services/security.service';
import { ConfigurationService } from '../shared/services/configuration.service';
import { BasketWrapperService } from '../shared/services/basket.wrapper.service'; import { BasketWrapperService } from '../shared/services/basket.wrapper.service';
import 'rxjs/Rx'; import 'rxjs/Rx';
@ -16,13 +17,18 @@ import 'rxjs/add/operator/map';
@Injectable() @Injectable()
export class OrdersService { export class OrdersService {
private ordersUrl: string = 'http://eshopcontainers:5102/api/v1/orders';
private ordersUrl: string = '';
constructor(private service: DataService, private basketService: BasketWrapperService, private identityService: SecurityService, private configurationService: ConfigurationService) {
if (this.configurationService.isReady)
this.ordersUrl = this.configurationService.serverSettings.orderingUrl;
else
this.configurationService.settingsLoaded$.subscribe(x => this.ordersUrl = this.configurationService.serverSettings.orderingUrl);
constructor(private service: DataService, private basketService: BasketWrapperService, private identityService: SecurityService) {
} }
getOrders(): Observable<IOrder[]> { getOrders(): Observable<IOrder[]> {
let url = this.ordersUrl;
let url = this.ordersUrl + '/api/v1/orders';
return this.service.get(url).map((response: Response) => { return this.service.get(url).map((response: Response) => {
return response.json(); return response.json();
@ -30,7 +36,7 @@ export class OrdersService {
} }
getOrder(id: number): Observable<IOrder> { getOrder(id: number): Observable<IOrder> {
let url = `${this.ordersUrl}/${id}`;
let url = this.ordersUrl + '/api/v1/orders/' + id;
return this.service.get(url).map((response: Response) => { return this.service.get(url).map((response: Response) => {
return response.json(); return response.json();
@ -38,7 +44,7 @@ export class OrdersService {
} }
postOrder(item): Observable<boolean> { postOrder(item): Observable<boolean> {
return this.service.post(this.ordersUrl + '/new', item).map((response: Response) => {
return this.service.post(this.ordersUrl + '/api/v1/orders/new', item).map((response: Response) => {
return true; return true;
}); });
} }


+ 6
- 0
src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/configuration.model.ts View File

@ -0,0 +1,6 @@
export interface IConfiguration {
catalogUrl: string,
orderingUrl: string,
identityUrl: string,
basketUrl: string
}

+ 38
- 0
src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/services/configuration.service.ts View File

@ -0,0 +1,38 @@
import { Injectable } from '@angular/core';
import { Http, Response, RequestOptionsArgs, RequestMethod, Headers } from '@angular/http';
import { IConfiguration } from '../models/configuration.model';
import { StorageService } from './storage.service';
import 'rxjs/Rx';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/throw';
import { Observer } from 'rxjs/Observer';
import 'rxjs/add/operator/map';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class ConfigurationService {
serverSettings: IConfiguration;
// observable that is fired when settings are loaded from server
private settingsLoadedSource = new Subject();
settingsLoaded$ = this.settingsLoadedSource.asObservable();
isReady: boolean = false;
constructor(private http: Http, private storageService: StorageService) { }
load() {
let url = "http://localhost:5104/Home/Configuration";
this.http.get(url).subscribe((response: Response) => {
console.log('server settings loaded');
this.serverSettings = response.json();
console.log(this.serverSettings);
this.storageService.store('basketUrl', this.serverSettings.basketUrl);
this.storageService.store('catalogUrl', this.serverSettings.catalogUrl);
this.storageService.store('identityUrl', this.serverSettings.identityUrl);
this.storageService.store('orderingUrl', this.serverSettings.orderingUrl);
this.isReady = true;
this.settingsLoadedSource.next();
});
}
}

+ 47
- 36
src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/services/security.service.ts View File

@ -5,58 +5,66 @@ import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject'; import { Subject } from 'rxjs/Subject';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { ConfigurationService } from './configuration.service';
import { StorageService } from './storage.service';
@Injectable() @Injectable()
export class SecurityService { export class SecurityService {
private actionUrl: string; private actionUrl: string;
private headers: Headers; private headers: Headers;
private storage: any;
private storage: StorageService;
private authenticationSource = new Subject<boolean>(); private authenticationSource = new Subject<boolean>();
authenticationChallenge$ = this.authenticationSource.asObservable(); authenticationChallenge$ = this.authenticationSource.asObservable();
private authorityUrl = '';
constructor(private _http: Http, private _router: Router, private route: ActivatedRoute) {
constructor(private _http: Http, private _router: Router, private route: ActivatedRoute, private _configurationService: ConfigurationService, private _storageService: StorageService) {
this.headers = new Headers(); this.headers = new Headers();
this.headers.append('Content-Type', 'application/json'); this.headers.append('Content-Type', 'application/json');
this.headers.append('Accept', 'application/json'); this.headers.append('Accept', 'application/json');
this.storage = sessionStorage; // localStorage;
this.storage = _storageService;
if (this.retrieve('IsAuthorized') !== '') {
this.IsAuthorized = this.retrieve('IsAuthorized');
this._configurationService.settingsLoaded$.subscribe(x => {
this.authorityUrl = this._configurationService.serverSettings.identityUrl
this.storage.store('IdentityUrl', this.authorityUrl);
});
if (this.storage.retrieve('IsAuthorized') !== '') {
this.IsAuthorized = this.storage.retrieve('IsAuthorized');
this.authenticationSource.next(true); this.authenticationSource.next(true);
this.UserData = this.retrieve('userData');
this.UserData = this.storage.retrieve('userData');
} }
} }
public IsAuthorized: boolean; public IsAuthorized: boolean;
public GetToken(): any { public GetToken(): any {
return this.retrieve('authorizationData');
return this.storage.retrieve('authorizationData');
} }
public ResetAuthorizationData() { public ResetAuthorizationData() {
this.store('authorizationData', '');
this.store('authorizationDataIdToken', '');
this.storage.store('authorizationData', '');
this.storage.store('authorizationDataIdToken', '');
this.IsAuthorized = false; this.IsAuthorized = false;
this.store('IsAuthorized', false);
this.storage.store('IsAuthorized', false);
} }
public UserData: any; public UserData: any;
public SetAuthorizationData(token: any, id_token: any) { public SetAuthorizationData(token: any, id_token: any) {
if (this.retrieve('authorizationData') !== '') {
this.store('authorizationData', '');
if (this.storage.retrieve('authorizationData') !== '') {
this.storage.store('authorizationData', '');
} }
this.store('authorizationData', token);
this.store('authorizationDataIdToken', id_token);
this.storage.store('authorizationData', token);
this.storage.store('authorizationDataIdToken', id_token);
this.IsAuthorized = true; this.IsAuthorized = true;
this.store('IsAuthorized', true);
this.storage.store('IsAuthorized', true);
this.getUserData() this.getUserData()
.subscribe(data => { .subscribe(data => {
this.UserData = data; this.UserData = data;
this.store('userData', data);
this.storage.store('userData', data);
// emit observable // emit observable
this.authenticationSource.next(true); this.authenticationSource.next(true);
window.location.href = 'http://localhost:5104'; window.location.href = 'http://localhost:5104';
@ -70,7 +78,7 @@ export class SecurityService {
public Authorize() { public Authorize() {
this.ResetAuthorizationData(); this.ResetAuthorizationData();
let authorizationUrl = 'http://10.0.75.1:5105/connect/authorize';
let authorizationUrl = this.authorityUrl + '/connect/authorize';
let client_id = 'js'; let client_id = 'js';
let redirect_uri = 'http://localhost:5104/'; let redirect_uri = 'http://localhost:5104/';
let response_type = 'id_token token'; let response_type = 'id_token token';
@ -78,8 +86,8 @@ export class SecurityService {
let nonce = 'N' + Math.random() + '' + Date.now(); let nonce = 'N' + Math.random() + '' + Date.now();
let state = Date.now() + '' + Math.random(); let state = Date.now() + '' + Math.random();
this.store('authStateControl', state);
this.store('authNonce', nonce);
this.storage.store('authStateControl', state);
this.storage.store('authNonce', nonce);
let url = let url =
authorizationUrl + '?' + authorizationUrl + '?' +
@ -112,7 +120,7 @@ export class SecurityService {
if (!result.error) { if (!result.error) {
if (result.state !== this.retrieve('authStateControl')) {
if (result.state !== this.storage.retrieve('authStateControl')) {
console.log('AuthorizedCallback incorrect state'); console.log('AuthorizedCallback incorrect state');
} else { } else {
@ -123,11 +131,11 @@ export class SecurityService {
console.log(dataIdToken); console.log(dataIdToken);
// validate nonce // validate nonce
if (dataIdToken.nonce !== this.retrieve('authNonce')) {
if (dataIdToken.nonce !== this.storage.retrieve('authNonce')) {
console.log('AuthorizedCallback incorrect nonce'); console.log('AuthorizedCallback incorrect nonce');
} else { } else {
this.store('authNonce', '');
this.store('authStateControl', '');
this.storage.store('authNonce', '');
this.storage.store('authStateControl', '');
authResponseIsValid = true; authResponseIsValid = true;
console.log('AuthorizedCallback state and nonce validated, returning access token'); console.log('AuthorizedCallback state and nonce validated, returning access token');
@ -142,8 +150,8 @@ export class SecurityService {
} }
public Logoff() { public Logoff() {
let authorizationUrl = 'http://10.0.75.1:5105/connect/endsession';
let id_token_hint = this.retrieve('authorizationDataIdToken');
let authorizationUrl = this.authorityUrl + '/connect/endsession';
let id_token_hint = this.storage.retrieve('authorizationDataIdToken');
let post_logout_redirect_uri = 'http://localhost:5104/'; let post_logout_redirect_uri = 'http://localhost:5104/';
let url = let url =
@ -197,23 +205,26 @@ export class SecurityService {
return data; return data;
} }
private retrieve(key: string): any {
let item = this.storage.getItem(key);
//private retrieve(key: string): any {
// let item = this.storage.getItem(key);
if (item && item !== 'undefined') {
return JSON.parse(this.storage.getItem(key));
}
// if (item && item !== 'undefined') {
// return JSON.parse(this.storage.getItem(key));
// }
return;
}
// return;
//}
private store(key: string, value: any) {
this.storage.setItem(key, JSON.stringify(value));
}
//private store(key: string, value: any) {
// this.storage.setItem(key, JSON.stringify(value));
//}
private getUserData = (): Observable<string[]> => { private getUserData = (): Observable<string[]> => {
this.setHeaders(); this.setHeaders();
return this._http.get('http://10.0.75.1:5105/connect/userinfo', {
if (this.authorityUrl === '')
this.authorityUrl = this.storage.retrieve('IdentityUrl');
return this._http.get(this.authorityUrl + '/connect/userinfo', {
headers: this.headers, headers: this.headers,
body: '' body: ''
}).map(res => res.json()); }).map(res => res.json());


+ 24
- 0
src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/services/storage.service.ts View File

@ -0,0 +1,24 @@
import { Injectable } from '@angular/core';
@Injectable()
export class StorageService {
private storage: any;
constructor() {
this.storage = sessionStorage; // localStorage;
}
public retrieve(key: string): any {
let item = this.storage.getItem(key);
if (item && item !== 'undefined') {
return JSON.parse(this.storage.getItem(key));
}
return;
}
public store(key: string, value: any) {
this.storage.setItem(key, JSON.stringify(value));
}
}

+ 5
- 1
src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/shared.module.ts View File

@ -9,6 +9,8 @@ import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { DataService } from './services/data.service'; import { DataService } from './services/data.service';
import { BasketWrapperService} from './services/basket.wrapper.service'; import { BasketWrapperService} from './services/basket.wrapper.service';
import { SecurityService } from './services/security.service'; import { SecurityService } from './services/security.service';
import { ConfigurationService } from './services/configuration.service';
import { StorageService } from './services/storage.service';
// Components: // Components:
import { Pager } from './components/pager/pager'; import { Pager } from './components/pager/pager';
@ -52,7 +54,9 @@ export class SharedModule {
// Providers // Providers
DataService, DataService,
BasketWrapperService, BasketWrapperService,
SecurityService
SecurityService,
ConfigurationService,
StorageService
] ]
}; };
} }


+ 0
- 6
src/Web/WebSPA/eShopOnContainers.WebSPA/Program.cs View File

@ -8,14 +8,8 @@ namespace eShopConContainers.WebSPA
{ {
public static void Main(string[] args) public static void Main(string[] args)
{ {
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
//.AddJsonFile("hosting.json", optional: true)
.Build();
var host = new WebHostBuilder() var host = new WebHostBuilder()
.UseKestrel() .UseKestrel()
.UseConfiguration(config)
.UseContentRoot(Directory.GetCurrentDirectory()) .UseContentRoot(Directory.GetCurrentDirectory())
.UseUrls("http://0.0.0.0:5104") .UseUrls("http://0.0.0.0:5104")
.UseIISIntegration() .UseIISIntegration()


+ 9
- 1
src/Web/WebSPA/eShopOnContainers.WebSPA/Server/Controllers/HomeController.cs View File

@ -3,16 +3,20 @@
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using eShopOnContainers.WebSPA;
namespace eShopConContainers.WebSPA.Server.Controllers namespace eShopConContainers.WebSPA.Server.Controllers
{ {
public class HomeController : Controller public class HomeController : Controller
{ {
private readonly IHostingEnvironment _env; private readonly IHostingEnvironment _env;
private readonly IOptions<AppSettings> _settings;
public HomeController(IHostingEnvironment env)
public HomeController(IHostingEnvironment env, IOptions<AppSettings> settings)
{ {
_env = env; _env = env;
_settings = settings;
} }
public IActionResult Index() public IActionResult Index()
@ -31,5 +35,9 @@ namespace eShopConContainers.WebSPA.Server.Controllers
return file.Name; return file.Name;
} }
public IActionResult Configuration()
{
return Json(_settings.Value);
}
} }
} }

+ 4
- 1
src/Web/WebSPA/eShopOnContainers.WebSPA/Startup.cs View File

@ -8,6 +8,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Serialization;
using eShopOnContainers.WebSPA;
namespace eShopConContainers.WebSPA namespace eShopConContainers.WebSPA
{ {
@ -33,11 +34,13 @@ namespace eShopConContainers.WebSPA
Configuration = builder.Build(); Configuration = builder.Build();
} }
public static IConfigurationRoot Configuration { get; set; }
public static IConfigurationRoot Configuration { get; set;}
// This method gets called by the runtime. Use this method to add services to the container. // This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940 // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
services.Configure<AppSettings>(Configuration);
services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN"); services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
services.AddMvc() services.AddMvc()


+ 4
- 0
src/Web/WebSPA/eShopOnContainers.WebSPA/appsettings.json View File

@ -1,4 +1,8 @@
{ {
"CatalogUrl": "http://localhost:5101",
"OrderingUrl": "http://localhost:5102",
"BasketUrl": "http://localhost:5103",
"IdentityUrl": "http://localhost:5105",
"Logging": { "Logging": {
"IncludeScopes": false, "IncludeScopes": false,
"LogLevel": { "LogLevel": {


+ 4
- 5
src/Web/WebSPA/eShopOnContainers.WebSPA/project.json View File

@ -27,6 +27,7 @@
"Microsoft.Extensions.Logging": "1.0.0", "Microsoft.Extensions.Logging": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0", "Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.Extensions.Logging.Debug": "1.0.0", "Microsoft.Extensions.Logging.Debug": "1.0.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0",
"Microsoft.VisualStudio.Web.CodeGeneration.Tools": { "Microsoft.VisualStudio.Web.CodeGeneration.Tools": {
"version": "1.0.0-preview2-final", "version": "1.0.0-preview2-final",
"type": "build" "type": "build"
@ -101,11 +102,9 @@
] ]
}, },
"scripts": { "scripts": {
//"prepublish": [
// "npm install",
// "node node_modules/webpack/bin/webpack.js --config config/webpack.config.vendor.js",
// "node node_modules/webpack/bin/webpack.js --config config/webpack.config.js"
//],
"prepublish": [
"npm run build:prod"
],
"postpublish": [ "postpublish": [
"dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%"
] ]


Loading…
Cancel
Save