1 Commits

Author SHA1 Message Date
Karsten Jeppesen
fee1f04bbc Version: 1.0 2025-11-21 08:34:04 +01:00
95 changed files with 1849 additions and 217 deletions

View File

@@ -1,37 +1,12 @@
{ {
"Version": 1, "Version": 1,
"WorkspaceRootPath": "D:\\Master20251026\\org\\WebApplication-API\\", "WorkspaceRootPath": "D:\\Master20251026\\dst\\WebApplication-API\\",
"Documents": [ "Documents": [],
{
"AbsoluteMoniker": "D:0:0:{A6000D9B-D8FD-48CA-83FA-9C7464FF0E88}|WebApplication-API\\WebApplication-API.csproj|d:\\master20251026\\org\\webapplication-api\\webapplication-api\\controllers\\weatherforecastcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{A6000D9B-D8FD-48CA-83FA-9C7464FF0E88}|WebApplication-API\\WebApplication-API.csproj|solutionrelative:webapplication-api\\controllers\\weatherforecastcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
}
],
"DocumentGroupContainers": [ "DocumentGroupContainers": [
{ {
"Orientation": 0, "Orientation": 0,
"VerticalTabListWidth": 256, "VerticalTabListWidth": 256,
"DocumentGroups": [ "DocumentGroups": []
{
"DockedWidth": 200,
"SelectedChildIndex": 0,
"Children": [
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "WeatherForecastController.cs",
"DocumentMoniker": "D:\\Master20251026\\org\\WebApplication-API\\WebApplication-API\\Controllers\\WeatherForecastController.cs",
"RelativeDocumentMoniker": "WebApplication-API\\Controllers\\WeatherForecastController.cs",
"ToolTip": "D:\\Master20251026\\org\\WebApplication-API\\WebApplication-API\\Controllers\\WeatherForecastController.cs",
"RelativeToolTip": "WebApplication-API\\Controllers\\WeatherForecastController.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABYAAAAxAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-27T19:26:26.649Z",
"EditorCaption": ""
}
]
}
]
} }
] ]
} }

View File

@@ -1,37 +1,12 @@
{ {
"Version": 1, "Version": 1,
"WorkspaceRootPath": "D:\\Master20251026\\org\\WebApplication-API\\", "WorkspaceRootPath": "D:\\Master20251026\\dst\\WebApplication-API\\",
"Documents": [ "Documents": [],
{
"AbsoluteMoniker": "D:0:0:{A6000D9B-D8FD-48CA-83FA-9C7464FF0E88}|WebApplication-API\\WebApplication-API.csproj|d:\\master20251026\\org\\webapplication-api\\webapplication-api\\controllers\\weatherforecastcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{A6000D9B-D8FD-48CA-83FA-9C7464FF0E88}|WebApplication-API\\WebApplication-API.csproj|solutionrelative:webapplication-api\\controllers\\weatherforecastcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
}
],
"DocumentGroupContainers": [ "DocumentGroupContainers": [
{ {
"Orientation": 0, "Orientation": 0,
"VerticalTabListWidth": 256, "VerticalTabListWidth": 256,
"DocumentGroups": [ "DocumentGroups": []
{
"DockedWidth": 200,
"SelectedChildIndex": 0,
"Children": [
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "WeatherForecastController.cs",
"DocumentMoniker": "D:\\Master20251026\\org\\WebApplication-API\\WebApplication-API\\Controllers\\WeatherForecastController.cs",
"RelativeDocumentMoniker": "WebApplication-API\\Controllers\\WeatherForecastController.cs",
"ToolTip": "D:\\Master20251026\\org\\WebApplication-API\\WebApplication-API\\Controllers\\WeatherForecastController.cs",
"RelativeToolTip": "WebApplication-API\\Controllers\\WeatherForecastController.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABYAAAAxAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-27T19:26:26.649Z",
"EditorCaption": ""
}
]
}
]
} }
] ]
} }

View File

@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio Version 17
VisualStudioVersion = 17.14.36616.10 d17.14 VisualStudioVersion = 17.14.36616.10 d17.14
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApplication-API", "WebApplication-API\WebApplication-API.csproj", "{A6000D9B-D8FD-48CA-83FA-9C7464FF0E88}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApplication-API", "WebApplication-API\WebApplication-API.csproj", "{CCE0BD23-703B-4CDC-958C-DDE09FB70D00}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -11,15 +11,15 @@ Global
Release|Any CPU = Release|Any CPU Release|Any CPU = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A6000D9B-D8FD-48CA-83FA-9C7464FF0E88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CCE0BD23-703B-4CDC-958C-DDE09FB70D00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A6000D9B-D8FD-48CA-83FA-9C7464FF0E88}.Debug|Any CPU.Build.0 = Debug|Any CPU {CCE0BD23-703B-4CDC-958C-DDE09FB70D00}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A6000D9B-D8FD-48CA-83FA-9C7464FF0E88}.Release|Any CPU.ActiveCfg = Release|Any CPU {CCE0BD23-703B-4CDC-958C-DDE09FB70D00}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A6000D9B-D8FD-48CA-83FA-9C7464FF0E88}.Release|Any CPU.Build.0 = Release|Any CPU {CCE0BD23-703B-4CDC-958C-DDE09FB70D00}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3BFDC144-55B3-4CB9-AC6B-FD11B42991BB} SolutionGuid = {307B341F-18AE-4D3A-AC0D-C2C5EE035FA5}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1,14 @@
{
"author": "Karsten Jeppesen kaje@ucn.dk",
"classifications": [ "Web", "Web API" ],
"name": "OpenIDConnectAPI", // Name of the template
"defaultName": "OpenID-API", // Suggested default project name
"identity": "UCNkaje.OpenIDConnectAPI", // Globally unique name for this template
"shortName": "oidc_api", // Short name that can be used on the cli
"tags": {
"language": "C#", // Specify that this template is in C#.
"type": "project" // and it is a project typr
},
"sourceName": "WebApplication-API", // Will replace this string with the value provided via -n.
"preferNameDirectory" : "true" // So mlikely always the parent folder name = project name
}

View File

@@ -1,3 +1,4 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace WebApplication_API.Controllers namespace WebApplication_API.Controllers
@@ -18,8 +19,10 @@ namespace WebApplication_API.Controllers
_logger = logger; _logger = logger;
} }
//[HttpGet(Name = "GetWeatherForecast")] // Authorization is shown here using the Authorize policy option
[HttpGet] //[Authorize]
[Authorize(Policy = "Admin")]
[HttpGet(Name = "WeatherForecast")]
public IEnumerable<WeatherForecast> Get() public IEnumerable<WeatherForecast> Get()
{ {
return Enumerable.Range(1, 5).Select(index => new WeatherForecast return Enumerable.Range(1, 5).Select(index => new WeatherForecast

View File

@@ -0,0 +1,190 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.HttpOverrides;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.OpenApi.Models;
// Required NuGet Packages
// Microsoft.AspNetCore.Authentication.JwtBearer
// Microsoft.AspNetCore.Authentication.OpenIdConnect
// Microsoft.IdentityModel.Protocols.OpenIdConnect
// Microsoft.AspNet.WebApi.Core
namespace WebApplication_API.OpenIDConnect
{
public class OpenIDConnectUtils
{
// Configuration priority from highest to lowest
// Highest: Command line arguments
// : Non-prefixed environment variables
// : User secrets from the .NET User Secrets Manager
// : Any appsettings.{ ENVIRONMENT_NAME }.json files
// : The appsettings.json file
// Lowest : Fallback to the host configuration
/// <summary>
/// Setting up OpenIDConnect authentication (Program.cs)
/// </summary>
/// <param name="builder">WebApplicationBuilder</param>
public void ConfigureBuild(WebApplicationBuilder builder)
{
MyConfiguration.Set(builder.Configuration);
builder.Services.AddControllers();
// >>> This adds the authentication service
builder.Services
.AddAuthentication()
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
{
// OpenIDRealmURI coud be "https://auth.a.ucnit.eu/realms/xOIDCx"
options.Authority = builder.Configuration["OpenIDRealmURI"];
options.Audience = "account";
options.MapInboundClaims = false;
options.Events = new JwtBearerEvents()
{
OnMessageReceived = msg =>
{
var token = msg?.Request.Headers.Authorization.ToString();
string path = msg?.Request.Path ?? "";
if (!string.IsNullOrEmpty(token))
{
Console.WriteLine("Access token");
Console.WriteLine($"URL: {path}");
Console.WriteLine($"Token: {token}\r\n");
}
else
{
Console.WriteLine("Access token");
Console.WriteLine("URL: " + path);
Console.WriteLine("Token: No access token provided\r\n");
}
return Task.CompletedTask;
}
};
options.Events = new JwtBearerEvents()
{
//...
OnTokenValidated = ctx =>
{
Console.WriteLine();
Console.WriteLine("Claims from the access token");
if (ctx?.Principal != null)
{
foreach (var claim in ctx.Principal.Claims)
{
Console.WriteLine($"{claim.Type} - {claim.Value}");
}
}
Console.WriteLine();
return Task.CompletedTask;
}
};
});
// <<<
// >>> This adds the authorization service
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("Admin", policy => policy.RequireClaim("roles", "admin", "warlock"));
});
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
// >>> Add Swagger with Authorization option
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Title = "My API",
Version = "v1"
});
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
In = ParameterLocation.Header,
Description = "Please insert JWT with Bearer into field",
Name = "Authorization",
Type = SecuritySchemeType.ApiKey
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement {
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
new string[] { }
}
});
});
// <<<
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});
}
/// <summary>
/// Map synthetic endpoints for authentication
/// </summary>
/// <param name="app">WebApplication</param>
public void ConfigureApp(WebApplication app)
{
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
}
public JwtSecurityToken GetJwtPayload(HttpContext myContext)
{
var handler = new JwtSecurityTokenHandler();
return handler.ReadJwtToken(myContext.GetTokenAsync("access_token").Result);
}
public string GetJwtClaim(HttpContext myContext, string theClaim)
{
JwtSecurityToken jwtPayload = GetJwtPayload(myContext);
return jwtPayload.Claims.FirstOrDefault(claim => claim.Type == theClaim).Value;
}
}
static public class MyConfiguration
{
static ConfigurationManager _config;
static public void Set(ConfigurationManager config)
{
_config = config;
}
static public ConfigurationManager Get()
{
return _config;
}
}
}

View File

@@ -1,25 +1,14 @@
using WebApplication_API.OpenIDConnect;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
// Add services to the container. // Configure for OpenID
OpenIDConnectUtils oidcConfig = new();
builder.Services.AddControllers(); oidcConfig.ConfigureBuild(builder);
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build(); var app = builder.Build();
// Configure the HTTP request pipeline. // Configure for OpenID
if (app.Environment.IsDevelopment()) oidcConfig.ConfigureApp(app);
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run(); app.Run();

View File

@@ -1,33 +1,24 @@
{ {
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:12867",
"sslPort": 44351
}
},
"profiles": { "profiles": {
"http": { "http": {
"commandName": "Project", "commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true, "launchBrowser": true,
"launchUrl": "swagger", "launchUrl": "swagger",
"applicationUrl": "http://localhost:5133",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
} },
"dotnetRunMessages": true,
"applicationUrl": "http://localhost:5124"
}, },
"https": { "https": {
"commandName": "Project", "commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true, "launchBrowser": true,
"launchUrl": "swagger", "launchUrl": "swagger",
"applicationUrl": "https://localhost:7035;http://localhost:5133",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
} },
"dotnetRunMessages": true,
"applicationUrl": "https://localhost:8888;http://localhost:5124"
}, },
"IIS Express": { "IIS Express": {
"commandName": "IISExpress", "commandName": "IISExpress",
@@ -37,5 +28,14 @@
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
} }
} }
},
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:21570",
"sslPort": 44323
}
} }
} }

View File

@@ -8,6 +8,10 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNet.WebApi.Core" Version="5.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.21" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="8.0.21" />
<PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="8.14.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
</ItemGroup> </ItemGroup>

View File

@@ -1,4 +1,4 @@
@WebApplication_API_HostAddress = http://localhost:5133 @WebApplication_API_HostAddress = http://localhost:5124
GET {{WebApplication_API_HostAddress}}/weatherforecast/ GET {{WebApplication_API_HostAddress}}/weatherforecast/
Accept: application/json Accept: application/json

View File

@@ -5,5 +5,7 @@
"Microsoft.AspNetCore": "Warning" "Microsoft.AspNetCore": "Warning"
} }
}, },
"AllowedHosts": "*" "AllowedHosts": "*",
"Comment3": "Arguments for KeyCloak Code Flow",
"OpenIDRealmURI": "https://auth.a.ucnit.eu/realms/xOIDCx"
} }

View File

@@ -9,13 +9,13 @@ build_property.EnforceExtendedAnalyzerRules =
build_property._SupportedPlatformList = Linux,macOS,Windows build_property._SupportedPlatformList = Linux,macOS,Windows
build_property.RootNamespace = WebApplication_API build_property.RootNamespace = WebApplication_API
build_property.RootNamespace = WebApplication_API build_property.RootNamespace = WebApplication_API
build_property.ProjectDir = D:\Master20251026\org\WebApplication-API\WebApplication-API\ build_property.ProjectDir = D:\Master20251026\dst\WebApplication-API\WebApplication-API\
build_property.EnableComHosting = build_property.EnableComHosting =
build_property.EnableGeneratedComInterfaceComImportInterop = build_property.EnableGeneratedComInterfaceComImportInterop =
build_property.RazorLangVersion = 8.0 build_property.RazorLangVersion = 8.0
build_property.SupportLocalizedComponentNames = build_property.SupportLocalizedComponentNames =
build_property.GenerateRazorMetadataSourceChecksumAttributes = build_property.GenerateRazorMetadataSourceChecksumAttributes =
build_property.MSBuildProjectDirectory = D:\Master20251026\org\WebApplication-API\WebApplication-API build_property.MSBuildProjectDirectory = D:\Master20251026\dst\WebApplication-API\WebApplication-API
build_property._RazorSourceGeneratorDebug = build_property._RazorSourceGeneratorDebug =
build_property.EffectiveAnalysisLevelStyle = 8.0 build_property.EffectiveAnalysisLevelStyle = 8.0
build_property.EnableCodeStyleSeverity = build_property.EnableCodeStyleSeverity =

View File

@@ -1 +1 @@
{"GlobalPropertiesHash":"C0wUyCc9yaHfiEY6YUgPvLFowH/hufkm1hsl/sHuNPk=","FingerprintPatternsHash":"gq3WsqcKBUGTSNle7RKKyXRIwh7M8ccEqOqYvIzoM04=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["cKJ1tyfnMzHIfqHHqW5dfnrbQ7Jx7FZ\u002Bq1\u002B8ozEHR2w=","cTAiuzpCzB/QBFcD4YdBOjxiaE6QiUVw2dmCKxAt2K0="],"CachedAssets":{},"CachedCopyCandidates":{}} {"GlobalPropertiesHash":"VuaE3syYJ2cNgABg1DseBHbk2+NDr8cEi5lWP7zbvgQ=","FingerprintPatternsHash":"gq3WsqcKBUGTSNle7RKKyXRIwh7M8ccEqOqYvIzoM04=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["qf6EYwVoVtzr6j4VvwpAB/MXJs4kQ1HlqkeEu\u002BE/MQU=","uzr/D\u002BYXZ9duD8p458pp9hf1xT6SHYMse4TWSBokfe4="],"CachedAssets":{},"CachedCopyCandidates":{}}

View File

@@ -1,6 +1,6 @@
{ {
"Version": 1, "Version": 1,
"WorkspaceRootPath": "D:\\Master20251026\\org\\WebApplication-MVC\\", "WorkspaceRootPath": "D:\\Master20251026\\dst\\WebApplication-MVC\\",
"Documents": [], "Documents": [],
"DocumentGroupContainers": [ "DocumentGroupContainers": [
{ {

View File

@@ -1,6 +1,6 @@
{ {
"Version": 1, "Version": 1,
"WorkspaceRootPath": "D:\\Master20251026\\org\\WebApplication-MVC\\", "WorkspaceRootPath": "D:\\Master20251026\\dst\\WebApplication-MVC\\",
"Documents": [], "Documents": [],
"DocumentGroupContainers": [ "DocumentGroupContainers": [
{ {

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1,15 @@
{
"$schema": "http://json.schemastore.org/template",
"author": "Karsten Jeppesen kaje@ucn.dk",
"classifications": [ "Web" ],
"name": "OpenIDConnectMVC", // Name of the template
"defaultName": "OpenID-MVC", // Suggested default project name
"identity": "UCNkaje.OpenIDConnectMVC", // Globally unique name for this template
"shortName": "oidc_mvc", // Short name that can be used on the cli
"tags": {
"language": "C#", // Specify that this template is in C#.
"type": "project" // and it is a project typr
},
"sourceName": "WebApplication-MVC", // Will replace this string with the value provided via -n.
"preferNameDirectory" : "true" // So mlikely always the parent folder name = project name
}

View File

@@ -0,0 +1,22 @@
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace WebApplication_MVC.Controllers
{
public class AccountController : Controller
{
public ActionResult Login()
{
return Challenge(OpenIdConnectDefaults.AuthenticationScheme);
}
[HttpGet]
public ActionResult Logout(int id)
{
return SignOut(CookieAuthenticationDefaults.AuthenticationScheme, OpenIdConnectDefaults.AuthenticationScheme);
}
}
}

View File

@@ -1,5 +1,11 @@
using System.Diagnostics; // Required packages
// Newtonsoft.Json
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq;
using System.Diagnostics;
using System.IdentityModel.Tokens.Jwt;
using WebApplication_MVC.Models; using WebApplication_MVC.Models;
namespace WebApplication_MVC.Controllers namespace WebApplication_MVC.Controllers
@@ -13,8 +19,17 @@ namespace WebApplication_MVC.Controllers
_logger = logger; _logger = logger;
} }
public IActionResult Index() public IActionResult Index(string theaction = "none")
{ {
// If an access_token was provided, then this part shows how to get at it
string? accessToken = HttpContext.GetTokenAsync("access_token").Result;
if (accessToken != null)
{
var handler = new JwtSecurityTokenHandler();
var jwtSecurityToken = handler.ReadJwtToken(accessToken);
string name = jwtSecurityToken.Claims.FirstOrDefault(claim => claim.Type == "name")?.Value;
ViewBag.name = name;
}
return View(); return View();
} }

View File

@@ -0,0 +1,192 @@
//#define IsRazor
#define IsMVC
//#define IsAPI
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
// Required NuGet Packages
// Microsoft.AspNetCore.Authentication.JwtBearer
// Microsoft.AspNetCore.Authentication.OpenIdConnect
// Microsoft.IdentityModel.Protocols.OpenIdConnect
// Microsoft.AspNet.WebApi.Core
namespace WebApplication_MVC.OpenIDConnect
{
public class OpenIDConnectUtils
{
// Configuration priority from highest to lowest
// Highest: Command line arguments
// : Non-prefixed environment variables
// : User secrets from the .NET User Secrets Manager
// : Any appsettings.{ ENVIRONMENT_NAME }.json files
// : The appsettings.json file
// Lowest : Fallback to the host configuration
/// <summary>
/// Setting up OpenIDConnect authentication (Program.cs)
/// </summary>
/// <param name="builder">WebApplicationBuilder</param>
public void ConfigureBuild(WebApplicationBuilder builder)
{
// Add services to the container.
builder.Services.AddControllersWithViews();
MyConfiguration.Set(builder.Configuration);
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
options.Authority = builder.Configuration["OpenIDRealmURI"];
options.ClientId = builder.Configuration["OpenIDClient"];
options.ClientSecret = builder.Configuration["OpenIDSecret"];
options.CallbackPath = "/signin-oidc";
//options.CallbackPath = "/signin-external";
// Authorization Code flow (recommended)
options.ResponseType = "code";
options.SaveTokens = true; // store tokens in auth properties
options.GetClaimsFromUserInfoEndpoint = true;
options.MapInboundClaims = false;
// Scopes - clear then add what's needed
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("ucn");
options.Scope.Add("email");
options.Scope.Add("offline_access"); // to get refresh tokens
// Map claim types if needed
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "roles"
};
// Optional: events for logging / error handling
options.Events = new OpenIdConnectEvents
{
OnTokenValidated = context =>
{
// e.g. add custom claims or logging
return Task.CompletedTask;
},
OnAuthenticationFailed = context =>
{
context.HandleResponse();
context.Response.Redirect("/Error?message=" + Uri.EscapeDataString(context.Exception.Message));
return Task.CompletedTask;
},
// added29.10.2025
OnSignedOutCallbackRedirect = context =>
{
context.Response.Redirect(context.Options.SignedOutRedirectUri);
context.HandleResponse();
return Task.CompletedTask;
}
};
});
// Change here for authorization policies
builder.Services
.AddAuthorizationBuilder()
.AddPolicy("read_access", builder =>
{
// claim, list of acceptable values
builder.RequireClaim("myClaim", "MyClaimValueRO1", "MyClaimValueRO2");
})
.AddPolicy("write_access", builder =>
{
builder.RequireClaim("myClaim", "MyClaimValueRW1", "MyClaimValueRW2");
});
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});
}
/// <summary>
/// Map synthetic endpoints for authentication
/// </summary>
/// <param name="app">WebApplication</param>
public void ConfigureApp(WebApplication app)
{
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
// Synthetic endpoint for authentication
// Call this endpoint to start login sequence.
// Something like this will do: <a href="authentication/login" class="btn btn-warning">Login</a>
app.MapGet("/authentication/login", ()
=> TypedResults.Challenge(
new AuthenticationProperties { RedirectUri = "/" }))
.AllowAnonymous();
app.MapGet("/authentication/logout", ()
=> TypedResults.SignOut(
new AuthenticationProperties { RedirectUri = "/" }))
.AllowAnonymous();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseForwardedHeaders();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
}
public JwtSecurityToken GetJwtPayload(HttpContext myContext)
{
var handler = new JwtSecurityTokenHandler();
return handler.ReadJwtToken(myContext.GetTokenAsync("access_token").Result);
}
public string GetJwtClaim(HttpContext myContext, string theClaim)
{
JwtSecurityToken jwtPayload = GetJwtPayload(myContext);
return jwtPayload.Claims.FirstOrDefault(claim => claim.Type == theClaim).Value;
}
}
static public class MyConfiguration
{
static ConfigurationManager _config;
static public void Set(ConfigurationManager config)
{
_config = config;
}
static public ConfigurationManager Get()
{
return _config;
}
}
}

View File

@@ -1,27 +1,17 @@
using WebApplication_MVC.OpenIDConnect;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
// Add services to the container. // Add services to the container.
builder.Services.AddControllersWithViews(); builder.Services.AddRazorPages();
// Configure for OpenID
OpenIDConnectUtils oidcConfig = new();
oidcConfig.ConfigureBuild(builder);
var app = builder.Build(); var app = builder.Build();
// Configure the HTTP request pipeline. // Configure for OpenID
if (!app.Environment.IsDevelopment()) oidcConfig.ConfigureApp(app);
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run(); app.Run();

View File

@@ -1,31 +1,22 @@
{ {
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:60463",
"sslPort": 44352
}
},
"profiles": { "profiles": {
"http": { "http": {
"commandName": "Project", "commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true, "launchBrowser": true,
"applicationUrl": "http://localhost:5074",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
} },
"dotnetRunMessages": true,
"applicationUrl": "http://localhost:5074"
}, },
"https": { "https": {
"commandName": "Project", "commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true, "launchBrowser": true,
"applicationUrl": "https://localhost:7045;http://localhost:5074",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
} },
"dotnetRunMessages": true,
"applicationUrl": "https://localhost:7777;http://localhost:5074"
}, },
"IIS Express": { "IIS Express": {
"commandName": "IISExpress", "commandName": "IISExpress",
@@ -34,5 +25,14 @@
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
} }
} }
},
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:60463",
"sslPort": 44352
}
} }
} }

View File

@@ -25,6 +25,18 @@
<li class="nav-item"> <li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a> <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</li> </li>
@if (ViewBag.name == null)
{
<li class="nav-item">
<a href="authentication/login" class="btn btn-warning">Login</a>
</li>
}
else
{
<li class="nav-item">
<a href="authentication/logout" class="btn btn-warning">Logout</a>
</li>
}
</ul> </ul>
</div> </div>
</div> </div>

View File

@@ -2,9 +2,22 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<IsPackable>true</IsPackable>
<PackageType>Template</PackageType>
<PackageId>UCN.KAJE.Template.OpenID.MVC</PackageId>
<PackageVersion>0.9.0</PackageVersion>
<Title>UCN.KAJE.OpenID.MVC</Title>
<Description>OpenID MVC Template</Description>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>WebApplication_MVC</RootNamespace> <RootNamespace>WebApplication_MVC</RootNamespace>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.21" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="8.0.21" />
<PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="8.14.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
</ItemGroup>
</Project> </Project>

View File

@@ -2,5 +2,7 @@
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<ActiveDebugProfile>https</ActiveDebugProfile> <ActiveDebugProfile>https</ActiveDebugProfile>
<Controller_SelectedScaffolderID>MvcControllerWithActionsScaffolder</Controller_SelectedScaffolderID>
<Controller_SelectedScaffolderCategoryPath>root/Common/MVC/Controller</Controller_SelectedScaffolderCategoryPath>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

View File

@@ -5,5 +5,9 @@
"Microsoft.AspNetCore": "Warning" "Microsoft.AspNetCore": "Warning"
} }
}, },
"AllowedHosts": "*" "AllowedHosts": "*",
"Comment3": "Arguments for KeyCloak Code Flow",
"OpenIDRealmURI": "https://auth.a.ucnit.eu/realms/xOIDCx",
"OpenIDClient": "Alice",
"OpenIDSecret": "JvDnso8O773pE9ENJdRhsrJd5pVD5Q86"
} }

View File

@@ -0,0 +1 @@
README file

View File

@@ -1 +0,0 @@
4ebb1750b7b8762fef591300bd34c2e2341e15736e5b3541ba7383e0d93731ef

File diff suppressed because one or more lines are too long

View File

@@ -12,7 +12,8 @@ using System;
using System.Reflection; using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("WebApplication-MVC")] [assembly: System.Reflection.AssemblyCompanyAttribute("WebApplication-MVC")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Release")]
[assembly: System.Reflection.AssemblyDescriptionAttribute("OpenID MVC Template")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
[assembly: System.Reflection.AssemblyProductAttribute("WebApplication-MVC")] [assembly: System.Reflection.AssemblyProductAttribute("WebApplication-MVC")]

View File

@@ -0,0 +1 @@
0c83178b8e3ac4ab8609fbcc8345f3fdbf41f110d116f89c7b3dd663ee238c5e

View File

@@ -9,41 +9,41 @@ build_property.EnforceExtendedAnalyzerRules =
build_property._SupportedPlatformList = Linux,macOS,Windows build_property._SupportedPlatformList = Linux,macOS,Windows
build_property.RootNamespace = WebApplication_MVC build_property.RootNamespace = WebApplication_MVC
build_property.RootNamespace = WebApplication_MVC build_property.RootNamespace = WebApplication_MVC
build_property.ProjectDir = D:\Master20251026\org\WebApplication-MVC\WebApplication-MVC\ build_property.ProjectDir = D:\Master20251026\dst\WebApplication-MVC\WebApplication-MVC\
build_property.EnableComHosting = build_property.EnableComHosting =
build_property.EnableGeneratedComInterfaceComImportInterop = build_property.EnableGeneratedComInterfaceComImportInterop =
build_property.RazorLangVersion = 8.0 build_property.RazorLangVersion = 8.0
build_property.SupportLocalizedComponentNames = build_property.SupportLocalizedComponentNames =
build_property.GenerateRazorMetadataSourceChecksumAttributes = build_property.GenerateRazorMetadataSourceChecksumAttributes =
build_property.MSBuildProjectDirectory = D:\Master20251026\org\WebApplication-MVC\WebApplication-MVC build_property.MSBuildProjectDirectory = D:\Master20251026\dst\WebApplication-MVC\WebApplication-MVC
build_property._RazorSourceGeneratorDebug = build_property._RazorSourceGeneratorDebug =
build_property.EffectiveAnalysisLevelStyle = 8.0 build_property.EffectiveAnalysisLevelStyle = 8.0
build_property.EnableCodeStyleSeverity = build_property.EnableCodeStyleSeverity =
[D:/Master20251026/org/WebApplication-MVC/WebApplication-MVC/Views/Home/Index.cshtml] [D:/Master20251026/dst/WebApplication-MVC/WebApplication-MVC/Views/Home/Index.cshtml]
build_metadata.AdditionalFiles.TargetPath = Vmlld3NcSG9tZVxJbmRleC5jc2h0bWw= build_metadata.AdditionalFiles.TargetPath = Vmlld3NcSG9tZVxJbmRleC5jc2h0bWw=
build_metadata.AdditionalFiles.CssScope = build_metadata.AdditionalFiles.CssScope =
[D:/Master20251026/org/WebApplication-MVC/WebApplication-MVC/Views/Home/Privacy.cshtml] [D:/Master20251026/dst/WebApplication-MVC/WebApplication-MVC/Views/Home/Privacy.cshtml]
build_metadata.AdditionalFiles.TargetPath = Vmlld3NcSG9tZVxQcml2YWN5LmNzaHRtbA== build_metadata.AdditionalFiles.TargetPath = Vmlld3NcSG9tZVxQcml2YWN5LmNzaHRtbA==
build_metadata.AdditionalFiles.CssScope = build_metadata.AdditionalFiles.CssScope =
[D:/Master20251026/org/WebApplication-MVC/WebApplication-MVC/Views/Shared/Error.cshtml] [D:/Master20251026/dst/WebApplication-MVC/WebApplication-MVC/Views/Shared/Error.cshtml]
build_metadata.AdditionalFiles.TargetPath = Vmlld3NcU2hhcmVkXEVycm9yLmNzaHRtbA== build_metadata.AdditionalFiles.TargetPath = Vmlld3NcU2hhcmVkXEVycm9yLmNzaHRtbA==
build_metadata.AdditionalFiles.CssScope = build_metadata.AdditionalFiles.CssScope =
[D:/Master20251026/org/WebApplication-MVC/WebApplication-MVC/Views/Shared/_ValidationScriptsPartial.cshtml] [D:/Master20251026/dst/WebApplication-MVC/WebApplication-MVC/Views/Shared/_ValidationScriptsPartial.cshtml]
build_metadata.AdditionalFiles.TargetPath = Vmlld3NcU2hhcmVkXF9WYWxpZGF0aW9uU2NyaXB0c1BhcnRpYWwuY3NodG1s build_metadata.AdditionalFiles.TargetPath = Vmlld3NcU2hhcmVkXF9WYWxpZGF0aW9uU2NyaXB0c1BhcnRpYWwuY3NodG1s
build_metadata.AdditionalFiles.CssScope = build_metadata.AdditionalFiles.CssScope =
[D:/Master20251026/org/WebApplication-MVC/WebApplication-MVC/Views/_ViewImports.cshtml] [D:/Master20251026/dst/WebApplication-MVC/WebApplication-MVC/Views/_ViewImports.cshtml]
build_metadata.AdditionalFiles.TargetPath = Vmlld3NcX1ZpZXdJbXBvcnRzLmNzaHRtbA== build_metadata.AdditionalFiles.TargetPath = Vmlld3NcX1ZpZXdJbXBvcnRzLmNzaHRtbA==
build_metadata.AdditionalFiles.CssScope = build_metadata.AdditionalFiles.CssScope =
[D:/Master20251026/org/WebApplication-MVC/WebApplication-MVC/Views/_ViewStart.cshtml] [D:/Master20251026/dst/WebApplication-MVC/WebApplication-MVC/Views/_ViewStart.cshtml]
build_metadata.AdditionalFiles.TargetPath = Vmlld3NcX1ZpZXdTdGFydC5jc2h0bWw= build_metadata.AdditionalFiles.TargetPath = Vmlld3NcX1ZpZXdTdGFydC5jc2h0bWw=
build_metadata.AdditionalFiles.CssScope = build_metadata.AdditionalFiles.CssScope =
[D:/Master20251026/org/WebApplication-MVC/WebApplication-MVC/Views/Shared/_Layout.cshtml] [D:/Master20251026/dst/WebApplication-MVC/WebApplication-MVC/Views/Shared/_Layout.cshtml]
build_metadata.AdditionalFiles.TargetPath = Vmlld3NcU2hhcmVkXF9MYXlvdXQuY3NodG1s build_metadata.AdditionalFiles.TargetPath = Vmlld3NcU2hhcmVkXF9MYXlvdXQuY3NodG1s
build_metadata.AdditionalFiles.CssScope = b-8qwq1t3net build_metadata.AdditionalFiles.CssScope = b-8qwq1t3net

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{ {
"Version": 1, "Version": 1,
"WorkspaceRootPath": "D:\\Master20251026\\org\\WebApplication-Razor\\", "WorkspaceRootPath": "D:\\Master20251026\\dst\\WebApplication-Razor\\",
"Documents": [], "Documents": [],
"DocumentGroupContainers": [ "DocumentGroupContainers": [
{ {

View File

@@ -1,6 +1,6 @@
{ {
"Version": 1, "Version": 1,
"WorkspaceRootPath": "D:\\Master20251026\\org\\WebApplication-Razor\\", "WorkspaceRootPath": "D:\\Master20251026\\dst\\WebApplication-Razor\\",
"Documents": [], "Documents": [],
"DocumentGroupContainers": [ "DocumentGroupContainers": [
{ {

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1,14 @@
{
"author": "Karsten Jeppesen kaje@ucn.dk",
"classifications": [ "Web" ],
"name": "OpenIDConnectRazor", // Name of the template
"defaultName": "OpenID-Razor", // Suggested default project name
"identity": "UCNkaje.OpenIDConnectRazor", // Globally unique name for this template
"shortName": "oidc_razor", // Short name that can be used on the cli
"tags": {
"language": "C#", // Specify that this template is in C#.
"type": "project" // and it is a project typr
},
"sourceName": "WebApplication-Razor", // Will replace this string with the value provided via -n.
"preferNameDirectory" : "true" // So mlikely always the parent folder name = project name
}

View File

@@ -0,0 +1,167 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.HttpOverrides;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
// Required NuGet Packages
// Microsoft.AspNetCore.Authentication.JwtBearer
// Microsoft.AspNetCore.Authentication.OpenIdConnect
// Microsoft.IdentityModel.Protocols.OpenIdConnect
// Microsoft.AspNet.WebApi.Core
namespace WebApplication_Razor.OpenIDConnect
{
public class OpenIDConnectUtils
{
// Configuration priority from highest to lowest
// Highest: Command line arguments
// : Non-prefixed environment variables
// : User secrets from the .NET User Secrets Manager
// : Any appsettings.{ ENVIRONMENT_NAME }.json files
// : The appsettings.json file
// Lowest : Fallback to the host configuration
/// <summary>
/// Setting up OpenIDConnect authentication (Program.cs)
/// </summary>
/// <param name="builder">WebApplicationBuilder</param>
public void ConfigureBuild(WebApplicationBuilder builder)
{
// Add services to the container.
builder.Services.AddRazorPages();
MyConfiguration.Set(builder.Configuration);
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
options.Authority = builder.Configuration["OpenIDRealmURI"];
options.ClientId = builder.Configuration["OpenIDClient"];
options.ClientSecret = builder.Configuration["OpenIDSecret"];
options.CallbackPath = "/signin-oidc";
// Authorization Code flow (recommended)
options.ResponseType = "code";
options.SaveTokens = true; // store tokens in auth properties
options.GetClaimsFromUserInfoEndpoint = true;
options.MapInboundClaims = false;
// Scopes - clear then add what's needed
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("ucn");
options.Scope.Add("email");
options.Scope.Add("offline_access"); // to get refresh tokens
// Map claim types if needed
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "roles"
};
// Optional: events for logging / error handling
options.Events = new OpenIdConnectEvents
{
OnTokenValidated = context =>
{
// e.g. add custom claims or logging
return Task.CompletedTask;
},
OnAuthenticationFailed = context =>
{
context.HandleResponse();
context.Response.Redirect("/Error?message=" + Uri.EscapeDataString(context.Exception.Message));
return Task.CompletedTask;
}
};
});
// Change here for authorization policies
builder.Services
.AddAuthorizationBuilder()
.AddPolicy("read_access", builder =>
{
// claim, list of acceptable values
builder.RequireClaim("myClaim", "MyClaimValueRO1", "MyClaimValueRO2");
})
.AddPolicy("write_access", builder =>
{
builder.RequireClaim("myClaim", "MyClaimValueRW1", "MyClaimValueRW2");
});
// Require authentication globally (optional)
builder.Services.AddRazorPages(options =>
{
options.Conventions.AuthorizeFolder("/");
});
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});
}
/// <summary>
/// Map synthetic endpoints for authentication
/// </summary>
/// <param name="app">WebApplication</param>
public void ConfigureApp(WebApplication app)
{
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseStaticFiles();
app.UseRouting();
app.UseForwardedHeaders();
app.UseAuthentication();
app.UseAuthorization();
app.MapRazorPages(); // Or app.MapDefaultControllerRoute();
}
public JwtSecurityToken GetJwtPayload(HttpContext myContext)
{
var handler = new JwtSecurityTokenHandler();
return handler.ReadJwtToken(myContext.GetTokenAsync("access_token").Result);
}
public string GetJwtClaim(HttpContext myContext, string theClaim)
{
JwtSecurityToken jwtPayload = GetJwtPayload(myContext);
return jwtPayload.Claims.FirstOrDefault(claim => claim.Type == theClaim).Value;
}
}
static public class MyConfiguration
{
static ConfigurationManager _config;
static public void Set(ConfigurationManager config)
{
_config = config;
}
static public ConfigurationManager Get()
{
return _config;
}
}
}

View File

@@ -1,25 +1,17 @@
using WebApplication_Razor.OpenIDConnect;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
// Add services to the container. // Add services to the container.
builder.Services.AddRazorPages(); builder.Services.AddRazorPages();
// Configure for OpenID
OpenIDConnectUtils oidcConfig = new();
oidcConfig.ConfigureBuild(builder);
var app = builder.Build(); var app = builder.Build();
// Configure the HTTP request pipeline. // Configure for OpenID
if (!app.Environment.IsDevelopment()) oidcConfig.ConfigureApp(app);
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run(); app.Run();

View File

@@ -1,31 +1,22 @@
{ {
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:2424",
"sslPort": 44397
}
},
"profiles": { "profiles": {
"http": { "http": {
"commandName": "Project", "commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true, "launchBrowser": true,
"applicationUrl": "http://localhost:5039",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
} },
"dotnetRunMessages": true,
"applicationUrl": "http://localhost:5039"
}, },
"https": { "https": {
"commandName": "Project", "commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true, "launchBrowser": true,
"applicationUrl": "https://localhost:7285;http://localhost:5039",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
} },
"dotnetRunMessages": true,
"applicationUrl": "https://localhost:7777;http://localhost:5039"
}, },
"IIS Express": { "IIS Express": {
"commandName": "IISExpress", "commandName": "IISExpress",
@@ -34,5 +25,14 @@
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
} }
} }
},
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:2424",
"sslPort": 44397
}
} }
} }

