openiddict / openiddict-core

Flexible and versatile OAuth 2.0/OpenID Connect stack for .NET
https://openiddict.com/
Apache License 2.0
4.41k stars 514 forks source link

Is possible to customize OpenIdDictApplication adding a new field? #434

Closed michaelsogos closed 6 years ago

michaelsogos commented 7 years ago

Dear,

Our needs is to add a new field on OpenIddictApplication. We try to customize that entity, create an ef migration, update database schema, and referencing the new class (MyApplication that inherit from OpeniddictApplication) when we need an instance of OpeniddictApplicationManager(); till here everything ok.

But when we use dependency injection to get ApplicationManager like scope.ServiceProvider.GetRequiredService<OpenIddictApplicationManager<MyApplication>>(); It fail with error

No service for type 'OpenIddict.Core.OpenIddictApplicationManager`1[BusinessManagerService.AuthServer.Models.MyApplication]' has been registered.

Then i try to register in different way the service type required but i have to implement store, logger, etc.

So, exist an easier way to extend OpeniddictApplication?

kevinchalet commented 7 years ago

There are 4 things you need to do when creating your own entities (assuming you're willing to derive from ours, 'cause you don't have to if you also provide your own stores):

michaelsogos commented 7 years ago

Can you supply me an example? I'm stuck somewhere.

My need is to add a property bool IsReserved like this

    public class ApplicationClient   : OpenIddictApplication<int>
    {
        [DefaultValue(false)]
        public bool IsReserved { get; set; }
    }
kevinchalet commented 7 years ago
public class MyApplication : OpenIddictApplication<long, MyAuthorization, MyToken>
{
    public bool IsReserved { get; set; }
}
public class MyAuthorization : OpenIddictAuthorization<long, MyApplication, MyToken> { }
public class MyScope : OpenIddictScope<long> { }
public class MyToken : OpenIddictToken<long, MyApplication, MyAuthorization> { }
services.AddOpenIddict<MyApplication, MyAuthorization, MyScope, MyToken>();
services.AddDbContext<ApplicationDbContext>(options =>
{
    options.UseSqlServer(configuration["Data:DefaultConnection:ConnectionString"]);
    options.UseOpenIddict<MyApplication, MyAuthorization, MyScope, MyToken, long>();
});
michaelsogos commented 7 years ago

Great, it work perfectly!!!

Just you forgot to mention this :) , but i not understood if it is needed again or not, time ago there was an issue that the DbContext options was not enought; i didn't try again without the below code. :)

 protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);
            //builder.UseOpenIddict();
            builder.UseOpenIddict<MyApplication, MyAuthorization, MyScope, MyToken, string>();
        }
michaelsogos commented 7 years ago

For who come next, i implemented it for PK int, i can share example in case it is needed :)

kevinchalet commented 7 years ago

@michaelsogos using the ModelBuilder is an alternative way to register the OpenIddict entities. In my sample, I used options.UseOpenIddict<MyApplication, MyAuthorization, MyScope, MyToken, string>(); directly in Startup, which does the same thing.

michaelsogos commented 7 years ago

yes, I suspected this ;) , i had both.

dave0292 commented 2 years ago

I have implemented my custom entities like in the previous example and I have been able to create those tables correctly (including two custom columns in applications table), but I don't know how to save changes into database using the "OpenIddictApplicationManager":

var manager = scope.ServiceProvider.GetRequiredService<OpenIddictApplicationManager<SpApplication>>();

Where "SpApplication" inherits from "OpenIddictEntityFrameworkCoreApplication<string, CustomAuthorization, CustomToken" like:

public class SpApplication : OpenIddictEntityFrameworkCoreApplication<string, CustomAuthorization, CustomToken>

Saving applications in the following way does not save the organizationId value into database:

if (await manager.FindByClientIdAsync("postman", cancellationToken) is null)
{
    await manager.CreateAsync(new CustomOpenIddictApplicationDescriptor
    {
        ClientId = "postman",
        ClientSecret = "postman-secret",
        DisplayName = "Postman",
        OrganizationId = 2,
        //RedirectUris = { new Uri("https://oauth.pstmn.io/v1/callback") },
        Permissions =
        {
            OpenIddictConstants.Permissions.Endpoints.Token,
            OpenIddictConstants.Permissions.GrantTypes.ClientCredentials,
            OpenIddictConstants.Permissions.Prefixes.Scope + "api",
            OpenIddictConstants.Permissions.ResponseTypes.Token
        }
    }, cancellationToken);
}

...

public class CustomOpenIddictApplicationDescriptor : OpenIddictApplicationDescriptor
{
    public int OrganizationId { get; set; }
    public bool Enabled { get; set; } = true;
}

Do I need to implement my custom SpApplicationStore to be able to save this kind of custom column values?

frogerdevs commented 2 years ago
  • 're

hi, @dave0292 I have same problem, please tell me if you solve this issue. Thanks.

enantiomer2000 commented 2 years ago

I have implemented my custom entities like in the previous example and I have been able to create those tables correctly (including two custom columns in applications table), but I don't know how to save changes into database using the "OpenIddictApplicationManager":

