diff --git a/docker-compose.override.yml b/docker-compose.override.yml index e5cadd087..48fd03b99 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -21,11 +21,11 @@ services: webspa: 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://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: - "5104:5104" @@ -40,7 +40,7 @@ services: catalog.api: environment: - 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 ports: - "5101:5101" diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/Auth/AuthorizationHeaderParameterOperationFilter.cs b/src/Services/Ordering/Ordering.API/Infrastructure/Auth/AuthorizationHeaderParameterOperationFilter.cs new file mode 100644 index 000000000..94e2a48c2 --- /dev/null +++ b/src/Services/Ordering/Ordering.API/Infrastructure/Auth/AuthorizationHeaderParameterOperationFilter.cs @@ -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(); + + operation.Parameters.Add(new NonBodyParameter + { + Name = "Authorization", + In = "header", + Description = "access token", + Required = true, + Type = "string" + }); + } + } + } +} diff --git a/src/Services/Ordering/Ordering.API/Startup.cs b/src/Services/Ordering/Ordering.API/Startup.cs index a9883c764..05a7defbb 100644 --- a/src/Services/Ordering/Ordering.API/Startup.cs +++ b/src/Services/Ordering/Ordering.API/Startup.cs @@ -4,6 +4,7 @@ using Autofac; using Autofac.Extensions.DependencyInjection; using Infrastructure; + using Infrastructure.Auth; using Infrastructure.AutofacModules; using Infrastructure.Filters; using Infrastructure.Services; @@ -41,7 +42,6 @@ public IServiceProvider ConfigureServices(IServiceCollection services) { // Add framework services. - services.AddMvc(options => { options.Filters.Add(typeof(HttpGlobalExceptionFilter)); @@ -57,6 +57,7 @@ services.AddSwaggerGen(); services.ConfigureSwaggerGen(options => { + options.OperationFilter(); options.DescribeAllEnumsAsStrings(); options.SingleApiVersion(new Swashbuckle.Swagger.Model.Info() { diff --git a/src/Web/WebMVC/Startup.cs b/src/Web/WebMVC/Startup.cs index 49106f017..c6020eeeb 100644 --- a/src/Web/WebMVC/Startup.cs +++ b/src/Web/WebMVC/Startup.cs @@ -25,13 +25,13 @@ namespace Microsoft.eShopOnContainers.WebMVC .SetBasePath(env.ContentRootPath) .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) // Settings for the application .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(); } diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/AppSettings.cs b/src/Web/WebSPA/eShopOnContainers.WebSPA/AppSettings.cs new file mode 100644 index 000000000..19e2b5cfe --- /dev/null +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/AppSettings.cs @@ -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; } + } +} diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/app.component.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/app.component.ts index 22c9d76ab..00abe4ad4 100644 --- a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/app.component.ts +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/app.component.ts @@ -5,6 +5,7 @@ import { Subscription } from 'rxjs/Subscription'; import { DataService } from './shared/services/data.service'; import { SecurityService } from './shared/services/security.service'; +import { ConfigurationService } from './shared/services/configuration.service'; /* * App Component @@ -20,13 +21,17 @@ export class AppComponent implements OnInit { private Authenticated: boolean = false; subscription: Subscription; - constructor(private titleService: Title, private securityService: SecurityService) { + constructor(private titleService: Title, private securityService: SecurityService, private configurationService: ConfigurationService) { this.Authenticated = this.securityService.IsAuthorized; } ngOnInit() { console.log('app on init'); 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) { diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/basket/basket-status/basket-status.component.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/basket/basket-status/basket-status.component.ts index a9617978f..0680fefa0 100644 --- a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/basket/basket-status/basket-status.component.ts +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/basket/basket-status/basket-status.component.ts @@ -4,6 +4,7 @@ import { Subscription } from 'rxjs/Subscription'; import { BasketService } from '../basket.service'; import { BasketWrapperService } from '../../shared/services/basket.wrapper.service'; import { SecurityService } from '../../shared/services/security.service'; +import { ConfigurationService } from '../../shared/services/configuration.service'; @Component({ selector: 'esh-basket-status', @@ -17,7 +18,7 @@ export class BasketStatusComponent implements OnInit { 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() { // Subscribe to Add Basket Observable: @@ -25,7 +26,8 @@ export class BasketStatusComponent implements OnInit { item => { this.service.setBasket(item).subscribe(res => { 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: this.basketDroppedSubscription = this.service.basketDroped$.subscribe(res => { this.badge = 0; - console.log('dropped event fired'); }); // Subscribe to login and logout observable this.authSubscription = this.authService.authenticationChallenge$.subscribe(res => { this.service.getBasket().subscribe(basket => { - this.badge = basket.items.length; + if (basket != null) + this.badge = basket.items.length; }); }); // 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; + }); + }); + } } } diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/basket/basket.service.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/basket/basket.service.ts index 0227b7a2d..4417eaad5 100644 --- a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/basket/basket.service.ts +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/basket/basket.service.ts @@ -7,6 +7,8 @@ import { SecurityService } from '../shared/services/security.service'; import { IBasket } from '../shared/models/basket.model'; import { IBasketItem } from '../shared/models/basketItem.model'; 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 { Observable } from 'rxjs/Observable'; @@ -14,11 +16,11 @@ import 'rxjs/add/observable/throw'; import { Observer } from 'rxjs/Observer'; import 'rxjs/add/operator/map'; import 'rxjs/add/operator/catch'; -import { Subject } from 'rxjs/Subject'; +import { Subject } from 'rxjs/Subject'; @Injectable() export class BasketService { - private basketUrl: string = 'http://eshopcontainers:5103'; + private basketUrl: string = ''; basket: IBasket = { buyerId: '', items: [] @@ -28,16 +30,23 @@ export class BasketService { private basketDropedSource = new Subject(); 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 = []; - + // Init: if (this.authService.IsAuthorized) { if (this.authService.UserData) { 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(); }); } - + setBasket(item): Observable { this.basket.items.push(item); return this.service.post(this.basketUrl + '/', this.basket).map((response: Response) => { @@ -55,12 +64,24 @@ export class BasketService { getBasket(): Observable { return this.service.get(this.basketUrl + '/' + this.basket.buyerId).map((response: Response) => { + if (response.status === 204) { + return null; + } + return response.json(); }); } dropBasket() { + this.basket.items = []; this.service.delete(this.basketUrl + '/' + this.basket.buyerId); this.basketDropedSource.next(); } + + private loadData() { + this.getBasket().subscribe(basket => { + if (basket != null) + this.basket.items = basket.items; + }); + } } \ No newline at end of file diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.component.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.component.ts index 5ae78fd9c..db6a4c7be 100644 --- a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.component.ts +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.component.ts @@ -1,5 +1,6 @@ import { Component, OnInit } from '@angular/core'; import { CatalogService } from './catalog.service'; +import { ConfigurationService } from '../shared/services/configuration.service'; import { ICatalog } from '../shared/models/catalog.model'; import { ICatalogItem } from '../shared/models/catalogItem.model'; import { ICatalogType } from '../shared/models/catalogType.model'; @@ -20,9 +21,19 @@ export class CatalogComponent implements OnInit { typeSelected: number; paginationInfo: IPager; - constructor(private service: CatalogService, private basketService: BasketWrapperService) { } + constructor(private service: CatalogService, private basketService: BasketWrapperService, private configurationService: ConfigurationService) { } ngOnInit() { + if (this.configurationService.isReady) { + this.loadData(); + }else{ + this.configurationService.settingsLoaded$.subscribe(x => { + this.loadData(); + }); + } + } + + loadData() { this.getBrands(); this.getCatalog(10, 0); this.getTypes(); diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.service.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.service.ts index f79840179..bdcb9d664 100644 --- a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.service.ts +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.service.ts @@ -2,6 +2,7 @@ import { Injectable } from '@angular/core'; import { Response } from '@angular/http'; import { DataService } from '../shared/services/data.service'; +import { ConfigurationService } from '../shared/services/configuration.service'; import { ICatalog } from '../shared/models/catalog.model'; import { ICatalogBrand } from '../shared/models/catalogBrand.model'; import { ICatalogType } from '../shared/models/catalogType.model'; @@ -14,11 +15,16 @@ import 'rxjs/add/operator/map'; @Injectable() 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 { @@ -45,4 +51,4 @@ export class CatalogService { return response.json(); }); }; -} \ No newline at end of file +} diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/orders/orders.component.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/orders/orders.component.ts index 218b692f3..78d52a132 100644 --- a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/orders/orders.component.ts +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/orders/orders.component.ts @@ -1,6 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { OrdersService } from './orders.service'; import { IOrder } from '../shared/models/order.model'; +import { ConfigurationService } from '../shared/services/configuration.service'; @Component({ selector: 'esh-orders', @@ -10,10 +11,16 @@ import { IOrder } from '../shared/models/order.model'; export class OrdersComponent implements OnInit { orders: IOrder[]; - constructor(private service: OrdersService) { } + constructor(private service: OrdersService, private configurationService: ConfigurationService) { } ngOnInit() { - this.getOrders(); + if (this.configurationService.isReady) { + this.getOrders() + } else { + this.configurationService.settingsLoaded$.subscribe(x => { + this.getOrders(); + }); + } } diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/orders/orders.service.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/orders/orders.service.ts index 8d0b4d91a..20899b9a9 100644 --- a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/orders/orders.service.ts +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/orders/orders.service.ts @@ -5,6 +5,7 @@ import { DataService } from '../shared/services/data.service'; import { IOrder } from '../shared/models/order.model'; import { IOrderItem } from '../shared/models/orderItem.model'; import { SecurityService } from '../shared/services/security.service'; +import { ConfigurationService } from '../shared/services/configuration.service'; import { BasketWrapperService } from '../shared/services/basket.wrapper.service'; import 'rxjs/Rx'; @@ -16,13 +17,18 @@ import 'rxjs/add/operator/map'; @Injectable() 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 { - let url = this.ordersUrl; + let url = this.ordersUrl + '/api/v1/orders'; return this.service.get(url).map((response: Response) => { return response.json(); @@ -30,7 +36,7 @@ export class OrdersService { } getOrder(id: number): Observable { - let url = `${this.ordersUrl}/${id}`; + let url = this.ordersUrl + '/api/v1/orders/' + id; return this.service.get(url).map((response: Response) => { return response.json(); @@ -38,7 +44,7 @@ export class OrdersService { } postOrder(item): Observable { - 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; }); } diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/configuration.model.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/configuration.model.ts new file mode 100644 index 000000000..74efe89a4 --- /dev/null +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/configuration.model.ts @@ -0,0 +1,6 @@ +export interface IConfiguration { + catalogUrl: string, + orderingUrl: string, + identityUrl: string, + basketUrl: string +} \ No newline at end of file diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/services/configuration.service.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/services/configuration.service.ts new file mode 100644 index 000000000..bfe672e5e --- /dev/null +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/services/configuration.service.ts @@ -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(); + }); + } +} diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/services/security.service.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/services/security.service.ts index c3e15806d..47e70a60a 100644 --- a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/services/security.service.ts +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/services/security.service.ts @@ -5,58 +5,66 @@ import { Observable } from 'rxjs/Observable'; import { Subject } from 'rxjs/Subject'; import { Router } from '@angular/router'; import { ActivatedRoute } from '@angular/router'; +import { ConfigurationService } from './configuration.service'; +import { StorageService } from './storage.service'; @Injectable() export class SecurityService { private actionUrl: string; private headers: Headers; - private storage: any; + private storage: StorageService; private authenticationSource = new Subject(); 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.append('Content-Type', '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.UserData = this.retrieve('userData'); + this.UserData = this.storage.retrieve('userData'); } } public IsAuthorized: boolean; public GetToken(): any { - return this.retrieve('authorizationData'); + return this.storage.retrieve('authorizationData'); } public ResetAuthorizationData() { - this.store('authorizationData', ''); - this.store('authorizationDataIdToken', ''); + this.storage.store('authorizationData', ''); + this.storage.store('authorizationDataIdToken', ''); this.IsAuthorized = false; - this.store('IsAuthorized', false); + this.storage.store('IsAuthorized', false); } public UserData: 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.store('IsAuthorized', true); + this.storage.store('IsAuthorized', true); this.getUserData() .subscribe(data => { this.UserData = data; - this.store('userData', data); + this.storage.store('userData', data); // emit observable this.authenticationSource.next(true); window.location.href = 'http://localhost:5104'; @@ -70,7 +78,7 @@ export class SecurityService { public Authorize() { this.ResetAuthorizationData(); - let authorizationUrl = 'http://10.0.75.1:5105/connect/authorize'; + let authorizationUrl = this.authorityUrl + '/connect/authorize'; let client_id = 'js'; let redirect_uri = 'http://localhost:5104/'; let response_type = 'id_token token'; @@ -78,8 +86,8 @@ export class SecurityService { let nonce = 'N' + Math.random() + '' + Date.now(); 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 = authorizationUrl + '?' + @@ -112,7 +120,7 @@ export class SecurityService { if (!result.error) { - if (result.state !== this.retrieve('authStateControl')) { + if (result.state !== this.storage.retrieve('authStateControl')) { console.log('AuthorizedCallback incorrect state'); } else { @@ -123,11 +131,11 @@ export class SecurityService { console.log(dataIdToken); // validate nonce - if (dataIdToken.nonce !== this.retrieve('authNonce')) { + if (dataIdToken.nonce !== this.storage.retrieve('authNonce')) { console.log('AuthorizedCallback incorrect nonce'); } else { - this.store('authNonce', ''); - this.store('authStateControl', ''); + this.storage.store('authNonce', ''); + this.storage.store('authStateControl', ''); authResponseIsValid = true; console.log('AuthorizedCallback state and nonce validated, returning access token'); @@ -142,8 +150,8 @@ export class SecurityService { } 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 url = @@ -197,23 +205,26 @@ export class SecurityService { 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 => { 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, body: '' }).map(res => res.json()); diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/services/storage.service.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/services/storage.service.ts new file mode 100644 index 000000000..e11bd96be --- /dev/null +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/services/storage.service.ts @@ -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)); + } +} diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/shared.module.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/shared.module.ts index 4b6e60a40..64441396f 100644 --- a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/shared.module.ts +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/shared.module.ts @@ -9,6 +9,8 @@ import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { DataService } from './services/data.service'; import { BasketWrapperService} from './services/basket.wrapper.service'; import { SecurityService } from './services/security.service'; +import { ConfigurationService } from './services/configuration.service'; +import { StorageService } from './services/storage.service'; // Components: import { Pager } from './components/pager/pager'; @@ -52,7 +54,9 @@ export class SharedModule { // Providers DataService, BasketWrapperService, - SecurityService + SecurityService, + ConfigurationService, + StorageService ] }; } diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Program.cs b/src/Web/WebSPA/eShopOnContainers.WebSPA/Program.cs index 40099c4e9..ffad0461e 100644 --- a/src/Web/WebSPA/eShopOnContainers.WebSPA/Program.cs +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Program.cs @@ -8,14 +8,8 @@ namespace eShopConContainers.WebSPA { public static void Main(string[] args) { - var config = new ConfigurationBuilder() - .SetBasePath(Directory.GetCurrentDirectory()) - //.AddJsonFile("hosting.json", optional: true) - .Build(); - var host = new WebHostBuilder() .UseKestrel() - .UseConfiguration(config) .UseContentRoot(Directory.GetCurrentDirectory()) .UseUrls("http://0.0.0.0:5104") .UseIISIntegration() diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Server/Controllers/HomeController.cs b/src/Web/WebSPA/eShopOnContainers.WebSPA/Server/Controllers/HomeController.cs index c70a67769..ee980e334 100644 --- a/src/Web/WebSPA/eShopOnContainers.WebSPA/Server/Controllers/HomeController.cs +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Server/Controllers/HomeController.cs @@ -3,16 +3,20 @@ using System.Linq; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; +using eShopOnContainers.WebSPA; namespace eShopConContainers.WebSPA.Server.Controllers { public class HomeController : Controller { private readonly IHostingEnvironment _env; + private readonly IOptions _settings; - public HomeController(IHostingEnvironment env) + public HomeController(IHostingEnvironment env, IOptions settings) { _env = env; + _settings = settings; } public IActionResult Index() @@ -31,5 +35,9 @@ namespace eShopConContainers.WebSPA.Server.Controllers return file.Name; } + public IActionResult Configuration() + { + return Json(_settings.Value); + } } } diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Startup.cs b/src/Web/WebSPA/eShopOnContainers.WebSPA/Startup.cs index 705ba34f2..907e32d49 100644 --- a/src/Web/WebSPA/eShopOnContainers.WebSPA/Startup.cs +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Startup.cs @@ -8,6 +8,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Newtonsoft.Json.Serialization; +using eShopOnContainers.WebSPA; namespace eShopConContainers.WebSPA { @@ -33,11 +34,13 @@ namespace eShopConContainers.WebSPA 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. // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { + services.Configure(Configuration); + services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN"); services.AddMvc() diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/appsettings.json b/src/Web/WebSPA/eShopOnContainers.WebSPA/appsettings.json index 23bef8a13..ea2fed9ea 100644 --- a/src/Web/WebSPA/eShopOnContainers.WebSPA/appsettings.json +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/appsettings.json @@ -1,4 +1,8 @@ { + "CatalogUrl": "http://localhost:5101", + "OrderingUrl": "http://localhost:5102", + "BasketUrl": "http://localhost:5103", + "IdentityUrl": "http://localhost:5105", "Logging": { "IncludeScopes": false, "LogLevel": { diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/project.json b/src/Web/WebSPA/eShopOnContainers.WebSPA/project.json index 42bacd71b..57b813c07 100644 --- a/src/Web/WebSPA/eShopOnContainers.WebSPA/project.json +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/project.json @@ -27,6 +27,7 @@ "Microsoft.Extensions.Logging": "1.0.0", "Microsoft.Extensions.Logging.Console": "1.0.0", "Microsoft.Extensions.Logging.Debug": "1.0.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", "Microsoft.VisualStudio.Web.CodeGeneration.Tools": { "version": "1.0.0-preview2-final", "type": "build" @@ -101,11 +102,9 @@ ] }, "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": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]