Merge in 'release/5.0-preview8' changes
This commit is contained in:
commit
c60c278512
|
|
@ -245,8 +245,8 @@
|
|||
<IdentityServer4StoragePackageVersion>3.0.0</IdentityServer4StoragePackageVersion>
|
||||
<IdentityServer4EntityFrameworkStoragePackageVersion>3.0.0</IdentityServer4EntityFrameworkStoragePackageVersion>
|
||||
<MessagePackPackageVersion>2.1.90</MessagePackPackageVersion>
|
||||
<MicrosoftIdentityWebPackageVersion>0.2.0-preview</MicrosoftIdentityWebPackageVersion>
|
||||
<MicrosoftIdentityWebUIPackageVersion>0.2.0-preview</MicrosoftIdentityWebUIPackageVersion>
|
||||
<MicrosoftIdentityWebPackageVersion>0.2.1-preview</MicrosoftIdentityWebPackageVersion>
|
||||
<MicrosoftIdentityWebUIPackageVersion>0.2.1-preview</MicrosoftIdentityWebUIPackageVersion>
|
||||
<MicrosoftGraphPackageVersion>3.8.0</MicrosoftGraphPackageVersion>
|
||||
<MessagePackAnalyzerPackageVersion>$(MessagePackPackageVersion)</MessagePackAnalyzerPackageVersion>
|
||||
<MoqPackageVersion>4.10.0</MoqPackageVersion>
|
||||
|
|
|
|||
|
|
@ -188,5 +188,30 @@ namespace Templates.Test
|
|||
Browser.Exists(By.CssSelector("table>tbody>tr"));
|
||||
Browser.Equal(5, () => Browser.FindElements(By.CssSelector("p+table>tbody>tr")).Count);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[QuarantinedTest]
|
||||
[InlineData("IndividualB2C", null)]
|
||||
[InlineData("IndividualB2C", new string[] { "--called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
|
||||
[InlineData("SingleOrg", null)]
|
||||
[InlineData("SingleOrg", new string[] { "--called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
|
||||
[InlineData("SingleOrg", new string[] { "--calls-graph" })]
|
||||
public async Task BlazorServerTemplat_IdentityWeb_BuildAndPublish(string auth, string[] args)
|
||||
{
|
||||
Project = await ProjectFactory.GetOrCreateProject("blazorserveridweb" + Guid.NewGuid().ToString().Substring(0, 10).ToLower(), Output);
|
||||
|
||||
var createResult = await Project.RunDotNetNewAsync("blazorserver", auth: auth, args: args);
|
||||
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", Project, createResult));
|
||||
|
||||
var publishResult = await Project.RunDotNetPublishAsync();
|
||||
Assert.True(0 == publishResult.ExitCode, ErrorMessages.GetFailedProcessMessage("publish", Project, publishResult));
|
||||
|
||||
// Run dotnet build after publish. The reason is that one uses Config = Debug and the other uses Config = Release
|
||||
// The output from publish will go into bin/Release/netcoreappX.Y/publish and won't be affected by calling build
|
||||
// later, while the opposite is not true.
|
||||
|
||||
var buildResult = await Project.RunDotNetBuildAsync();
|
||||
Assert.True(0 == buildResult.ExitCode, ErrorMessages.GetFailedProcessMessage("build", Project, buildResult));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -418,6 +418,27 @@ namespace Templates.Test
|
|||
"--default-scope", "full",
|
||||
"--app-id-uri", "ApiUri",
|
||||
"--api-client-id", "1234123413241324"),
|
||||
new TemplateInstance(
|
||||
"blazorwasmhostedaadgraph", "-ho",
|
||||
"-au", "SingleOrg",
|
||||
"--calls-graph",
|
||||
"--domain", "my-domain",
|
||||
"--tenant-id", "tenantId",
|
||||
"--client-id", "clientId",
|
||||
"--default-scope", "full",
|
||||
"--app-id-uri", "ApiUri",
|
||||
"--api-client-id", "1234123413241324"),
|
||||
new TemplateInstance(
|
||||
"blazorwasmhostedaadapi", "-ho",
|
||||
"-au", "SingleOrg",
|
||||
"--called-api-url", "\"https://graph.microsoft.com\"",
|
||||
"--called-api-scopes", "user.readwrite",
|
||||
"--domain", "my-domain",
|
||||
"--tenant-id", "tenantId",
|
||||
"--client-id", "clientId",
|
||||
"--default-scope", "full",
|
||||
"--app-id-uri", "ApiUri",
|
||||
"--api-client-id", "1234123413241324"),
|
||||
new TemplateInstance(
|
||||
"blazorwasmstandaloneaadb2c",
|
||||
"-au", "IndividualB2C",
|
||||
|
|
|
|||
|
|
@ -17,14 +17,15 @@
|
|||
<!--#endif -->
|
||||
<!--#if (IndividualAuth || OrganizationalAuth) -->
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.AzureAD.UI" Version="${MicrosoftAspNetCoreAuthenticationAzureADUIPackageVersion}" Condition="'$(OrganizationalAuth)' == 'True'" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.AzureADB2C.UI" Version="${MicrosoftAspNetCoreAuthenticationAzureADB2CUIPackageVersion}" Condition="'$(IndividualB2CAuth)' == 'True'" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="${MicrosoftAspNetCoreDiagnosticsEntityFrameworkCorePackageVersion}" Condition=" '$(IndividualLocalAuth)' == 'True' " />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="${MicrosoftAspNetCoreIdentityEntityFrameworkCorePackageVersion}" Condition=" '$(IndividualLocalAuth)' == 'True' " />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="${MicrosoftAspNetCoreIdentityUIPackageVersion}" Condition=" '$(IndividualLocalAuth)' == 'True' " />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="${MicrosoftEntityFrameworkCoreSqlServerPackageVersion}" Condition=" '$(IndividualLocalAuth)' == 'True' AND '$(UseLocalDB)' == 'True'" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="${MicrosoftEntityFrameworkCoreSqlitePackageVersion}" Condition=" '$(IndividualLocalAuth)' == 'True' AND '$(UseLocalDB)' != 'True'" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="${MicrosoftEntityFrameworkCoreToolsPackageVersion}" Condition=" '$(IndividualLocalAuth)' == 'True' " />
|
||||
<PackageReference Include="Microsoft.Identity.Web" Version="${MicrosoftIdentityWebPackageVersion}" Condition=" '$(IndividualB2CAuth)' == 'True' OR '$(OrganizationalAuth)' == 'True'" />
|
||||
<PackageReference Include="Microsoft.Identity.Web.UI" Version="${MicrosoftIdentityWebUIPackageVersion}" Condition=" '$(IndividualB2CAuth)' == 'True' OR '$(OrganizationalAuth)' == 'True'" />
|
||||
<PackageReference Include="Microsoft.Graph" Version="${MicrosoftGraphPackageVersion}" Condition=" '$(GenerateGraph)' == 'True' "/>
|
||||
</ItemGroup>
|
||||
|
||||
<!--#endif -->
|
||||
|
|
|
|||
|
|
@ -38,8 +38,9 @@
|
|||
<!--#endif -->
|
||||
<!--#if (OrganizationalAuth || IndividualB2CAuth) -->
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.AzureAD.UI" Version="${MicrosoftAspNetCoreAuthenticationAzureADUIPackageVersion}" Condition="'$(OrganizationalAuth)' == 'True'" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.AzureADB2C.UI" Version="${MicrosoftAspNetCoreAuthenticationAzureADB2CUIPackageVersion}" Condition="'$(IndividualB2CAuth)' == 'True'" />
|
||||
<PackageReference Include="Microsoft.Identity.Web" Version="${MicrosoftIdentityWebPackageVersion}" />
|
||||
<PackageReference Include="Microsoft.Identity.Web.UI" Version="${MicrosoftIdentityWebUIPackageVersion}" />
|
||||
<PackageReference Include="Microsoft.Graph" Version="${MicrosoftGraphPackageVersion}" Condition=" '$(GenerateGraph)' == 'True' "/>
|
||||
</ItemGroup>
|
||||
<!--#endif -->
|
||||
|
||||
|
|
|
|||
|
|
@ -67,6 +67,18 @@
|
|||
"NoHttps": {
|
||||
"longName": "no-https",
|
||||
"shortName": ""
|
||||
},
|
||||
"CalledApiUrl": {
|
||||
"longName": "called-api-url",
|
||||
"shortName": ""
|
||||
},
|
||||
"CalledApiScopes": {
|
||||
"longName": "called-api-scopes",
|
||||
"shortName": ""
|
||||
},
|
||||
"CallsMicrosoftGraph": {
|
||||
"longName": "calls-graph",
|
||||
"shortName": ""
|
||||
}
|
||||
},
|
||||
"usageExamples": [
|
||||
|
|
|
|||
|
|
@ -127,6 +127,52 @@
|
|||
"Shared/LoginDisplay.IndividualB2CAuth.razor",
|
||||
"Shared/LoginDisplay.OrganizationalAuth.razor"
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": "(!GenerateApi)",
|
||||
"exclude": [
|
||||
"Services/DownstreamWebApi.cs",
|
||||
"Pages/CallWebApi.razor"
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": "(!GenerateGraph)",
|
||||
"exclude": [
|
||||
"Services/MicrosoftGraphServiceExtensions.cs",
|
||||
"Services/TokenAcquisitionCredentialProvider.cs",
|
||||
"Shared/NavMenu.CallsMicrosoftGraph.razor",
|
||||
"Pages/ShowProfile.razor"
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": "(!GenerateApiOrGraph)",
|
||||
"rename": {
|
||||
"Shared/NavMenu.NoGraphOrApi.razor": "Shared/NavMenu.razor"
|
||||
},
|
||||
"exclude": [
|
||||
"Shared/NavMenu.CallsMicrosoftGraph.razor",
|
||||
"Shared/NavMenu.CallsWebApi.razor"
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": "(GenerateGraph)",
|
||||
"rename": {
|
||||
"Shared/NavMenu.CallsMicrosoftGraph.razor": "Shared/NavMenu.razor"
|
||||
},
|
||||
"exclude": [
|
||||
"Shared/NavMenu.NoGraphOrApi.razor",
|
||||
"Shared/NavMenu.CallsWebApi.razor"
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": "(GenerateApi)",
|
||||
"rename": {
|
||||
"Shared/NavMenu.CallsWebApi.razor": "Shared/NavMenu.razor"
|
||||
},
|
||||
"exclude": [
|
||||
"Shared/NavMenu.NoGraphOrApi.razor",
|
||||
"Shared/NavMenu.CallsMicrosoftGraph.razor"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -174,21 +220,28 @@
|
|||
"SignUpSignInPolicyId": {
|
||||
"type": "parameter",
|
||||
"datatype": "string",
|
||||
"defaultValue": "",
|
||||
"defaultValue": "b2c_1_susi",
|
||||
"replaces": "MySignUpSignInPolicyId",
|
||||
"description": "The sign-in and sign-up policy ID for this project (use with IndividualB2C auth)."
|
||||
},
|
||||
"SignedOutCallbackPath": {
|
||||
"type": "parameter",
|
||||
"datatype": "string",
|
||||
"defaultValue": "/signout/B2C_1_susi",
|
||||
"replaces": "/signout/MySignUpSignInPolicyId",
|
||||
"description": "The global signout callback (use with IndividualB2C auth)."
|
||||
},
|
||||
"ResetPasswordPolicyId": {
|
||||
"type": "parameter",
|
||||
"datatype": "string",
|
||||
"defaultValue": "",
|
||||
"defaultValue": "b2c_1_reset",
|
||||
"replaces": "MyResetPasswordPolicyId",
|
||||
"description": "The reset password policy ID for this project (use with IndividualB2C auth)."
|
||||
},
|
||||
"EditProfilePolicyId": {
|
||||
"type": "parameter",
|
||||
"datatype": "string",
|
||||
"defaultValue": "",
|
||||
"defaultValue": "b2c_1_edit_profile",
|
||||
"replaces": "MyEditProfilePolicyId",
|
||||
"description": "The edit profile policy ID for this project (use with IndividualB2C auth)."
|
||||
},
|
||||
|
|
@ -352,6 +405,37 @@
|
|||
"format": "yyyy"
|
||||
}
|
||||
},
|
||||
"CalledApiUrl": {
|
||||
"type": "parameter",
|
||||
"datatype": "string",
|
||||
"replaces": "[WebApiUrl]",
|
||||
"defaultValue" : "https://graph.microsoft.com/beta",
|
||||
"description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified."
|
||||
},
|
||||
"CallsMicrosoftGraph": {
|
||||
"type": "parameter",
|
||||
"datatype": "bool",
|
||||
"defaultValue": "false",
|
||||
"description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified."
|
||||
},
|
||||
"CalledApiScopes": {
|
||||
"type": "parameter",
|
||||
"datatype": "string",
|
||||
"replaces" : "user.read",
|
||||
"description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified."
|
||||
},
|
||||
"GenerateApi": {
|
||||
"type": "computed",
|
||||
"value": "((IndividualB2CAuth || OrganizationalAuth) && (CalledApiUrl != \"https://graph.microsoft.com/beta\" || CalledApiScopes != \"user.read\"))"
|
||||
},
|
||||
"GenerateGraph": {
|
||||
"type": "computed",
|
||||
"value": "(OrganizationalAuth && CallsMicrosoftGraph)"
|
||||
},
|
||||
"GenerateApiOrGraph": {
|
||||
"type": "computed",
|
||||
"value": "(GenerateApi || GenerateGraph)"
|
||||
},
|
||||
"skipRestore": {
|
||||
"type": "parameter",
|
||||
"datatype": "bool",
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@
|
|||
@if (SignInManager.IsSignedIn(User))
|
||||
{
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Manage/Index" title="Manage">Hello @User.Identity.Name!</a>
|
||||
<a class="nav-link text-dark" asp-area="MicrosoftIdentity" asp-page="/Account/Manage/Index" title="Manage">Hello @User.Identity.Name!</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<form class="form-inline" asp-area="Identity" asp-page="/Account/Logout" asp-route-returnUrl="/" method="post">
|
||||
<form class="form-inline" asp-area="MicrosoftIdentity" asp-page="/Account/Logout" asp-route-returnUrl="/" method="post">
|
||||
<button type="submit" class="nav-link btn btn-link text-dark">Logout</button>
|
||||
</form>
|
||||
</li>
|
||||
|
|
@ -18,10 +18,10 @@
|
|||
else
|
||||
{
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Register">Register</a>
|
||||
<a class="nav-link text-dark" asp-area="MicrosoftIdentity" asp-page="/Account/Register">Register</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Login">Login</a>
|
||||
<a class="nav-link text-dark" asp-area="MicrosoftIdentity" asp-page="/Account/Login">Login</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
@page "/callwebapi"
|
||||
|
||||
@using BlazorServerWeb_CSharp
|
||||
@using Microsoft.Identity.Web
|
||||
|
||||
@inject IDownstreamWebApi downstreamAPI
|
||||
@inject MicrosoftIdentityConsentAndConditionalAccessHandler ConsentHandler
|
||||
|
||||
<h1>Call an API</h1>
|
||||
|
||||
<p>This component demonstrates fetching data from a Web API.</p>
|
||||
|
||||
@if (apiResult == null)
|
||||
{
|
||||
<p><em>Loading...</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<h2>API Result</h2>
|
||||
@apiResult
|
||||
}
|
||||
|
||||
@code {
|
||||
private string apiResult;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
apiResult = await downstreamAPI.CallWebApiAsync("me");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ConsentHandler.HandleException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
@page "/showprofile"
|
||||
|
||||
@using Microsoft.Identity.Web
|
||||
@using Microsoft.Graph
|
||||
@inject Microsoft.Graph.GraphServiceClient GraphServiceClient
|
||||
@inject MicrosoftIdentityConsentAndConditionalAccessHandler ConsentHandler
|
||||
|
||||
<h1>Me</h1>
|
||||
|
||||
<p>This component demonstrates fetching data from a service.</p>
|
||||
|
||||
@if (user == null)
|
||||
{
|
||||
<p><em>Loading...</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<table class="table table-striped table-condensed" style="font-family: monospace">
|
||||
<tr>
|
||||
<th>Property</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Name</td>
|
||||
<td>@user.DisplayName</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Photo</td>
|
||||
<td>
|
||||
@{
|
||||
if (photo != null)
|
||||
{
|
||||
<img style="margin: 5px 0; width: 150px" src="data:image/jpeg;base64, @photo" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<h3>NO PHOTO</h3>
|
||||
<p>Check user profile in Azure Active Directory to add a photo.</p>
|
||||
}
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
}
|
||||
|
||||
@code {
|
||||
User user;
|
||||
string photo;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
user = await GraphServiceClient.Me.Request().GetAsync();
|
||||
photo = await GetPhoto();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ConsentHandler.HandleException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task<string> GetPhoto()
|
||||
{
|
||||
string photo;
|
||||
|
||||
try
|
||||
{
|
||||
using (var photoStream = await GraphServiceClient.Me.Photo.Content.Request().GetAsync())
|
||||
{
|
||||
byte[] photoByte = ((System.IO.MemoryStream)photoStream).ToArray();
|
||||
photo = Convert.ToBase64String(photoByte);
|
||||
this.StateHasChanged();
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
photo = null;
|
||||
}
|
||||
return photo;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,9 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Identity.Web;
|
||||
|
||||
namespace BlazorServerWeb_CSharp
|
||||
{
|
||||
public interface IDownstreamWebApi
|
||||
{
|
||||
Task<string> CallWebApiAsync(string relativeEndpoint = "", string[] requiredScopes = null);
|
||||
}
|
||||
|
||||
public static class DownstreamWebApiExtensions
|
||||
{
|
||||
public static void AddDownstreamWebApiService(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
// https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests
|
||||
services.AddHttpClient<IDownstreamWebApi, DownstreamWebApi>();
|
||||
}
|
||||
}
|
||||
|
||||
public class DownstreamWebApi : IDownstreamWebApi
|
||||
{
|
||||
private readonly ITokenAcquisition _tokenAcquisition;
|
||||
|
||||
private readonly IConfiguration _configuration;
|
||||
|
||||
private readonly HttpClient _httpClient;
|
||||
|
||||
public DownstreamWebApi(
|
||||
ITokenAcquisition tokenAcquisition,
|
||||
IConfiguration configuration,
|
||||
HttpClient httpClient)
|
||||
{
|
||||
_tokenAcquisition = tokenAcquisition;
|
||||
_configuration = configuration;
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls the Web API with the required scopes
|
||||
/// </summary>
|
||||
/// <param name="requireScopes">[Optional] Scopes required to call the Web API. If
|
||||
/// not specified, uses scopes from the configuration</param>
|
||||
/// <param name="relativeEndpoint">Endpoint relative to the CalledApiUrl configuration</param>
|
||||
/// <returns>A JSON string representing the result of calling the Web API</returns>
|
||||
public async Task<string> CallWebApiAsync(string relativeEndpoint = "", string[] requiredScopes = null)
|
||||
{
|
||||
string[] scopes = requiredScopes ?? _configuration["CalledApi:CalledApiScopes"]?.Split(' ');
|
||||
string apiUrl = (_configuration["CalledApi:CalledApiUrl"] as string)?.TrimEnd('/') + $"/{relativeEndpoint}";
|
||||
|
||||
string accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(scopes);
|
||||
HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, apiUrl);
|
||||
httpRequestMessage.Headers.Add("Authorization", $"bearer {accessToken}");
|
||||
|
||||
string apiResult;
|
||||
var response = await _httpClient.SendAsync(httpRequestMessage);
|
||||
if (response.StatusCode == HttpStatusCode.OK)
|
||||
{
|
||||
apiResult = await response.Content.ReadAsStringAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
apiResult = $"Error calling the API '{apiUrl}'";
|
||||
}
|
||||
|
||||
return apiResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Graph;
|
||||
using Microsoft.Identity.Web;
|
||||
|
||||
namespace BlazorServerWeb_CSharp
|
||||
{
|
||||
public static class MicrosoftGraphServiceExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds the Microsoft Graph client as a singleton.
|
||||
/// </summary>
|
||||
/// <param name="services">Service collection.</param>
|
||||
/// <param name="initialScopes">Initial scopes.</param>
|
||||
/// <param name="graphBaseUrl">Base URL for Microsoft graph. This can be
|
||||
/// changed for instance for applications running in national clouds</param>
|
||||
public static IServiceCollection AddMicrosoftGraph(this IServiceCollection services,
|
||||
IEnumerable<string> initialScopes,
|
||||
string graphBaseUrl = "https://graph.microsoft.com/v1.0")
|
||||
{
|
||||
services.AddTokenAcquisition(true);
|
||||
services.AddSingleton<GraphServiceClient, GraphServiceClient>(serviceProvider =>
|
||||
{
|
||||
var tokenAquisitionService = serviceProvider.GetService<ITokenAcquisition>();
|
||||
GraphServiceClient client = string.IsNullOrWhiteSpace(graphBaseUrl) ?
|
||||
new GraphServiceClient(new TokenAcquisitionCredentialProvider(tokenAquisitionService, initialScopes)) :
|
||||
new GraphServiceClient(graphBaseUrl, new TokenAcquisitionCredentialProvider(tokenAquisitionService, initialScopes));
|
||||
return client;
|
||||
});
|
||||
return services;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
using Microsoft.Graph;
|
||||
using Microsoft.Identity.Web;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BlazorServerWeb_CSharp
|
||||
{
|
||||
internal class TokenAcquisitionCredentialProvider : IAuthenticationProvider
|
||||
{
|
||||
public TokenAcquisitionCredentialProvider(ITokenAcquisition tokenAcquisition, IEnumerable<string> initialScopes)
|
||||
{
|
||||
_tokenAcquisition = tokenAcquisition;
|
||||
_initialScopes = initialScopes;
|
||||
}
|
||||
|
||||
ITokenAcquisition _tokenAcquisition;
|
||||
IEnumerable<string> _initialScopes;
|
||||
|
||||
public async Task AuthenticateRequestAsync(HttpRequestMessage request)
|
||||
{
|
||||
request.Headers.Add("Authorization",
|
||||
$"Bearer {await _tokenAcquisition.GetAccessTokenForUserAsync(_initialScopes)}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +1,21 @@
|
|||
@using Microsoft.AspNetCore.Authentication.AzureADB2C.UI
|
||||
@using Microsoft.Identity.Web
|
||||
@using Microsoft.Extensions.Options
|
||||
@inject IOptionsMonitor<AzureADB2COptions> AzureADB2COptions
|
||||
@inject IOptionsMonitor<MicrosoftIdentityOptions> microsoftIdentityOptions
|
||||
|
||||
<AuthorizeView>
|
||||
<Authorized>
|
||||
@if (canEditProfile)
|
||||
{
|
||||
<a href="AzureADB2C/Account/EditProfile">Hello, @context.User.Identity.Name!</a>
|
||||
<a href="MicrosoftIdentity/Account/EditProfile">Hello, @context.User.Identity.Name!</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<text>Hello, @context.User.Identity.Name!</text>
|
||||
}
|
||||
<a href="AzureADB2C/Account/SignOut">Log out</a>
|
||||
<a href="MicrosoftIdentity/Account/SignOut">Log out</a>
|
||||
</Authorized>
|
||||
<NotAuthorized>
|
||||
<a href="AzureADB2C/Account/SignIn">Log in</a>
|
||||
<a href="MicrosoftIdentity/Account/SignIn">Log in</a>
|
||||
</NotAuthorized>
|
||||
</AuthorizeView>
|
||||
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
var options = AzureADB2COptions.Get(AzureADB2CDefaults.AuthenticationScheme);
|
||||
var options = microsoftIdentityOptions.CurrentValue;
|
||||
canEditProfile = !string.IsNullOrEmpty(options.EditProfilePolicyId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<AuthorizeView>
|
||||
<Authorized>
|
||||
Hello, @context.User.Identity.Name!
|
||||
<a href="AzureAD/Account/SignOut">Log out</a>
|
||||
<a href="MicrosoftIdentity/Account/SignOut">Log out</a>
|
||||
</Authorized>
|
||||
<NotAuthorized>
|
||||
<a href="AzureAD/Account/SignIn">Log in</a>
|
||||
<a href="MicrosoftIdentity/Account/SignIn">Log in</a>
|
||||
</NotAuthorized>
|
||||
</AuthorizeView>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
<div class="top-row pl-4 navbar navbar-dark">
|
||||
<a class="navbar-brand" href="">BlazorServerWeb-CSharp</a>
|
||||
<button class="navbar-toggler" @onclick="ToggleNavMenu">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
|
||||
<ul class="nav flex-column">
|
||||
<li class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
|
||||
<span class="oi oi-home" aria-hidden="true"></span> Home
|
||||
</NavLink>
|
||||
</li>
|
||||
<li class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="counter">
|
||||
<span class="oi oi-plus" aria-hidden="true"></span> Counter
|
||||
</NavLink>
|
||||
</li>
|
||||
<li class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="fetchdata">
|
||||
<span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
|
||||
</NavLink>
|
||||
</li>
|
||||
<li class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="showprofile">
|
||||
<span class="oi oi-list-rich" aria-hidden="true"></span> Show profile
|
||||
</NavLink>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private bool collapseNavMenu = true;
|
||||
|
||||
private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;
|
||||
|
||||
private void ToggleNavMenu()
|
||||
{
|
||||
collapseNavMenu = !collapseNavMenu;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
<div class="top-row pl-4 navbar navbar-dark">
|
||||
<a class="navbar-brand" href="">BlazorServerWeb-CSharp</a>
|
||||
<button class="navbar-toggler" @onclick="ToggleNavMenu">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
|
||||
<ul class="nav flex-column">
|
||||
<li class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
|
||||
<span class="oi oi-home" aria-hidden="true"></span> Home
|
||||
</NavLink>
|
||||
</li>
|
||||
<li class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="counter">
|
||||
<span class="oi oi-plus" aria-hidden="true"></span> Counter
|
||||
</NavLink>
|
||||
</li>
|
||||
<li class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="fetchdata">
|
||||
<span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
|
||||
</NavLink>
|
||||
</li>
|
||||
<li class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="callwebapi">
|
||||
<span class="oi oi-list-rich" aria-hidden="true"></span> Call Web API
|
||||
</NavLink>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private bool collapseNavMenu = true;
|
||||
|
||||
private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;
|
||||
|
||||
private void ToggleNavMenu()
|
||||
{
|
||||
collapseNavMenu = !collapseNavMenu;
|
||||
}
|
||||
}
|
||||
|
|
@ -4,17 +4,16 @@ using System.Linq;
|
|||
using System.Threading.Tasks;
|
||||
#if (OrganizationalAuth || IndividualB2CAuth)
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.Identity.Web;
|
||||
using Microsoft.Identity.Web.UI;
|
||||
using Microsoft.Identity.Web.TokenCacheProviders.InMemory;
|
||||
#endif
|
||||
#if (OrganizationalAuth)
|
||||
using Microsoft.AspNetCore.Authentication.AzureAD.UI;
|
||||
#if (MultiOrgAuth)
|
||||
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
|
||||
#endif
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
#endif
|
||||
#if (IndividualB2CAuth)
|
||||
using Microsoft.AspNetCore.Authentication.AzureADB2C.UI;
|
||||
#endif
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
#if (IndividualLocalAuth)
|
||||
|
|
@ -42,6 +41,9 @@ using Microsoft.IdentityModel.Tokens;
|
|||
using BlazorServerWeb_CSharp.Areas.Identity;
|
||||
#endif
|
||||
using BlazorServerWeb_CSharp.Data;
|
||||
#if (GenerateGraph)
|
||||
using Microsoft.Graph;
|
||||
#endif
|
||||
|
||||
namespace BlazorServerWeb_CSharp
|
||||
{
|
||||
|
|
@ -70,59 +72,39 @@ namespace BlazorServerWeb_CSharp
|
|||
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
|
||||
.AddEntityFrameworkStores<ApplicationDbContext>();
|
||||
#elif (OrganizationalAuth)
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
|
||||
.AddAzureAD(options => Configuration.Bind("AzureAd", options));
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
#if (MultiOrgAuth)
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
{
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
// Instead of using the default validation (validating against a single issuer value, as we do in
|
||||
// line of business apps), we inject our own multitenant validation logic
|
||||
ValidateIssuer = false,
|
||||
|
||||
// If the app is meant to be accessed by entire organizations, add your issuer validation logic here.
|
||||
//IssuerValidator = (issuer, securityToken, validationParameters) => {
|
||||
// if (myIssuerValidationLogic(issuer)) return issuer;
|
||||
//}
|
||||
};
|
||||
|
||||
options.Events = new OpenIdConnectEvents
|
||||
{
|
||||
OnTicketReceived = context =>
|
||||
{
|
||||
// If your authentication logic is based on users then add your logic here
|
||||
return Task.CompletedTask;
|
||||
},
|
||||
OnAuthenticationFailed = context =>
|
||||
{
|
||||
context.Response.Redirect("/Error");
|
||||
context.HandleResponse(); // Suppress the exception
|
||||
return Task.CompletedTask;
|
||||
},
|
||||
// If your application needs to authenticate single users, add your user validation below.
|
||||
//OnTokenValidated = context =>
|
||||
//{
|
||||
// return myUserValidationLogic(context.Ticket.Principal);
|
||||
//}
|
||||
};
|
||||
});
|
||||
#if (GenerateApiOrGraph)
|
||||
string[] scopes = Configuration.GetValue<string>("CalledApi:CalledApiScopes")?.Split(' ');
|
||||
#endif
|
||||
#if (GenerateApiOrGraph)
|
||||
services.AddMicrosoftWebAppAuthentication(Configuration, "AzureAd")
|
||||
.AddMicrosoftWebAppCallsWebApi(Configuration, scopes, "AzureAd")
|
||||
.AddInMemoryTokenCaches();
|
||||
#else
|
||||
services.AddMicrosoftWebAppAuthentication(Configuration, "AzureAd");
|
||||
#endif
|
||||
#if (GenerateApi)
|
||||
services.AddDownstreamWebApiService(Configuration);
|
||||
#endif
|
||||
#if (GenerateGraph)
|
||||
services.AddMicrosoftGraph(scopes, Configuration.GetValue<string>("CalledApi:CalledApiUrl"));
|
||||
#endif
|
||||
|
||||
#elif (IndividualB2CAuth)
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
services.AddAuthentication(AzureADB2CDefaults.AuthenticationScheme)
|
||||
.AddAzureADB2C(options => Configuration.Bind("AzureAdB2C", options));
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
|
||||
#if (GenerateApi)
|
||||
string[] scopes = Configuration.GetValue<string>("CalledApi:CalledApiScopes")?.Split(' ');
|
||||
#endif
|
||||
#if (OrganizationalAuth)
|
||||
services.AddControllersWithViews();
|
||||
#if (GenerateApi)
|
||||
services.AddMicrosoftWebAppAuthentication(Configuration, "AzureAdB2C")
|
||||
.AddMicrosoftWebAppCallsWebApi(Configuration, scopes, "AzureAdB2C")
|
||||
.AddInMemoryTokenCaches();
|
||||
|
||||
services.AddDownstreamWebApiService(Configuration);
|
||||
#else
|
||||
services.AddMicrosoftWebAppAuthentication(Configuration, "AzureAdB2C");
|
||||
#endif
|
||||
#endif
|
||||
#if (OrganizationalAuth || IndividualB2CAuth)
|
||||
services.AddControllersWithViews()
|
||||
.AddMicrosoftIdentityUI();
|
||||
|
||||
services.AddAuthorization(options =>
|
||||
{
|
||||
|
|
@ -132,7 +114,12 @@ namespace BlazorServerWeb_CSharp
|
|||
|
||||
#endif
|
||||
services.AddRazorPages();
|
||||
#if (OrganizationalAuth || IndividualB2CAuth)
|
||||
services.AddServerSideBlazor()
|
||||
.AddMicrosoftIdentityConsentHandler();
|
||||
#else
|
||||
services.AddServerSideBlazor();
|
||||
#endif
|
||||
#if (IndividualLocalAuth)
|
||||
services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<IdentityUser>>();
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -5,6 +5,12 @@
|
|||
// "ClientId": "11111111-1111-1111-11111111111111111",
|
||||
// "CallbackPath": "/signin-oidc",
|
||||
// "Domain": "qualified.domain.name",
|
||||
// "SignedOutCallbackPath": "/signout/MySignUpSignInPolicyId",
|
||||
//#if (GenerateApi)
|
||||
// "ClientSecret": "secret-from-app-registration",
|
||||
// "ClientCertificates" : [
|
||||
// ],
|
||||
//#endif
|
||||
// "SignUpSignInPolicyId": "MySignUpSignInPolicyId",
|
||||
// "ResetPasswordPolicyId": "MyResetPasswordPolicyId",
|
||||
// "EditProfilePolicyId": "MyEditProfilePolicyId"
|
||||
|
|
@ -19,18 +25,36 @@
|
|||
// "TenantId": "22222222-2222-2222-2222-222222222222",
|
||||
//#endif
|
||||
// "ClientId": "11111111-1111-1111-11111111111111111",
|
||||
//#if (GenerateApiOrGraph)
|
||||
// "ClientSecret": "secret-from-app-registration",
|
||||
// "ClientCertificates" : [
|
||||
// ],
|
||||
//#endif
|
||||
// "CallbackPath": "/signin-oidc"
|
||||
// },
|
||||
//#endif
|
||||
////#endif
|
||||
////#if (GenerateApiOrGraph)
|
||||
// "CalledApi": {
|
||||
// /*
|
||||
// 'CalledApiScopes' contains space separated scopes of the Web API you want to call. This can be:
|
||||
// - a scope for a V2 application (for instance api://b3682cc7-8b30-4bd2-aaba-080c6bf0fd31/access_as_user)
|
||||
// - a scope corresponding to a V1 application (for instance <App ID URI>/.default, where <App ID URI> is the
|
||||
// App ID URI of a legacy v1 Web application
|
||||
// Applications are registered in the https://portal.azure.com portal.
|
||||
// */
|
||||
// "CalledApiScopes": "user.read",
|
||||
// "CalledApiUrl": "[WebApiUrl]"
|
||||
// },
|
||||
////#endif
|
||||
////#if (IndividualLocalAuth)
|
||||
// "ConnectionStrings": {
|
||||
////#if (UseLocalDB)
|
||||
//#if (UseLocalDB)
|
||||
// "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-BlazorServerWeb-CSharp-53bc9b9d-9d6a-45d4-8429-2a2761773502;Trusted_Connection=True;MultipleActiveResultSets=true"
|
||||
////#else
|
||||
//#else
|
||||
// "DefaultConnection": "DataSource=app.db;Cache=Shared"
|
||||
//#endif
|
||||
// },
|
||||
//#endif
|
||||
////#endif
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
|
|
|
|||
|
|
@ -77,6 +77,18 @@
|
|||
"NoHttps": {
|
||||
"longName": "no-https",
|
||||
"shortName": ""
|
||||
},
|
||||
"CalledApiUrl": {
|
||||
"longName": "called-api-url",
|
||||
"shortName": ""
|
||||
},
|
||||
"CalledApiScopes": {
|
||||
"longName": "called-api-scopes",
|
||||
"shortName": ""
|
||||
},
|
||||
"CallsMicrosoftGraph": {
|
||||
"longName": "calls-graph",
|
||||
"shortName": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -211,6 +211,19 @@
|
|||
"Server/Controllers/OidcConfigurationController.cs",
|
||||
"Server/Models/ApplicationUser.cs"
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": "(Hosted && !GenerateApi)",
|
||||
"exclude": [
|
||||
"Server/Services/DownstreamWebApi.cs"
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": "(Hosted &&!GenerateGraph)",
|
||||
"exclude": [
|
||||
"Server/Services/MicrosoftGraphServiceExtensions.cs",
|
||||
"Server/Services/TokenAcquisitionCredentialProvider.cs"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -297,7 +310,7 @@
|
|||
"datatype": "string",
|
||||
"defaultValue": "https://login.microsoftonline.com/",
|
||||
"replaces": "https:////login.microsoftonline.com/",
|
||||
"description": "The Azure Active Directory instance to connect to (use with SingleOrg)."
|
||||
"description": "The Azure Active Directory instance to connect to (use with SingleOrg auth)."
|
||||
},
|
||||
"ClientId": {
|
||||
"type": "parameter",
|
||||
|
|
@ -452,6 +465,37 @@
|
|||
"parameters": {
|
||||
"format": "yyyy"
|
||||
}
|
||||
},
|
||||
"CalledApiUrl": {
|
||||
"type": "parameter",
|
||||
"datatype": "string",
|
||||
"replaces": "[WebApiUrl]",
|
||||
"defaultValue" : "https://graph.microsoft.com/v1.0/me",
|
||||
"description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified."
|
||||
},
|
||||
"CallsMicrosoftGraph": {
|
||||
"type": "parameter",
|
||||
"datatype": "bool",
|
||||
"defaultValue": "false",
|
||||
"description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified."
|
||||
},
|
||||
"CalledApiScopes": {
|
||||
"type": "parameter",
|
||||
"datatype": "string",
|
||||
"replaces" : "user.read",
|
||||
"description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified."
|
||||
},
|
||||
"GenerateApi": {
|
||||
"type": "computed",
|
||||
"value": "(( (IndividualB2CAuth && !Hosted) || OrganizationalAuth) && (CalledApiUrl != \"https://graph.microsoft.com/v1.0/me\" || CalledApiScopes != \"user.read\"))"
|
||||
},
|
||||
"GenerateGraph": {
|
||||
"type": "computed",
|
||||
"value": "(OrganizationalAuth && CallsMicrosoftGraph)"
|
||||
},
|
||||
"GenerateApiOrGraph": {
|
||||
"type": "computed",
|
||||
"value": "(GenerateApi || GenerateGraph)"
|
||||
}
|
||||
},
|
||||
"tags": {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,25 @@
|
|||
using ComponentsWebAssembly_CSharp.Shared;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
#if (!NoAuth)
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
#endif
|
||||
#if (GenerateApi)
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Identity.Web;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
#endif
|
||||
#if (GenerateGraph)
|
||||
using Microsoft.Graph;
|
||||
#endif
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
#if (OrganizationalAuth || IndividualB2CAuth)
|
||||
using Microsoft.Identity.Web.Resource;
|
||||
#endif
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ComponentsWebAssembly_CSharp.Shared;
|
||||
|
||||
namespace ComponentsWebAssembly_CSharp.Server.Controllers
|
||||
{
|
||||
|
|
@ -23,16 +35,28 @@ namespace ComponentsWebAssembly_CSharp.Server.Controllers
|
|||
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
|
||||
};
|
||||
|
||||
private readonly ILogger<WeatherForecastController> logger;
|
||||
private readonly ILogger<WeatherForecastController> _logger;
|
||||
|
||||
public WeatherForecastController(ILogger<WeatherForecastController> logger)
|
||||
// The Web API will only accept tokens 1) for users, and 2) having the access_as_user scope for this API
|
||||
static readonly string[] scopeRequiredByApi = new string[] { "access_as_user" };
|
||||
|
||||
#if (GenerateApi)
|
||||
private readonly IDownstreamWebApi _downstreamWebApi;
|
||||
|
||||
public WeatherForecastController(ILogger<WeatherForecastController> logger,
|
||||
IDownstreamWebApi downstreamWebApi)
|
||||
{
|
||||
this.logger = logger;
|
||||
_logger = logger;
|
||||
_downstreamWebApi = downstreamWebApi;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IEnumerable<WeatherForecast> Get()
|
||||
public async Task<IEnumerable<WeatherForecast>> Get()
|
||||
{
|
||||
HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);
|
||||
|
||||
string downstreamApiResult = await _downstreamWebApi.CallWebApiAsync();
|
||||
|
||||
var rng = new Random();
|
||||
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
|
||||
{
|
||||
|
|
@ -42,5 +66,54 @@ namespace ComponentsWebAssembly_CSharp.Server.Controllers
|
|||
})
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
#elseif (GenerateGraph)
|
||||
private readonly GraphServiceClient _graphServiceClient;
|
||||
|
||||
public WeatherForecastController(ILogger<WeatherForecastController> logger,
|
||||
GraphServiceClient graphServiceClient)
|
||||
{
|
||||
_logger = logger;
|
||||
_graphServiceClient = graphServiceClient;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IEnumerable<WeatherForecast>> Get()
|
||||
{
|
||||
HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);
|
||||
var user = await _graphServiceClient.Me.Request().GetAsync();
|
||||
|
||||
var rng = new Random();
|
||||
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
|
||||
{
|
||||
Date = DateTime.Now.AddDays(index),
|
||||
TemperatureC = rng.Next(-20, 55),
|
||||
Summary = Summaries[rng.Next(Summaries.Length)]
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
#else
|
||||
public WeatherForecastController(ILogger<WeatherForecastController> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IEnumerable<WeatherForecast> Get()
|
||||
{
|
||||
#if (OrganizationalAuth || IndividualB2CAuth)
|
||||
HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);
|
||||
|
||||
#endif
|
||||
var rng = new Random();
|
||||
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
|
||||
{
|
||||
Date = DateTime.Now.AddDays(index),
|
||||
TemperatureC = rng.Next(-20, 55),
|
||||
Summary = Summaries[rng.Next(Summaries.Length)]
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Identity.Web;
|
||||
|
||||
namespace ComponentsWebAssembly_CSharp.Server
|
||||
{
|
||||
public interface IDownstreamWebApi
|
||||
{
|
||||
Task<string> CallWebApiAsync(string relativeEndpoint = "", string[] requiredScopes = null);
|
||||
}
|
||||
|
||||
public static class DownstreamWebApiExtensions
|
||||
{
|
||||
public static void AddDownstreamWebApiService(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
// https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests
|
||||
services.AddHttpClient<IDownstreamWebApi, DownstreamWebApi>();
|
||||
}
|
||||
}
|
||||
|
||||
public class DownstreamWebApi : IDownstreamWebApi
|
||||
{
|
||||
private readonly ITokenAcquisition _tokenAcquisition;
|
||||
|
||||
private readonly IConfiguration _configuration;
|
||||
|
||||
private readonly HttpClient _httpClient;
|
||||
|
||||
public DownstreamWebApi(
|
||||
ITokenAcquisition tokenAcquisition,
|
||||
IConfiguration configuration,
|
||||
HttpClient httpClient)
|
||||
{
|
||||
_tokenAcquisition = tokenAcquisition;
|
||||
_configuration = configuration;
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls the Web API with the required scopes
|
||||
/// </summary>
|
||||
/// <param name="requireScopes">[Optional] Scopes required to call the Web API. If
|
||||
/// not specified, uses scopes from the configuration</param>
|
||||
/// <param name="relativeEndpoint">Endpoint relative to the CalledApiUrl configuration</param>
|
||||
/// <returns>A JSON string representing the result of calling the Web API</returns>
|
||||
public async Task<string> CallWebApiAsync(string relativeEndpoint = "", string[] requiredScopes = null)
|
||||
{
|
||||
string[] scopes = requiredScopes ?? _configuration["CalledApi:CalledApiScopes"]?.Split(' ');
|
||||
string apiUrl = (_configuration["CalledApi:CalledApiUrl"] as string)?.TrimEnd('/') + $"/{relativeEndpoint}";
|
||||
|
||||
string accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(scopes);
|
||||
HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, apiUrl);
|
||||
httpRequestMessage.Headers.Add("Authorization", $"bearer {accessToken}");
|
||||
|
||||
string apiResult;
|
||||
var response = await _httpClient.SendAsync(httpRequestMessage);
|
||||
if (response.StatusCode == HttpStatusCode.OK)
|
||||
{
|
||||
apiResult = await response.Content.ReadAsStringAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
apiResult = $"Error calling the API '{apiUrl}'";
|
||||
}
|
||||
|
||||
return apiResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Graph;
|
||||
using Microsoft.Identity.Web;
|
||||
|
||||
namespace ComponentsWebAssembly_CSharp.Server
|
||||
{
|
||||
public static class MicrosoftGraphServiceExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds the Microsoft Graph client as a singleton.
|
||||
/// </summary>
|
||||
/// <param name="services">Service collection.</param>
|
||||
/// <param name="initialScopes">Initial scopes.</param>
|
||||
/// <param name="graphBaseUrl">Base URL for Microsoft graph. This can be
|
||||
/// changed for instance for applications running in national clouds</param>
|
||||
public static IServiceCollection AddMicrosoftGraph(this IServiceCollection services,
|
||||
IEnumerable<string> initialScopes,
|
||||
string graphBaseUrl = "https://graph.microsoft.com/v1.0")
|
||||
{
|
||||
services.AddTokenAcquisition(true);
|
||||
services.AddSingleton<GraphServiceClient, GraphServiceClient>(serviceProvider =>
|
||||
{
|
||||
var tokenAquisitionService = serviceProvider.GetService<ITokenAcquisition>();
|
||||
GraphServiceClient client = string.IsNullOrWhiteSpace(graphBaseUrl) ?
|
||||
new GraphServiceClient(new TokenAcquisitionCredentialProvider(tokenAquisitionService, initialScopes)) :
|
||||
new GraphServiceClient(graphBaseUrl, new TokenAcquisitionCredentialProvider(tokenAquisitionService, initialScopes));
|
||||
return client;
|
||||
});
|
||||
return services;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
using Microsoft.Graph;
|
||||
using Microsoft.Identity.Web;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ComponentsWebAssembly_CSharp.Server
|
||||
{
|
||||
internal class TokenAcquisitionCredentialProvider : IAuthenticationProvider
|
||||
{
|
||||
public TokenAcquisitionCredentialProvider(ITokenAcquisition tokenAcquisition, IEnumerable<string> initialScopes)
|
||||
{
|
||||
_tokenAcquisition = tokenAcquisition;
|
||||
_initialScopes = initialScopes;
|
||||
}
|
||||
|
||||
ITokenAcquisition _tokenAcquisition;
|
||||
IEnumerable<string> _initialScopes;
|
||||
|
||||
public async Task AuthenticateRequestAsync(HttpRequestMessage request)
|
||||
{
|
||||
request.Headers.Add("Authorization",
|
||||
$"Bearer {await _tokenAcquisition.GetAccessTokenForUserAsync(_initialScopes)}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +1,10 @@
|
|||
#if (OrganizationalAuth || IndividualB2CAuth || IndividualLocalAuth)
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
#endif
|
||||
#if (OrganizationalAuth)
|
||||
using Microsoft.AspNetCore.Authentication.AzureAD.UI;
|
||||
#endif
|
||||
#if (IndividualB2CAuth)
|
||||
using Microsoft.AspNetCore.Authentication.AzureADB2C.UI;
|
||||
#endif
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
#if (IndividualLocalAuth)
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.UI;
|
||||
#if (OrganizationalAuth || IndividualB2CAuth)
|
||||
using Microsoft.Identity.Web;
|
||||
using Microsoft.Identity.Web.TokenCacheProviders.InMemory;
|
||||
#endif
|
||||
#if (RequiresHttps)
|
||||
using Microsoft.AspNetCore.HttpsPolicy;
|
||||
|
|
@ -29,6 +22,9 @@ using System.Linq;
|
|||
using ComponentsWebAssembly_CSharp.Server.Data;
|
||||
using ComponentsWebAssembly_CSharp.Server.Models;
|
||||
#endif
|
||||
#if (GenerateGraph)
|
||||
using Microsoft.Graph;
|
||||
#endif
|
||||
|
||||
namespace ComponentsWebAssembly_CSharp.Server
|
||||
{
|
||||
|
|
@ -47,13 +43,13 @@ namespace ComponentsWebAssembly_CSharp.Server
|
|||
{
|
||||
#if (IndividualLocalAuth)
|
||||
services.AddDbContext<ApplicationDbContext>(options =>
|
||||
#if (UseLocalDB)
|
||||
#if (UseLocalDB)
|
||||
options.UseSqlServer(
|
||||
Configuration.GetConnectionString("DefaultConnection")));
|
||||
#else
|
||||
#else
|
||||
options.UseSqlite(
|
||||
Configuration.GetConnectionString("DefaultConnection")));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
|
||||
.AddEntityFrameworkStores<ApplicationDbContext>();
|
||||
|
|
@ -65,15 +61,32 @@ namespace ComponentsWebAssembly_CSharp.Server
|
|||
.AddIdentityServerJwt();
|
||||
#endif
|
||||
#if (OrganizationalAuth)
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
|
||||
.AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
#if (GenerateApiOrGraph)
|
||||
// Adds Microsoft Identity platform (AAD v2.0) support to protect this Api
|
||||
services.AddMicrosoftWebApiAuthentication(Configuration, "AzureAd")
|
||||
.AddMicrosoftWebApiCallsWebApi(Configuration, "AzureAd")
|
||||
.AddInMemoryTokenCaches();
|
||||
#else
|
||||
// Adds Microsoft Identity platform (AAD v2.0) support to protect this Api
|
||||
services.AddMicrosoftWebApiAuthentication(Configuration, "AzureAd");
|
||||
#endif
|
||||
#if (GenerateApi)
|
||||
services.AddDownstreamWebApiService(Configuration);
|
||||
#endif
|
||||
#if (GenerateGraph)
|
||||
services.AddMicrosoftGraph(Configuration.GetValue<string>("CalledApi:CalledApiScopes")?.Split(' '),
|
||||
Configuration.GetValue<string>("CalledApi:CalledApiUrl"));
|
||||
#endif
|
||||
#elif (IndividualB2CAuth)
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
services.AddAuthentication(AzureADB2CDefaults.BearerAuthenticationScheme)
|
||||
.AddAzureADB2CBearer(options => Configuration.Bind("AzureAdB2C", options));
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
#if (GenerateApi)
|
||||
services.AddMicrosoftWebApiAuthentication(Configuration, "AzureAdB2C")
|
||||
.AddMicrosoftWebApiCallsWebApi(Configuration, "AzureAdB2C")
|
||||
.AddInMemoryTokenCaches();
|
||||
|
||||
services.AddDownstreamWebApiService(Configuration);
|
||||
#else
|
||||
services.AddMicrosoftWebApiAuthentication(Configuration, "AzureAdB2C");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
services.AddControllersWithViews();
|
||||
|
|
|
|||
|
|
@ -12,23 +12,51 @@
|
|||
// "Instance": "https:////aadB2CInstance.b2clogin.com/",
|
||||
// "ClientId": "11111111-1111-1111-11111111111111111",
|
||||
// "Domain": "qualified.domain.name",
|
||||
//#if (GenerateApi)
|
||||
// "ClientSecret": "secret-from-app-registration",
|
||||
// "ClientCertificates" : [
|
||||
// ],
|
||||
//#endif
|
||||
// "SignUpSignInPolicyId": "MySignUpSignInPolicyId"
|
||||
// },
|
||||
////#elseif (OrganizationalAuth)
|
||||
// "AzureAd": {
|
||||
//#if (!SingleOrgAuth)
|
||||
// "Instance": "https:////login.microsoftonline.com/common",
|
||||
//#else
|
||||
// "Instance": "https:////login.microsoftonline.com/",
|
||||
// "Domain": "qualified.domain.name",
|
||||
// "TenantId": "22222222-2222-2222-2222-222222222222",
|
||||
//#endif
|
||||
// "ClientId": "11111111-1111-1111-11111111111111111",
|
||||
//#if (GenerateApiOrGraph)
|
||||
// "ClientSecret": "secret-from-app-registration",
|
||||
// "ClientCertificates" : [
|
||||
// ],
|
||||
//#endif
|
||||
// "CallbackPath": "/signin-oidc"
|
||||
// },
|
||||
////#endif
|
||||
////#if (GenerateApiOrGraph)
|
||||
// "CalledApi": {
|
||||
// /*
|
||||
// 'CalledApiScopes' contains space separated scopes of the Web API you want to call. This can be:
|
||||
// - a scope for a V2 application (for instance api://b3682cc7-8b30-4bd2-aaba-080c6bf0fd31/access_as_user)
|
||||
// - a scope corresponding to a V1 application (for instance <App ID URI>/.default, where <App ID URI> is the
|
||||
// App ID URI of a legacy v1 Web application
|
||||
// Applications are registered in the https://portal.azure.com portal.
|
||||
// */
|
||||
// "CalledApiScopes": "user.read",
|
||||
// "CalledApiUrl": "[WebApiUrl]"
|
||||
// },
|
||||
////#endif
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
////#if (IndividualLocalAuth)
|
||||
// "IdentityServer": {
|
||||
// "Clients": {
|
||||
|
|
|
|||
|
|
@ -71,13 +71,12 @@ namespace Company.WebApplication1
|
|||
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
|
||||
.AddEntityFrameworkStores<ApplicationDbContext>();
|
||||
#elif (OrganizationalAuth)
|
||||
services.AddMicrosoftWebAppAuthentication(Configuration, "AzureAd")
|
||||
#if (GenerateApiOrGraph)
|
||||
.AddMicrosoftWebAppCallsWebApi(Configuration,
|
||||
"AzureAd")
|
||||
.AddInMemoryTokenCaches();
|
||||
services.AddMicrosoftWebAppAuthentication(Configuration, "AzureAd")
|
||||
.AddMicrosoftWebAppCallsWebApi(Configuration, "AzureAd")
|
||||
.AddInMemoryTokenCaches();
|
||||
#else
|
||||
;
|
||||
services.AddMicrosoftWebAppAuthentication(Configuration, "AzureAd");
|
||||
#endif
|
||||
#if (GenerateApi)
|
||||
services.AddDownstreamWebApiService(Configuration);
|
||||
|
|
@ -87,15 +86,14 @@ namespace Company.WebApplication1
|
|||
Configuration.GetValue<string>("CalledApi:CalledApiUrl"));
|
||||
#endif
|
||||
#elif (IndividualB2CAuth)
|
||||
services.AddMicrosoftWebAppAuthentication(Configuration, "AzureAdB2C")
|
||||
#if (GenerateApi)
|
||||
.AddMicrosoftWebAppCallsWebApi(Configuration,
|
||||
"AzureAdB2C")
|
||||
.AddInMemoryTokenCaches();
|
||||
services.AddMicrosoftWebAppAuthentication(Configuration, "AzureAdB2C")
|
||||
.AddMicrosoftWebAppCallsWebApi(Configuration, "AzureAdB2C")
|
||||
.AddInMemoryTokenCaches();
|
||||
|
||||
services.AddDownstreamWebApiService(Configuration);
|
||||
#else
|
||||
;
|
||||
services.AddMicrosoftWebAppAuthentication(Configuration, "AzureAdB2C");
|
||||
#endif
|
||||
#endif
|
||||
#if (OrganizationalAuth)
|
||||
|
|
@ -106,11 +104,11 @@ namespace Company.WebApplication1
|
|||
options.FallbackPolicy = options.DefaultPolicy;
|
||||
});
|
||||
services.AddRazorPages()
|
||||
.AddMvcOptions(options => {})
|
||||
.AddMicrosoftIdentityUI();
|
||||
.AddMvcOptions(options => {})
|
||||
.AddMicrosoftIdentityUI();
|
||||
#elif (IndividualB2CAuth)
|
||||
services.AddRazorPages()
|
||||
.AddMicrosoftIdentityUI();
|
||||
.AddMicrosoftIdentityUI();
|
||||
#else
|
||||
services.AddRazorPages();
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -71,13 +71,12 @@ namespace Company.WebApplication1
|
|||
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
|
||||
.AddEntityFrameworkStores<ApplicationDbContext>();
|
||||
#elif (OrganizationalAuth)
|
||||
services.AddMicrosoftWebAppAuthentication(Configuration, "AzureAd")
|
||||
#if (GenerateApiOrGraph)
|
||||
.AddMicrosoftWebAppCallsWebApi(Configuration,
|
||||
"AzureAd")
|
||||
.AddInMemoryTokenCaches();
|
||||
services.AddMicrosoftWebAppAuthentication(Configuration, "AzureAd")
|
||||
.AddMicrosoftWebAppCallsWebApi(Configuration, "AzureAd")
|
||||
.AddInMemoryTokenCaches();
|
||||
#else
|
||||
;
|
||||
services.AddMicrosoftWebAppAuthentication(Configuration, "AzureAd");
|
||||
#endif
|
||||
#if (GenerateApi)
|
||||
services.AddDownstreamWebApiService(Configuration);
|
||||
|
|
@ -87,15 +86,14 @@ namespace Company.WebApplication1
|
|||
Configuration.GetValue<string>("CalledApi:CalledApiUrl"));
|
||||
#endif
|
||||
#elif (IndividualB2CAuth)
|
||||
services.AddMicrosoftWebAppAuthentication(Configuration, "AzureAdB2C")
|
||||
#if (GenerateApi)
|
||||
.AddMicrosoftWebAppCallsWebApi(Configuration,
|
||||
"AzureAdB2C")
|
||||
.AddInMemoryTokenCaches();
|
||||
services.AddMicrosoftWebAppAuthentication(Configuration, "AzureAdB2C")
|
||||
.AddMicrosoftWebAppCallsWebApi(Configuration, "AzureAdB2C")
|
||||
.AddInMemoryTokenCaches();
|
||||
|
||||
services.AddDownstreamWebApiService(Configuration);
|
||||
#else
|
||||
;
|
||||
services.AddMicrosoftWebAppAuthentication(Configuration, "AzureAdB2C");
|
||||
#endif
|
||||
#endif
|
||||
#if (OrganizationalAuth)
|
||||
|
|
@ -112,7 +110,7 @@ namespace Company.WebApplication1
|
|||
#endif
|
||||
#if (OrganizationalAuth || IndividualB2CAuth)
|
||||
services.AddRazorPages()
|
||||
.AddMicrosoftIdentityUI();
|
||||
.AddMicrosoftIdentityUI();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,15 +41,15 @@ namespace Company.WebApplication1
|
|||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
#if (OrganizationalAuth)
|
||||
#if (GenerateApiOrGraph)
|
||||
// Adds Microsoft Identity platform (AAD v2.0) support to protect this Api
|
||||
services.AddMicrosoftWebApiAuthentication(Configuration, "AzureAd")
|
||||
#if (GenerateApiOrGraph)
|
||||
.AddMicrosoftWebApiCallsWebApi(Configuration,
|
||||
"AzureAd")
|
||||
.AddInMemoryTokenCaches();
|
||||
.AddMicrosoftWebApiCallsWebApi(Configuration, "AzureAd")
|
||||
.AddInMemoryTokenCaches();
|
||||
|
||||
#else
|
||||
;
|
||||
// Adds Microsoft Identity platform (AAD v2.0) support to protect this Api
|
||||
services.AddMicrosoftWebApiAuthentication(Configuration, "AzureAd");
|
||||
#endif
|
||||
#if (GenerateApi)
|
||||
services.AddDownstreamWebApiService(Configuration);
|
||||
|
|
@ -59,15 +59,14 @@ namespace Company.WebApplication1
|
|||
Configuration.GetValue<string>("CalledApi:CalledApiUrl"));
|
||||
#endif
|
||||
#elif (IndividualB2CAuth)
|
||||
services.AddMicrosoftWebApiAuthentication(Configuration, "AzureAdB2C")
|
||||
#if (GenerateApi)
|
||||
.AddMicrosoftWebApiCallsWebApi(Configuration,
|
||||
"AzureAdB2C")
|
||||
.AddInMemoryTokenCaches();
|
||||
services.AddMicrosoftWebApiAuthentication(Configuration, "AzureAdB2C")
|
||||
.AddMicrosoftWebApiCallsWebApi(Configuration, "AzureAdB2C")
|
||||
.AddInMemoryTokenCaches();
|
||||
|
||||
services.AddDownstreamWebApiService(Configuration);
|
||||
#else
|
||||
;
|
||||
services.AddMicrosoftWebApiAuthentication(Configuration, "AzureAdB2C");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue