thomasduft / openiddict-ui Goto Github PK
View Code? Open in Web Editor NEWA headless UI for the OpenIddict-Core stack.
License: MIT License
A headless UI for the OpenIddict-Core stack.
License: MIT License
Hi Thomas,
I have a concern regarding how a user can change his own password.
From my understanding, the APIs are more or less designed for an user admin. While this is fine probably for most use cases, an user might want to change his own password since he does not want the admin to know his password. At the moment, it seems to me that it is not possible for a non-admin role, or did I miss something?
Best regards,
Xiaoyang
Hi,
I use your API using client credential flow, and my application do not have Administrator role and therefore I had to create a custom IAuthorizationHandler with verification of specific claims in order to allow the usage of API.
It would be great to find a prettier to do this. Do you have any ideas?
public class SpecificApiAuthorizationHandler : IAuthorizationHandler
{
private readonly OpenIddictConfigurationOptions _openIdDictSettings;
private readonly HashSet<string> _authorizedScopes;
public SpecificApiAuthorizationHandler(
IOptions<OpenIddictConfigurationOptions> openIdDictOptions)
{
_openIdDictSettings = (openIdDictOptions ??
throw new ArgumentNullException(nameof(openIdDictOptions))).Value;
_authorizedScopes = new HashSet<string>(_openIdDictSettings.AuthorizedApiScope, StringComparer.OrdinalIgnoreCase);
}
public Task HandleAsync(AuthorizationHandlerContext context)
{
//if (context.Resource is HttpContext httpContext)
//{
// var endpoint = httpContext.GetEndpoint();
// var actionDescriptor = endpoint.Metadata.GetMetadata<ControllerActionDescriptor>();
//}
var pendingRequirements = context.PendingRequirements.ToList();
foreach (var requirement in pendingRequirements)
{
if (requirement is RolesAuthorizationRequirement rolesAuthorizationRequirement)
{
if (rolesAuthorizationRequirement.AllowedRoles.Contains(Roles.ADMINISTRATOR_ROLE))
{
if (IsAdmin(context.User, context.Resource) || HasClaimAuthorizedScope(context.User, context.Resource))
{
context.Succeed(rolesAuthorizationRequirement);
}
}
}
}
return Task.CompletedTask;
}
private bool IsAdmin(ClaimsPrincipal user, object? resource)
{
return user.IsInRole(Roles.ADMINISTRATOR_ROLE);
}
private bool HasClaimAuthorizedScope(ClaimsPrincipal user, object? resource)
{
return user.HasClaim(c => c.Type == Claims.Scope
&& c.Issuer.Equals(_openIdDictSettings.Authority, StringComparison.OrdinalIgnoreCase)
&& c.Value.Split(" ").Any(s => _authorizedScopes.Contains(s)));
}
}
The current code allows for the application user to be inherited from IdentityUser only. But IdentityUser can have it's primary key defined as a generic e.g. IdentityUser or IdentityUser
public class ApplicationUser : IdentityUser<Guid> { }
The constraints throughout this project restrict the application user to being of type IdenityUser (where TApplicationUser : IdentityUser)
To allow for different key types these constraints could be redefined as class only (e.g. this is how UserManager class handles this):
public static OpenIddictBuilder AddUIIdentityStore<TApplicationUser>(
this OpenIddictBuilder builder,
Action<OpenIddictUIIdentityStoreOptions> storeOptionsAction = null
) where TApplicationUser : class, new()
Or the code could be modified to use a generic interface e.g.
public static OpenIddictBuilder AddUIIdentityStore<TApplicationUser>(
this OpenIddictBuilder builder,
Action<OpenIddictUIIdentityStoreOptions> storeOptionsAction = null
) where TApplicationUser : IdentityUser, new()
{
return AddUIIdentityStore<TApplicationUser, string>(builder, storeOptionsAction);
}
public static OpenIddictBuilder AddUIIdentityStore<TApplicationUser, TKey>(
this OpenIddictBuilder builder,
Action<OpenIddictUIIdentityStoreOptions> storeOptionsAction = null
)
where TKey: IEquatable<TKey>
where TApplicationUser : IdentityUser<TKey>, new()
{
builder.Services.AddInfrastructureServices<TApplicationUser, TKey>();
builder.Services
.AddOpenIddictUIIdentityStore<OpenIddictUIIdentityContext>(storeOptionsAction);
return builder;
}
There are a few dependencies to Microsoft.AspNetCore.Mvc.Core which seems to not be needed (at least I was able to build with them removed) and it's causing issues when trying to build a self-contained executable cause it seems to have old and outdated dependencies itself.
tomware.OpenIddict.UI.Identity.Api 1.7.0 -> Microsoft.AspNetCore.Mvc.Core 2.2.5 -> Microsoft.Extensions.DependencyModel 2.1.0 -> Microsoft.DotNet.PlatformAbstractions 2.1.0 -> System.IO.FileSystem 4.0.1 -> runtime.unix.System.IO.FileSystem 4.3.0 -> System.Runtime.InteropServices (>= 4.3.0) [/src/Solution.sln]
tomware.OpenIddict.UI.Identity.Api 1.7.0 -> Microsoft.AspNetCore.Mvc.Core 2.2.5 -> Microsoft.Extensions.DependencyModel 2.1.0 -> Microsoft.DotNet.PlatformAbstractions 2.1.0 -> System.Runtime.InteropServices (>= 4.1.0) [/src/Solution.sln]
Can this reference be removed?
As a work around I got it working by adding this to my csproj:
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="7.0.0" />
Register Link (Account/Register) navigates to api/accounts/register.
I created an angular app based on this repo. Then I tried to public. It redirected to the openiddcit server and login was successful. But on redirection to my angular app from the authentication server. The it is looping in the angular app. It call the authorization again and again. No data is stored inside the local storage.
It is working fine in localhost.
ATM the user-management APIs that are built on top of ASP.NET Core Identity are built in.
As a developer I do not have the chance to not use those APIs (exclude) if not required in a project. The goal is to have dedicated packages to consume for an Identity Service.
Everything run fine when I ran it without docker, but when I use docker, I ran into this error: System.InvalidOperationException: IDX20803: Unable to obtain configuration from: 'System.String'. when I use Postman to get the Api (https://localhost:5001/api/Resource/private) after Login.
Here is my Docker compose:
version: '3'
services:
api:
build: Api/
ports:
- "5002:80"
- "5001:443"
environment:
ASPNETCORE_URLS: "https://+;http://+"
ASPNETCORE_HTTPS_PORT: "5001"
ASPNETCORE_ENVIRONMENT: "Development"
volumes:
- ${APPDATA}\microsoft\UserSecrets:/root/.microsoft/usersecrets
- ${USERPROFILE}.aspnet\https:/root/.aspnet/https/
server:
build: openiddict-ui/
ports:
- "4999:80"
- "5000:443"
environment:
ASPNETCORE_URLS: "https://+;http://+"
ASPNETCORE_HTTPS_PORT: "5000"
ASPNETCORE_ENVIRONMENT: "Development"
volumes:
- ${APPDATA}\microsoft\UserSecrets:/root/.microsoft/usersecrets
- ${USERPROFILE}.aspnet\https:/root/.aspnet/https/
Here is my Dockerfile Sever:
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build-env
RUN dotnet tool install -g dotnet-ef
ENV PATH $PATH:/root/.dotnet/tools
RUN dotnet ef --version
RUN apt-get update
RUN apt-get -y install sqlite3 libsqlite3-dev
WORKDIR /app
COPY .sln ./
COPY samples/Server/.csproj ./samples/Server/
COPY tests/.csproj ./tests/
COPY src/suite/OpenIddict.UI.Suite.Api/.csproj ./src/suite/OpenIddict.UI.Suite.Api/
COPY src/suite/OpenIddict.UI.Suite.Core/.csproj ./src/suite/OpenIddict.UI.Suite.Core/
COPY src/openiddict/OpenIddict.UI.Api/.csproj ./src/openiddict/OpenIddict.UI.Api/
COPY src/openiddict/OpenIddict.UI.Infrastructure/.csproj ./src/openiddict/OpenIddict.UI.Infrastructure/
COPY src/identity/OpenIddict.UI.Identity.Api/.csproj ./src/identity/OpenIddict.UI.Identity.Api/
COPY src/identity/OpenIddict.UI.Identity.Core/.csproj ./src/identity/OpenIddict.UI.Identity.Core/
COPY src/identity/OpenIddict.UI.Identity.Infrastructure/.csproj ./src/identity/OpenIddict.UI.Identity.Infrastructure/
RUN dotnet restore
COPY . ./
WORKDIR /app/samples/Server
RUN dotnet build -c Release -o out
WORKDIR /app/tests
RUN dotnet build -c Release -o out
WORKDIR /app/src/suite/OpenIddict.UI.Suite.Api
RUN dotnet build -c Release -o out
WORKDIR /app/src/suite/OpenIddict.UI.Suite.Core
RUN dotnet build -c Release -o out
WORKDIR /app/src/openiddict/OpenIddict.UI.Api
RUN dotnet build -c Release -o out
WORKDIR /app/src/openiddict/OpenIddict.UI.Infrastructure
RUN dotnet build -c Release -o out
WORKDIR /app/src/identity/OpenIddict.UI.Identity.Api
RUN dotnet build -c Release -o out
WORKDIR /app/src/identity/OpenIddict.UI.Identity.Core
RUN dotnet build -c Release -o out
WORKDIR /app/src/identity/OpenIddict.UI.Identity.Infrastructure
RUN dotnet build -c Release -o out
WORKDIR /app/samples/Server
RUN dotnet ef database update -c ApplicationDbContext
RUN dotnet ef database update -c OpenIddictUIContext
RUN dotnet ef database update -c OpenIddictUIIdentityContext
RUN dotnet publish -c Release -o out
FROM mcr.microsoft.com/dotnet/aspnet:5.0
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "Server.dll"]
Here is my Dockerfile Api:
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build-env
RUN apt-get update
RUN apt-get -y install sqlite3 libsqlite3-dev
WORKDIR /app/api
COPY *.csproj ./
RUN dotnet restore
COPY . ./
RUN dotnet publish -c Release -o out
FROM mcr.microsoft.com/dotnet/aspnet:5.0
WORKDIR /app/api
COPY --from=build-env /app/api/out .
ENTRYPOINT ["dotnet", "Api.dll"]
When using the IApplicationService.GetApplicationsAsync
method, the result list contains ApplicationInfo
instances with 0 Permissions
and RedirectUris
.
Hi Thomas,
Am I correct that the account API is only for the user identity but not for the user profile? If yes, how should I deal with the user profile? Should I create its own API?
Here is my simple user class.
public class MyUser: IdentityUser
{
public MyUser()
{
}
public MyUser(string username)
: base(username)
{
}
public string? Name { get; set; }
public string? FirstName { get; set; }
}
Best regards,
Xiaoyang
When I run dotnet ef database update, I run into this error: More than one DbContext was found. Specify which one to use
I notice that you have more than 1 DbContext. So how to fix this?
Hello @thomasduft
I have quickly added the integration tests for both public and private resource API (api/Resource/public and api/Resource/private) to validate the case when the API and the Server are not in the same app.
I always get the success status code from the public API, which is good, but the private API returns the internal server error due to the token validation failed, "No connection could be made because the target machine actively refused it". I ensure the token is valid and the Server is running properly since it returns the correct user info.
The interesting is, if I run the Server manually, all tests are passed. This means the token validation is success.
Is there something that I missed to get it run correctly?
If I delete some old scope, they doesnt appear in the request.GetScopes. That is true, but, when I add one more scope to the db and the client, the request.GetScopes() does not return that new scope, only the old five?
Please help !!!!
Hi @thomasduft,
I saw that I saw that you merged the Pull 5 one week ago to the main branch but I do not see the corresponding nuget packege.
Do you plan to publish the new version?
Thanks in advance for your answer
Not sure if it is meant to be used like this, but after updating an existing application the ClientSecret
is changed.
var app = await _apps.GetAsync(appId);
var param = new ApplicationParameter()
{
[...]
ClientSecret = app.ClientSecret,
[...]
}
await _apps.UpdateAsync(param);
Leaving the ClientSecret
at its initial value of null
will cause an exception, too.
So how am I supposed to update an existing application without changing the ClientSecret
?
hello,
i try to deploy to production.
the following error occur.
System.Security.Cryptography.CryptographicException: Access is denied.
what is the issue?
Hello can please share some UI Views samples so we can adopt/tailor or begin from it
Hey!
Tell me, please, how to switch the database to sql server?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.