View File

@@ -0,0 +1 @@
test

View File

@@ -1,10 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<IsPackable>true</IsPackable>
<PackageType>Template</PackageType>
<PackageVersion>0.9.0</PackageVersion>
<PackageId>UCNkaje.OpenIDConnectRazor.templates</PackageId>
<Authors>Karsten Jeppesen kaje@ucn.dk</Authors>
<Description>.NET Razor project with OpenID</Description>
<PackageTags>dotnet-new;templates</PackageTags>
<IncludeContentInPack>true</IncludeContentInPack>
<IncludeBuildOutput>false</IncludeBuildOutput>
<PackageLicenseExpression>GPL3</PackageLicenseExpression>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>WebApplication_Razor</RootNamespace> <RootNamespace>WebApplication_Razor</RootNamespace>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.21" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="8.0.21" />
<PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="8.14.0" />
</ItemGroup>
</Project> </Project>

View File

@@ -5,5 +5,9 @@
"Microsoft.AspNetCore": "Warning" "Microsoft.AspNetCore": "Warning"
} }
}, },
"AllowedHosts": "*" "AllowedHosts": "*",
"Comment3": "Arguments for KeyCloak Code Flow",
"OpenIDRealmURI": "https://auth.a.ucnit.eu/realms/xOIDCx",
"OpenIDClient": "Alice",
"OpenIDSecret": "JvDnso8O773pE9ENJdRhsrJd5pVD5Q86"
} }

View File

