Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EFCore persistence #17

Closed
thoraj opened this issue Mar 7, 2021 · 10 comments
Closed

EFCore persistence #17

thoraj opened this issue Mar 7, 2021 · 10 comments
Assignees
Labels
question Further information is requested

Comments

@thoraj
Copy link
Contributor

thoraj commented Mar 7, 2021

Can the aspnet core middleware be configured to use EFCore instead of files to persist policy?

@hsluoyz
Copy link
Member

hsluoyz commented Mar 7, 2021

@sagilio

@hsluoyz hsluoyz self-assigned this Mar 7, 2021
@hsluoyz hsluoyz added the question Further information is requested label Mar 7, 2021
@sagilio
Copy link
Member

sagilio commented Mar 7, 2021

Yes, you can implement a custom IEnforcerProvier like this:

public class CustomEnforcerProvider : IEnforcerProvider
{
    private readonly ICasbinModelProvider _modelProvider;
    private readonly CasbinDbContext<Guid> _casbinDbContext;
    private Enforcer _enforcer;

    public CustomEnforcerProvider(ICasbinModelProvider modelProvider, CasbinDbContext<Guid> casbinDbContext)
    {
        _modelProvider = modelProvider;
        _casbinDbContext = casbinDbContext;
    }

    public Enforcer GetEnforcer()
    {
        _enforcer ??= new Enforcer(_modelProvider.GetModel(), new EFCoreAdapter<Guid>(_casbinDbContext));
        return _enforcer;
    }
}

And add service in Startup.cs like this:

//Add Casbin Authorization
services.AddDbContext<CasbinDbContext<Guid>>(options => options.UseSqlite("Data Source=CasbinSample.db"));
services.AddScoped<IEnforcerProvider, CustomEnforcerProvider>();
services.AddCasbinAuthorization(options =>
{
    options.PreferSubClaimType = ClaimTypes.Name;
    options.DefaultModelPath = Path.Combine("CasbinConfigs", "basic_model.conf");
});

I think we can provide a quick way to configure EFCore Adapter later.

@thoraj
Copy link
Contributor Author

thoraj commented Mar 8, 2021

Thanks,
I noticed that it is possible to register a DefaultEnforcerFactory, and tried this:

            //Add Casbin Authorization
            services.AddCasbinAuthorization(options =>
            {
                options.PreferSubClaimType = ClaimTypes.Name;
                options.DefaultModelPath = Path.Combine("CasbinConfigs", "basic_model.conf");
//                options.DefaultPolicyPath = Path.Combine("CasbinConfigs", "basic_policy.csv");
                options.DefaultRequestTransformer = new CustomRequestTransformer();

                options.DefaultEnforcerFactory = model =>
                {
                    return new Enforcer(model, new DefaultFileAdapter(Path.Combine("CasbinConfigs", "basic_policy.csv")));
                };
            });

Is there a reason not to use the factory method as above instead of using a custom enforcer provider?

@sagilio
Copy link
Member

sagilio commented Mar 8, 2021

Because the EF Core Adapter needs a dbcontext which is a scope lifetime service. Use DefaultEnforcerFactory may can not get an IServiceProvider to create scope and resolve the dbcontext.
But we can change the DefaultEnforcerFactory to Func<IServiceProvider, ICasbinModel, Enforcer> to fix this problem.

@thoraj
Copy link
Contributor Author

thoraj commented Mar 10, 2021

I will try creating a custom enforcer provider as you suggest. (Although it is probably a good idea to make the changes to DefaultEnforcerFactory also as this is a natural place to customize this).

@sagilio
Copy link
Member

sagilio commented Mar 11, 2021

Now DefaultEnforcerFactory can get the IServiceProvider, you can use it like this:

services.AddDbContext<CasbinDbContext<Guid>>(options => options.UseSqlite("Data Source=CasbinSample.db"));
//Add Casbin Authorization
services.AddCasbinAuthorization(options =>
{
    options.PreferSubClaimType = ClaimTypes.Name;
    options.DefaultModelPath = Path.Combine("CasbinConfigs", "basic_model.conf");

    options.DefaultEnforcerFactory = (p, m) =>
        new Enforcer(m, new EFCoreAdapter<Guid>(p.GetRequiredService<CasbinDbContext<Guid>>()));
});

@thoraj
Copy link
Contributor Author

thoraj commented Mar 11, 2021

Excellent. Thank you.

We need the casbin database updates to share transaction with updating other parts of the database, so we will check out the best way to handle the CasbinDbContext lifecycle

@sagilio sagilio closed this as completed Mar 11, 2021
@VerdonTrigance
Copy link

Can we pin this somewhere in the wiki? I guess many of us wants to know how to use it with EF.

@hsluoyz hsluoyz pinned this issue Dec 8, 2021
@hsluoyz
Copy link
Member

hsluoyz commented Dec 8, 2021

@sagilio can we add this to README?

@sagilio
Copy link
Member

sagilio commented Dec 9, 2021

@hsluoyz @VerdonTrigance
Ok. In fact, I think we should provide a more simple way to use IAdapter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

4 participants