Web Api found ...

This commit is contained in:
Paul Schneider 2025-02-11 04:45:05 +00:00
commit 1d6cad7bef
23 changed files with 215 additions and 870 deletions

View file

@ -77,10 +77,12 @@ public static class Config
PostLogoutRedirectUris = { "https://localhost:5003/signout-callback-oidc" },
AllowOfflineAccess = true,
AllowedScopes = {
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
IdentityServerConstants.StandardScopes.OfflineAccess,
"scope2" }
},
};

View file

@ -2,6 +2,7 @@ using System.Globalization;
using System.Security.Cryptography.X509Certificates;
using Google.Apis.Util.Store;
using IdentityServer8;
using IdentityServer8.Hosting;
using IdentityServer8.Services;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
@ -187,8 +188,9 @@ internal static class HostingExtensions
.AddInMemoryClients(Config.Clients)
.AddInMemoryApiScopes(Config.ApiScopes)
.AddAspNetIdentity<ApplicationUser>()
.AddJwtBearerClientAuthentication()
;
services.AddScoped<IProfileService, ProfileService>();
//services.AddScoped<IProfileService, ProfileService>();
if (builder.Environment.IsDevelopment())
{
@ -207,7 +209,15 @@ internal static class HostingExtensions
// TODO .AddServerSideSessionStore<YavscServerSideSessionStore>()
var authenticationBuilder = services.AddAuthentication();
var authenticationBuilder = services.AddAuthentication()
.AddJwtBearer("Bearer", options =>
{
options.IncludeErrorDetails=true;
options.Authority = "https://localhost:5001";
options.TokenValidationParameters =
new() { ValidateAudience = false };
});
authenticationBuilder.AddGoogle(options =>
{
@ -251,13 +261,7 @@ internal static class HostingExtensions
};
});
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy", builder =>
{
_ = builder.WithOrigins("*");
});
});
// Add the system clock service
@ -313,10 +317,10 @@ internal static class HostingExtensions
services.AddAuthorization(options =>
{
options.AddPolicy("ApiScope", policy =>
{
policy.RequireAuthenticatedUser()
.RequireClaim("scope", "scope2");
});
{
policy.RequireAuthenticatedUser()
.RequireClaim("scope", "scope2");
});
options.AddPolicy("Performer", policy =>
{
policy
@ -334,11 +338,29 @@ internal static class HostingExtensions
// options.AddPolicy("BuildingEntry", policy => policy.Requirements.Add(new OfficeEntryRequirement()));
options.AddPolicy("Authenticated", policy => policy.RequireAuthenticatedUser());
options.AddPolicy("IsTheAuthor", policy => policy.Requirements.Add(new EditPermission()));
})
.AddCors(options =>
{
options.AddPolicy("CorsPolicy", builder =>
{
_ = builder.WithOrigins("*")
.AllowAnyHeader()
.AllowAnyMethod();
});
options.AddPolicy("default", policy =>
{
policy.WithOrigins("https://localhost:5003")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
services.AddSingleton<IAuthorizationHandler, PermissionHandler>();
// accepts any access token issued by identity server
return builder.Build();
}
public static WebApplication ConfigurePipeline(this WebApplication app)
@ -357,9 +379,6 @@ internal static class HostingExtensions
app.UseRouting();
app.UseIdentityServer();
app.UseAuthorization();
app.MapGet("/api/me", (HttpContext context) =>
new JsonResult(context?.User?.Claims.Select(c => new { c.Type, c.Value }))
).RequireAuthorization("ApiScope");
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");

View file

@ -8,11 +8,11 @@ using Yavsc.Models;
namespace Yavsc.Services
{
public class ProfileService : IProfileService
public class ProfileService : DefaultProfileService, IProfileService
{
private readonly UserManager<ApplicationUser> _userManager;
public ProfileService(
UserManager<ApplicationUser> userManager)
UserManager<ApplicationUser> userManager, ILogger<DefaultProfileService> logger) : base(logger)
{
_userManager = userManager;
}
@ -21,50 +21,56 @@ namespace Yavsc.Services
ProfileDataRequestContext context,
ApplicationUser user)
{
var requestedApiResources = context.RequestedResources.Resources.ApiResources.Select(
r => r.Name
).ToArray();
var requestedApiScopes = context.RequestedResources.Resources.ApiScopes.Select(
s => s.Name
).ToArray();
var allowedScopes = context.Client.AllowedScopes
.Where(s => s != JwtClaimTypes.Subject)
var requestedScopes = context.Client.AllowedScopes
.Where(s => s != JwtClaimTypes.Subject
&& requestedApiScopes.Contains(s))
.ToList();
if (allowedScopes.Contains("profile"))
if (context.RequestedClaimTypes.Contains("profile"))
if (requestedScopes.Contains("profile"))
{
allowedScopes.Remove("profile");
allowedScopes.Add(JwtClaimTypes.Name);
allowedScopes.Add(JwtClaimTypes.FamilyName);
allowedScopes.Add(JwtClaimTypes.Email);
allowedScopes.Add(JwtClaimTypes.PreferredUserName);
allowedScopes.Add("http://schemas.microsoft.com/ws/2008/06/identity/claims/role");
requestedScopes.Remove("profile");
requestedScopes.Add(JwtClaimTypes.Name);
requestedScopes.Add(JwtClaimTypes.FamilyName);
requestedScopes.Add(JwtClaimTypes.Email);
requestedScopes.Add(JwtClaimTypes.PreferredUserName);
requestedScopes.Add(JwtClaimTypes.Role);
}
var claims = new List<Claim> {
new Claim(JwtClaimTypes.Subject,user.Id.ToString()),
};
foreach (var subClaim in context.Subject.Claims)
if (requestedScopes.Contains(JwtClaimTypes.Name)||
requestedScopes.Contains(JwtClaimTypes.FamilyName))
{
if (allowedScopes.Contains(subClaim.Type))
claims.Add(subClaim);
claims.Add(new Claim(JwtClaimTypes.Name, user.FullName));
}
AddClaims(allowedScopes, claims, JwtClaimTypes.Email, user.Email);
AddClaims(allowedScopes, claims, JwtClaimTypes.PreferredUserName, user.FullName);
foreach (var scope in context.Client.AllowedScopes)
if (requestedScopes.Contains(JwtClaimTypes.PreferredUserName) )
{
claims.Add(new Claim("scope", scope));
claims.Add(new Claim(JwtClaimTypes.Name, user.UserName));
}
if (requestedScopes.Contains(JwtClaimTypes.Email))
claims.Add(new Claim(JwtClaimTypes.Email, user.Email));
if (requestedScopes.Contains(JwtClaimTypes.Role))
{
var roles = await this._userManager.GetRolesAsync(user);
if (roles.Count()>0)
{
claims.Add(new Claim(JwtClaimTypes.Role,String.Join(" ",roles)));
}
}
return claims;
}
private static void AddClaims(List<string> allowedScopes, List<Claim> claims,
string claimType, string claimValue
)
{
if (allowedScopes.Contains(claimType))
if (!claims.Any(c => c.Type == claimType))
claims.Add(new Claim(claimType, claimValue));
}
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var subjectId = context.Subject.Claims.FirstOrDefault(c => c.Type == "sub").Value;
@ -72,7 +78,6 @@ namespace Yavsc.Services
context.IssuedClaims = await GetClaimsFromUserAsync(context, user);
}
public async Task IsActiveAsync(IsActiveContext context)
{
var subjectId = context.Subject.Claims.FirstOrDefault(c => c.Type == "sub").Value;