@@ -11,8 +11,9 @@
using System; using System;
using System.Reflection; using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("WebApplication-Razor")] [assembly: System.Reflection.AssemblyCompanyAttribute("Karsten Jeppesen kaje@ucn.dk")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyDescriptionAttribute(".NET Razor project with OpenID")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
[assembly: System.Reflection.AssemblyProductAttribute("WebApplication-Razor")] [assembly: System.Reflection.AssemblyProductAttribute("WebApplication-Razor")]

View File

@@ -1 +1 @@
c6c89d037e25ad7d22f515db1d02e8b7c2eecd0cef2aad1241354e479d4ef67a bd0899c5c7dffe20d881f468179ad5e6e3310e0d7ec46aaf63ba818d636f3a3e

View File

@@ -9,41 +9,41 @@ build_property.EnforceExtendedAnalyzerRules =
build_property._SupportedPlatformList = Linux,macOS,Windows build_property._SupportedPlatformList = Linux,macOS,Windows
build_property.RootNamespace = WebApplication_Razor build_property.RootNamespace = WebApplication_Razor
build_property.RootNamespace = WebApplication_Razor build_property.RootNamespace = WebApplication_Razor
build_property.ProjectDir = D:\Master20251026\org\WebApplication-Razor\WebApplication-Razor\ build_property.ProjectDir = D:\Master20251026\dst\WebApplication-Razor\WebApplication-Razor\
build_property.EnableComHosting = build_property.EnableComHosting =
build_property.EnableGeneratedComInterfaceComImportInterop = build_property.EnableGeneratedComInterfaceComImportInterop =
build_property.RazorLangVersion = 8.0 build_property.RazorLangVersion = 8.0
build_property.SupportLocalizedComponentNames = build_property.SupportLocalizedComponentNames =
build_property.GenerateRazorMetadataSourceChecksumAttributes = build_property.GenerateRazorMetadataSourceChecksumAttributes =
build_property.MSBuildProjectDirectory = D:\Master20251026\org\WebApplication-Razor\WebApplication-Razor build_property.MSBuildProjectDirectory = D:\Master20251026\dst\WebApplication-Razor\WebApplication-Razor
build_property._RazorSourceGeneratorDebug = build_property._RazorSourceGeneratorDebug =
build_property.EffectiveAnalysisLevelStyle = 8.0 build_property.EffectiveAnalysisLevelStyle = 8.0
build_property.EnableCodeStyleSeverity = build_property.EnableCodeStyleSeverity =
[D:/Master20251026/org/WebApplication-Razor/WebApplication-Razor/Pages/Error.cshtml] [D:/Master20251026/dst/WebApplication-Razor/WebApplication-Razor/Pages/Error.cshtml]
build_metadata.AdditionalFiles.TargetPath = UGFnZXNcRXJyb3IuY3NodG1s build_metadata.AdditionalFiles.TargetPath = UGFnZXNcRXJyb3IuY3NodG1s
build_metadata.AdditionalFiles.CssScope = build_metadata.AdditionalFiles.CssScope =
[D:/Master20251026/org/WebApplication-Razor/WebApplication-Razor/Pages/Index.cshtml] [D:/Master20251026/dst/WebApplication-Razor/WebApplication-Razor/Pages/Index.cshtml]
build_metadata.AdditionalFiles.TargetPath = UGFnZXNcSW5kZXguY3NodG1s build_metadata.AdditionalFiles.TargetPath = UGFnZXNcSW5kZXguY3NodG1s
build_metadata.AdditionalFiles.CssScope = build_metadata.AdditionalFiles.CssScope =
[D:/Master20251026/org/WebApplication-Razor/WebApplication-Razor/Pages/Privacy.cshtml] [D:/Master20251026/dst/WebApplication-Razor/WebApplication-Razor/Pages/Privacy.cshtml]
build_metadata.AdditionalFiles.TargetPath = UGFnZXNcUHJpdmFjeS5jc2h0bWw= build_metadata.AdditionalFiles.TargetPath = UGFnZXNcUHJpdmFjeS5jc2h0bWw=
build_metadata.AdditionalFiles.CssScope = build_metadata.AdditionalFiles.CssScope =
[D:/Master20251026/org/WebApplication-Razor/WebApplication-Razor/Pages/Shared/_ValidationScriptsPartial.cshtml] [D:/Master20251026/dst/WebApplication-Razor/WebApplication-Razor/Pages/Shared/_ValidationScriptsPartial.cshtml]
build_metadata.AdditionalFiles.TargetPath = UGFnZXNcU2hhcmVkXF9WYWxpZGF0aW9uU2NyaXB0c1BhcnRpYWwuY3NodG1s build_metadata.AdditionalFiles.TargetPath = UGFnZXNcU2hhcmVkXF9WYWxpZGF0aW9uU2NyaXB0c1BhcnRpYWwuY3NodG1s
build_metadata.AdditionalFiles.CssScope = build_metadata.AdditionalFiles.CssScope =
[D:/Master20251026/org/WebApplication-Razor/WebApplication-Razor/Pages/_ViewImports.cshtml] [D:/Master20251026/dst/WebApplication-Razor/WebApplication-Razor/Pages/_ViewImports.cshtml]
build_metadata.AdditionalFiles.TargetPath = UGFnZXNcX1ZpZXdJbXBvcnRzLmNzaHRtbA== build_metadata.AdditionalFiles.TargetPath = UGFnZXNcX1ZpZXdJbXBvcnRzLmNzaHRtbA==
build_metadata.AdditionalFiles.CssScope = build_metadata.AdditionalFiles.CssScope =
[D:/Master20251026/org/WebApplication-Razor/WebApplication-Razor/Pages/_ViewStart.cshtml] [D:/Master20251026/dst/WebApplication-Razor/WebApplication-Razor/Pages/_ViewStart.cshtml]
build_metadata.AdditionalFiles.TargetPath = UGFnZXNcX1ZpZXdTdGFydC5jc2h0bWw= build_metadata.AdditionalFiles.TargetPath = UGFnZXNcX1ZpZXdTdGFydC5jc2h0bWw=
build_metadata.AdditionalFiles.CssScope = build_metadata.AdditionalFiles.CssScope =
[D:/Master20251026/org/WebApplication-Razor/WebApplication-Razor/Pages/Shared/_Layout.cshtml] [D:/Master20251026/dst/WebApplication-Razor/WebApplication-Razor/Pages/Shared/_Layout.cshtml]
build_metadata.AdditionalFiles.TargetPath = UGFnZXNcU2hhcmVkXF9MYXlvdXQuY3NodG1s build_metadata.AdditionalFiles.TargetPath = UGFnZXNcU2hhcmVkXF9MYXlvdXQuY3NodG1s
build_metadata.AdditionalFiles.CssScope = b-7r1e28y3hg build_metadata.AdditionalFiles.CssScope = b-7r1e28y3hg

File diff suppressed because one or more lines are too long