var manager = scope.ServiceProvider.GetRequiredService<OpenIddictApplicationManager<SpApplication>>();

Where "SpApplication" inherits from "OpenIddictEntityFrameworkCoreApplication<string, CustomAuthorization, CustomToken" like:

public class SpApplication : OpenIddictEntityFrameworkCoreApplication<string, CustomAuthorization, CustomToken>

Saving applications in the following way does not save the organizationId value into database:

if (await manager.FindByClientIdAsync("postman", cancellationToken) is null)
{
    await manager.CreateAsync(new CustomOpenIddictApplicationDescriptor
    {
        ClientId = "postman",
        ClientSecret = "postman-secret",
        DisplayName = "Postman",
        OrganizationId = 2,
        //RedirectUris = { new Uri("https://oauth.pstmn.io/v1/callback") },
        Permissions =
        {
            OpenIddictConstants.Permissions.Endpoints.Token,
            OpenIddictConstants.Permissions.GrantTypes.ClientCredentials,
            OpenIddictConstants.Permissions.Prefixes.Scope + "api",
            OpenIddictConstants.Permissions.ResponseTypes.Token
        }
    }, cancellationToken);
}

...

public class CustomOpenIddictApplicationDescriptor : OpenIddictApplicationDescriptor
{
    public int OrganizationId { get; set; }
    public bool Enabled { get; set; } = true;
}

Do I need to implement my custom SpApplicationStore to be able to save this kind of custom column values?

@dave0292 OR @frogerdevs I am seeing the same issue. There doesn't seem to be any documentation for this. Anybody solve this issue? Edit: Solved my issue here https://stackoverflow.com/questions/72369805/custom-openiddictapplication-field-always-returns-null/72382526#72382526

broguyman commented 1 year ago

If you're like me and ran into this issue in 2023. The way I solved the problem was to use the overload that accepts an object instead of the OpenIddictApplicationDescriptor.

RezaPouya commented 1 year ago

If you're like me and ran into this issue in 2023. The way I solved the problem was to use the overload that accepts an object instead of the OpenIddictApplicationDescriptor.

can you explain ?

RezaPouya commented 1 year ago
public class MyApplication : OpenIddictApplication<long, MyAuthorization, MyToken>
{
    public bool IsReserved { get; set; }
}
public class MyAuthorization : OpenIddictAuthorization<long, MyApplication, MyToken> { }
public class MyScope : OpenIddictScope<long> { }
public class MyToken : OpenIddictToken<long, MyApplication, MyAuthorization> { }
services.AddOpenIddict<MyApplication, MyAuthorization, MyScope, MyToken>();
services.AddDbContext<ApplicationDbContext>(options =>
{
    options.UseSqlServer(configuration["Data:DefaultConnection:ConnectionString"]);
    options.UseOpenIddict<MyApplication, MyAuthorization, MyScope, MyToken, long>();
});

version 4.8.0 doesn't have generic overload of AddOpenIddict<>() ? what should I do ?

broguyman commented 1 year ago

If you're like me and ran into this issue in 2023. The way I solved the problem was to use the overload that accepts an object instead of the OpenIddictApplicationDescriptor.

can you explain ?

I was talking about the CreateAsync method.

`await manager.CreateAsync(new MyApplication { ClientId = "blahblah",

ConsentType = OpenIddict.Abstractions.OpenIddictConstants.ConsentTypes.Explicit,
DisplayName = "AppName",
RedirectUris = JsonConvert.SerializeObject((new HashSet<Uri> {                        
    new Uri("https://localhost:1111/callback/renew"),
    new Uri("https://localhost:1111/callback/signin"),

})),
PostLogoutRedirectUris = JsonConvert.SerializeObject((new HashSet<Uri>
{
    new Uri("https://localhost:2222/callback/signout"),                        
}).ToArray()),
Permissions = JsonConvert.SerializeObject(new HashSet<string>
{
    OpenIddict.Abstractions.OpenIddictConstants.Permissions.Endpoints.Authorization,
    OpenIddict.Abstractions.OpenIddictConstants.Permissions.Endpoints.Logout,
    OpenIddict.Abstractions.OpenIddictConstants.Permissions.Endpoints.Token,
    OpenIddict.Abstractions.OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode,
    OpenIddict.Abstractions.OpenIddictConstants.Permissions.GrantTypes.RefreshToken,
    OpenIddict.Abstractions.OpenIddictConstants.Permissions.ResponseTypes.Code,
    OpenIddict.Abstractions.OpenIddictConstants.Permissions.Scopes.Email,
    OpenIddict.Abstractions.OpenIddictConstants.Permissions.Scopes.Profile,
    OpenIddict.Abstractions.OpenIddictConstants.Permissions.Scopes.Roles,                        
    OpenIddict.Abstractions.OpenIddictConstants.Permissions.Prefixes.Scope + "blahblah",
}),
Requirements = JsonConvert.SerializeObject(new HashSet<string>
{
    OpenIddict.Abstractions.OpenIddictConstants.Requirements.Features.ProofKeyForCodeExchange
}),
AppCode = "whatever app code".ToUpper(),

}, "GUID GOES HERE");`