Skip to content

Extensible authorization manager for Dotnet Core

Notifications You must be signed in to change notification settings

KazooDotNet/AuthMan

Repository files navigation

AuthMan

An extensible, code policy-based authorization manager for DotNet Core.

Install

Install the AuthMan and Microsoft.AspNetCore.Session nuget packages. Sessions are required to persist state.

Setup

In the standard Kestrel Startup.cs file, add something similar to the following code:

public Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services
            .AddDistributedMemoryCache();
            .AddSession()
            .AddAuthMan(opts => {
                opts.AuthManClass<IAuthMan>() // optional, defaults to using AuthMan.AuthMan
                opts.AddUserAuth<IUserMan, User>();
            });
    }

    public void Configure(IApplicationBuilder app)
    {
        app
	.UseSession()
	.UseAuthMann();
    }
}

IAuthMan can be anything that implements the IAuthMan interface. Same thing goes for IUserMan. User in the example above is your user model. You can subclass AuthMan (which implements IAuthMan) if you wish to add some convenience methods, or just remove the AuthManClass method to use the default.

Usage

The middleware (added by UseAuthMan() above), puts an instance of IAuthMan in the Items property of HttpContext. The key is authMan. Example:

var authMan = (AuthMan) httpContext.Items["authMan"];

How you get the HttpContext depends on the framework that you're using. For DotNet Core middleware, it is passed to the Invoke method.

To see if any authentication methods succeeded, use authMan.Authenticated().

If you need anything finer grained than that, you will need to implement policies. All policies must implement IPolicy. There's a convenience class you can inherit from called PolicyBase, which will handle a Before() => bool? method and the named method passed to Handle. Inheriting from PolicyBase allows you to do this:

public class UserPolicy : PolicyBase
{
    public bool? Before()
    {
        if (user.isSuperAdmin) return true; // True or false does not call the requsted method for authorization.
        return null; // Null values will call the requested method for authorization.
    }

    public async Task<bool> Read(int userId)
    {
        // retrieve the record do some logic...
        return canReadUser; // true or false
    }

}

// In some method somehwere
authMan.Authenticate<UserPolicy>("Read", user.Id); // will throw Exceptions.NotAuthorized if the policy returns false

// If you don't want it to throw an error, you can use `Can`:
if (authMan.Can<UserPolicy>("Read", user.Id)) {
    // Do stuff here.
}

You can also set up data scopes depending on the authenticated method if you like. Policies use dependency injection to resolve services.

public class AccountPolicy : PolicyBase
{
    private DbContext _dbContext;

    public Account(DbContext context) => _dbContext = context;

    public IQueryable<Data.Account> Scope()
    {
      if (SuperAdmin) // Implement your own logic for checking access and current user
        return _dbContext.Accounts;
      return from a in _dbContext.Accounts
        join au in _dbContext.AccountUsers on a.Id equals au.AccountId
        where CurrentUser.Id == au.UserId  
        select a;
    }
}

// In some method somewhere

var accounts = await authMan.Scope<AccountPolicy>().ToListAsync();

You can add arguments to YourPolicy#Scope() if you need them. Pass those arguments to authMan.Scope<>().

Extending

You don't have to use AddUserAuth. You can create your own by implenting IAuthenticate and then calling AddAuth<IAuthenticate>() like so:

public Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.Authentication<IAuthMan>(opts => {
            opts.AddAuth<MyCustomAuthClass>();
        });
    }
}

About

Extensible authorization manager for Dotnet Core

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages