jasontaylordev / CleanArchitecture

Clean Architecture Solution Template for ASP.NET Core
MIT License
16.63k stars 3.57k forks source link

[Feature Request] Adding Roles to Identity Server #56

Closed SuliemanMansouri closed 3 years ago

SuliemanMansouri commented 4 years ago

I am still new to Identity Server, still reading and exploring. I saw that there are roles that can be used to classify users. I don't know how to start that within this template and how to derive from my users in my domain.

My request is to include roles in the template. How to use them to restrict access to certain controllers or certain methods in a controller if possible. Show navigation items based on the user role. An example would be only an admin can register a user in the system, i.e issue login and password. While a user can only access items that does not include managerial duties.

Cheers

jasontaylordev commented 4 years ago

Greate suggestion Sulieman - I've added it to the roadmap. @notedchef is this something you are working on?

GFoley83 commented 4 years ago

I asked a similar question here: https://github.com/jasontaylordev/NorthwindTraders/issues/92#issuecomment-562359454

around the appetite for moving the auth logic out of Presentation (no [Authorize] attributes in controllers) , into the Application layer and what that approach might look like.

I do have a local branch for NorthwindTraders working that applies role checking as a pipeline behavior, by check if the current command request inherits from certain interfaces e.g. IRequiresAdminRights and making sure the current user has that role/claim. An alternative approach could be to extend the [Authorize] attribute to work with commands, similar to how the ABP project uses the [Authorize] attribute in the service layer.

Happy to help if there's a preferred approach.

Mat2001mat commented 4 years ago

@GFoley83 would you be able to share your implementation with us?

GFoley83 commented 4 years ago

Edit: this was an early stab at auth. See below for the preferred solution.

@Mat2001mat See here:

https://github.com/GFoley83/CleanArchitecture/commit/abe8c74c5fc010c74df5d3ac4256d8aef18b8493

This is an updated implementation for CleanArchitecture that supports adding and checking roles and/or claims via a behavior pipeline.

I've added the ability to:

For an example, run the solution, sign in with the default account and look at Weather Forecasts page and set breakpoints in RequestUserRoleBehavior.

One issue I couldn't resolve was support for both my approach above and using [Authorize] in controllers, so the later is currently broken (but to be fair, my approach is purely to address the fact that I don't want to use auth attributes anyway). I was playing wack-a-mole with ASP.NET Identity and IdentityServer startup config; every time I'd get one thing working, the other would break. I'm sure there's just some magic combo of certain config needed, I just couldn't find it.

@jasontaylordev if you're interested in the above approach, I'm happy to take some feedback, add a few tests etc. and open a PR.

iang0ld commented 4 years ago

In my opinion, the key issue that prevents this project from being the best Base EF Core Starter Template is Authentication and Authorisation. This would require

  1. Completion of the work done by @GFoley83, and
  2. The Addition of a complete Account Views with Forgotten Password (see Nucleus.Web.Vue/Src/Accounts/View in https://github.com/alirizaadiyahsi/Nucleus)

Are there any plans for these, if so any idea on timing?

jasontaylordev commented 4 years ago

Hi @iang0ld - they would great improvements. I'd like to focus on the testing first, but I might move onto those two next.

@GFoley83 I thought about implementing this too. I was considering creating a RequestAuthorizeAttribute to have a similar shape and structure to that of Authorize. Initial support would just be authenticated users. Then one or more roles. And whatever else proves useful, e.g. claims.

I don't know about timing to get these in, but I'll let you know when it's done. 😀

iang0ld commented 4 years ago

@GFoley83 FYI I will soon have extended Identity workflow adding to the project including Registration with email confirmation and forgotten email.

GFoley83 commented 4 years ago

Having been using the Auth pipeline behavior for a while now, I'm happy with the approach and feel it offers a lot more than using attributes for a few reasons:

Another approach that I have been playing with is implementing auth rules using the same style used for request command validation via FluentValidation, as a pure cross-cutting concern, with its own pipeline, separate from request command validation:

https://github.com/GFoley83/CleanArchitecture/tree/feature/auth-behavior

While my auth approach mentioned above uses a pipeline to implement auth rules and checking, it's not a cross-cutting concern as it relies on implementing an interface in the handler to enforce the required role. While this approach makes it clear that the handler requires that the user has certain permissions, it's not terribly flexible or customisable for complex scenarios such as having to checking multiple/different sources or providing customised error messages.

What I have currently looks like this:

AuthorisationBehavior:

public Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
    var validator = _validators.GetAuthValidator();

    if (validator == null)
    {
        return next();
    }

    if (string.IsNullOrEmpty(_currentUserService.UserId))
    {
        // API layer would return a 401 for this exception. See WebUI/Filters/ApiExceptionFilter.cs
        throw new AuthenticationException("User must be signed in.");
    }

    var context = new ValidationContext(request);

    var failures = validator
        .Validate(context)
        .Errors
        .Where(f => f != null)
        .ToList();

    if (failures.Count == 0)
    {
        return next();
    }

    // API layer would return a 403 for this exception. See WebUI/Filters/ApiExceptionFilter.cs
    throw new UnauthorizedAccessException(string.Join("", failures));
}

CreateTodoListAuthValidator:

public class CreateTodoListAuthValidator : AuthValidator<CreateTodoListCommand>
{
    public CreateTodoListAuthValidator(ILogger<CreateTodoListAuthValidator> logger,
        ICurrentUserService currentUserService,
        IIdentityService identityService) : base(logger, currentUserService)
    {
        RuleFor(v => v)
            .MustAsync(async (x, c) =>
            {
                var userIsInRoleResult = await identityService.UserIsInRoleAsync(currentUserService.UserId, Constants.UserRoles.GlobalAdmin);
                // var userHasClaim = await identityService.UserHasClaim(currentUserService.UserId, ClaimTypes.Role, Constants.UserRoles.GlobalAdmin);

                if (!userIsInRoleResult.Succeeded)
                {
                    logger.LogWarning($"User: {currentUserService.UserId} is not in role: {Constants.UserRoles.GlobalAdmin}.");
                    return false;
                }

                return userIsInRoleResult.Succeeded;
            })
            .WithMessage("User does not have permission to create todo lists.");
    }
}

I like this approach as it allows for a lot of flexibility, customisation and fits in with the existing style of the solution.

iang0ld commented 4 years ago

I agree that your method is more flexible that attributes. However, I prefer permission based authorization rather that role based. That way roles are simply used to manage the permissions and nothing else and the rest of the code doesn't care who you are.

GFoley83 commented 4 years ago

If by permissions you mean claims, then I agree that they are more useful than roles and easier to configure into the solution. The approach above supports that too. Just add a claim check method to the identityService:

https://github.com/GFoley83/CleanArchitecture/blob/feature/auth-behavior/src/Application/TodoLists/Commands/CreateTodoList/CreateTodoListAuthValidator.cs#L19

public async Task<Result> UserHasClaimAsync(string userId, string type, string value)
{
    var user = _userManager.Users.SingleOrDefault(u => u.Id == userId);

    if (user == null || !(await _userManager.GetClaimsAsync(user)).Any(i => i.Type == type && i.Value == value))
    {
        return Result.Failure(new[] { $"User: {userId} does not have claim: \"{type}\"." });
    }

    return Result.Success();
}

and then this:

var userIsInRoleResult = await identityService.UserIsInRoleAsync(currentUserService.UserId, UserRole.GlobalAdmin);

becomes this:

var userHasClaimResult = await identityService.UserHasClaimAsync(currentUserService.UserId, "CanCreateTodos", "true");

The point of the approach above is that the permission checking is up to you, per request; just like validation. It's supplementary, not an either/or. I could be calling AAD graph API for one command and checking local permissions for another. Just inject whatever services are required to check permissions, into your auth validator and that's it.

jasontaylordev commented 4 years ago

I've created an example of how an attribute-based approach might work - https://github.com/jasontaylordev/CleanArchitecture/commit/f97485b4e6a0dae35327e62606e07f611bd95d56. It includes tests. What do you think?

@GFoley83 some thoughts on the points you mentioned.

Attributes are harder to test. I don't normally just on this bandwagon but they are a bit of a pain. By using a pipeline for auth, adding tests is pretty straightforward.

What do you think of my tests? I think I have made it easy to test.

Attributes don't support dependency injection (or shouldn't be used that way is the common consensus)

I don't think this is going to be a blocker. The attributes will essentially just be a container for data. It is the behaviour that will have dependencies injected, and will perform authorization checks based on the attribute data. This is how the ASP.NET Core attribute works -https://github.com/aspnet/Security/blob/master/src/Microsoft.AspNetCore.Authorization/AuthorizeAttribute.cs.

Goes against the grain of the rest of the solution. Attributes aren't used anywhere else in the solution so it's another "thing" to get familiar with.

You're right. I think the tests will help a little. I'd also like to create a wiki for this template, something as detailed as the ABP sample.

Can't be used for complex scenario e.g. custom messages or validation rules.

Correct, I think this approach would work well for the simple scenarios, e.g. requires authorisation, user is in role, or use has claim.

We could then support complex cases with a custom approach or a policy (maybe? As per ASP.NET Core approach).

Most importantly, moves auth out of presentation into the application layer.

This is achieved in the sample I have provided.

Thanks all.

jasontaylordev commented 4 years ago

I've extended the sample by adding support for role-based authorization - https://github.com/jasontaylordev/CleanArchitecture/commit/573f3061e2b3b50ef5e2515b03e1a118602a1630.

Simple authorization is supported by applying the [Authorize] attribute to a command or query. For example:

[Authorize]
public class GetTodosQuery : IRequest<TodosVm> { }

The above query is accessible to any authenticated user.

Role-based authorization is supported by specifying the relevant role(s). For example, the following code limits the query access to members of the Admin role:

[Authorize(Roles = "Admin"]
public class GetTodosQuery : IRequest<TodosVm> { }

You can also specify multiple roles as a comma-separated list:

[Authorize(Roles = "Admin, SuperUser"]
public class GetTodosQuery : IRequest<TodosVm> { }

The above query would only be accessible by users who are a member of the Admin role or the SuperUser role.

If you apply multiple attributes then a user must be a member of all the roles specified:

[Authorize(Roles = "Admin")]
[Authorize(Roles = "SuperUser")]
public class GetTodosQuery : IRequest<TodosVm> { }

Only accessible to users who are a member of both the Admin role and the SuperUser role.

The above implementation is based on the ASP.NET Core implementation; https://docs.microsoft.com/en-us/aspnet/core/security/authorization/roles?view=aspnetcore-3.1#adding-role-checks. This should make it easier for users already familiar with the ASP.NET Core approach.

GFoley83 commented 4 years ago

Hi Jason. This looks awesome. I think using attributes on commands and queries makes a lot of sense when you're requirements around auth are of light to medium complexity, as it's very light weight and quick to implement. Whereas my approach above is a bit more code-heavy and involved and would be better suited to more complicated auth scenarios e.g checking for specific claims or validating against multiple/different identity providers.

I'll be taking a look at this over the weekend. Cheers.

iang0ld commented 4 years ago

Hi Guys,

I prefer the method of authorizing on permissions rather than roles as this gives focus to the feature and negates the need to check multiple roles. For added complexity I do that in the controller where it is easier to find and it it together with any settings related choices.

Jason is that something you would like to look at seeing as you have just completed it for Roles? If not I can have a go.

FYI I am currently testing the Identity Interface, including forgotten password, etc.

I will then be looking at Settings Management. Then Edition and Features. I use database per Client so I will implementing that as well. At that point there will be a complete base for SaaS .., and a Clean Architecture alternative to Boiler Plate. That's my aim.

Finally I am a huge fan of Vue. Jason I know you are too and were planning on a Vue alternative to Angular on the Front End. Is that something you are still looking to do.

ShreyasJejurkar commented 4 years ago

@jasontaylordev great work Jason as always.

But I didn't get the point why would we have authorization attribute and corresponding behavior on Queries and commands if we are restricting at the controller level itself.

Having the [Authorize] attribute in the Application layer will create a strong dependency of ASP.NET core identity in the application layer? And also another question, If the user has another attribute inhering Authorize attribute, will the behaviour will work?

taylorc commented 4 years ago

@MCCshreyas From my perspective the authorize attribute on the Controllers is to authenticate the user.

From a Clean Architecture perspective it is always good to move any application specific logic into application layer instead of keeping it in presentation, ex: if we were to re-package the application to be a console app or Desktop app or Job Scheduler app where we have to write all the security logic again for the presentation layer.

Having the [Authorize] attribute in the Application layer will create a strong dependency of ASP.NET core identity in the application layer?

I baulked at this one at first as well but I looked at the commit [573f306]. I found that Authorize attribute under "src/Application/Common/Security/AuthorizeAttribute.cs" file changes is an new attribute. Therefore there is no dependency as the Authorize attribute is a new attribute in the Application layer.

ShreyasJejurkar commented 4 years ago

@taylorc thanks for the commit link, which really helped me to understand. I got confused about the naming of the Authorize attribute, I thought it's coming from Identity.

taylorc commented 4 years ago

@MCCshreyas Happy to help

GFoley83 commented 4 years ago

Hi @jasontaylordev,

I've had a look at the auth attribute implementation and really like the simplicity of it. Couple of things came to mind while looking through the code:

E.g. so we could do something like:

    [Authorize(Roles = "Admin")]
    [Authorize(ClaimType = "MarketingTeamMember", ClaimValue = "true")]
    public class GetTodosQuery : IRequest<TodosVm>

As you have already done the hard work with the AuthorizationBehaviour pipeline.

The only thing I don't really like about this approach (which is what I address with my own solution above) is that it only works for simple use-cases e.g. values known ahead of time.

If you need to do any type of dynamic checking for a specific request e.g. querying a Db or requesting data from some other API, to make a decision on if a request is authorised to continue, then you'll need to role a custom solution.

Personally, I think there's room for both approaches in CleanArchitecture.

pcarvsilva commented 4 years ago

What about removing the attributes using bitmask enums ?

Each sollution could make it own claims

   [Flags]
public enum Claims
{
    None = 1 << 0,
    OneClaim= 1 <<1,
    AnotherClaim = 1 << 2,
    OtherClaims = 1 << 3,
    IsLogged = 1 <<4
}

Extend the request class so commands could use it

    public class IAuthorizationRequiredRequest<T>: IRequest<T>
    {
        public abstract virtual Claim requiredClaims{get;};
    }

Insert in the commad the claims necessary for it

    public class CreateTodoItemCommand : IAuthorizationRequiredRequest<int>
    {
        public int ListId { get; set; }
        public string Title { get; set; }
        public Claim requiredClaims{ get Clam.IsLogged & Claim.OneClaim }

    }

And then add a pipeline authorization like so ...

public class RequestAuthorizationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
 {
    public Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
        {
            if (someservice.checkClaims(request.requiredClaims) == false)
            {
                  throw new AuthorizationFailedException();
            }

            return next();
        }
 }

This would make the command really easy to test the authorization, and also would make it great in the case you are using the same user database in different sollutions but different claims

Also if you have to use a claim that needs to be implemented in some other way like a geolocalization claim, you could make it on your infrastructure code and It would work fine.

Testing would be simple since you just have to mock the service to return the same Claim as your command Claim.You could also mock it to test the AuthorizationBehaviour and it sould be fine.

P.S: Sorry for bad coding i'm without an IDE right know

GFoley83 commented 4 years ago

Love the idea of being able to use bitwise enums as it makes sense but not a fan of extending the IRequest<T> interface. I touched on this above and there's a similar discussion in an open caching PR that also proposes extending the IRequest<T> interface. The general rule is, if something is a cross-cutting concern, then you should not be aware of it inside your application or business logic, otherwise it stops being a cross-cutting concern. So typically that means auth, caching, validation, exception handling, auditing, Db resiliency etc.

pcarvsilva commented 4 years ago

What about making a service with a strategy that reads from the claim ?

Use it like that in your command

    [Authorize(Roles = "Admin")]
    [Authorize(ClaimType = "MarketingTeamMember", ClaimValue = "true")]
    [AuthorizeStrategy("CheckWithDB")]
    public class GetTodosQuery : IRequest<TodosVm>

This class reads the command and selects the attributes strategies

  class AuthorizationService<T> : where T : Command{
         Dictionary<string,IAuthorizationStrategy<T>>

         public void Authorize<T>{
                     //raises exc if wrong
        }
  }

  interface IAuthorizationStrategy<T>{
        void Authorize<T>(){ }
  }

Just extend it on Infrastructure/Identity/CustomAuthorizationStrategies and inject dependencies on Infrastructure/Identity/DependencyInjection.cs

flensrocker commented 4 years ago

I think you can omit the string splitting stuff with something like this:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public class AuthorizeAttribute : Attribute
{
    public AuthorizeAttribute(params string[] roles)
    {
        Roles = roles;
    }

    public IReadOnlyList<string> Roles { get; private set; }
}

[Authorize("Admin", "SuperUser")]

It depends if you want to extend this attribute with other properties like claims or policies or if you split them in "single responsiblity" attributes, like AuthorizeRoles, AuthorizePolicy, AuthorizeClaims etc.

This is also possible and leads to cleaner code, even if the user has to type a bit more:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public class AuthorizeAttribute : Attribute
{
    public AuthorizeAttribute()
    {
    }

    public string[] Roles { get; set; } = Array.Empty<string>();
}

[Authorize(Roles = new[] { "Admin", "SuperUser" })]

The first variation has the benefit of being immutable.

altumcon commented 4 years ago

How to Protect Routes Based on User Role in ClientApp

nixonad commented 4 years ago

@GFoley83 : For completeness, do you have an implementation of GetAuthValidator referenced in your solution above? I think your strategy with authorization is ideal, I've never quite got why hardcoding your roles in code is a good/acceptable thing to do. This strategy lets me implement role/claims/permission checks in any way I need to without modifying any of the plumbing.

In implementing this, I've found the AuthValidationBehaviour and the normal RequestValidationBehaviours both execute, and the 'normal' validation executes the AuthValidation since all are AbstractValidators. The Exception thrown means that this is not really a problem but ideally we'd want the AuthValidationBehaviour to execute first, then the normalValidations. I've also had to introduce some extra checks to prevent the authvalidation from executing a second time. Not quite as clean a solution as I'd hoped for. Continuing to improve it, but if you've encountered and/or solved these before I'd appreciate any advice.

Did you also extend ApiExceptionFilter to intercept the UnauthorizedAccessException?

Thanks

GFoley83 commented 4 years ago

@nixonad Yes. Just see my branch here for a full working example: https://github.com/GFoley83/CleanArchitecture/tree/feature/auth-behavior

It's up to date with the latest version of master, as of time of writing.

To test, just checkout, start debug, create a new user and try adding a Todo list to see the failure below. The built in administrator account has the correct role/claim to add a Todo list.

image

I just use extension methods on to find the auth or command validators by checking for the IAuthValidator interface.

This strategy lets me implement role/claims/permission checks in any way I need to without modifying any of the plumbing.

Exactly right. This was my main goal when trying to come up with an auth strategy.

o-l-i-g commented 4 years ago

I am hoping to get some guidance. I've spent a week watching videos and reading a ton trying to understand and I'm not quite there yet.

I've been trying to port my code into this architecture and I finally tried to start last week. First of all, huge kudos to @jasontaylordev and @GFoley83 on the contributions and explaining things on this repository / thread. If I had the knowledge I wish to contribute one day!

What I'm trying to achieve, is to make the Authentication API work without using SPA but also using the [Authorize] attribute in the application layer as suggested by Jason. I want to do this because I have close to no knowledge in SPA, nor IdentityServer4, and I am familiar with the use of [Authorize] attributes on controllers from the little ASP.NET Core knowledge I do have. It's been a heavy week of reading I tell you!

It would be great if I can ask for some guidance. I think I'm just a bit lost, I'm half way re-implementing login flow from scratch and having major doubts about my strategy.

1) As per the template I have not changed the IdentityServer4 configuration so I have it defined in appsettings.json to SPA profile. But I have removed SPA for the moment. Do I need to change that? I want to primarily use Mobile app to communicate with the API. 2) If the Authorization is happening in the Application layer, is IdentityServer4 still needed? 3) How 'sensible' is it for me to create a User entity, and re-implement register, login, logout, forgot password type of usecases in the application layer? If I were to do so, would I no longer need IdentityServer4?

Sorry for the long post!

GFoley83 commented 4 years ago
  1. Yes, you can delete the ClientApp folder and remove the SPA references if you just plan on using the solution as an API.
  2. Yes. IdentityServer4 is your OpenID Connect provider. If you want to use auth with your application e.g. JWTs then you're going to need to use something to do this.
  3. Not sure what you're trying to accomplish sorry or why you'd want to reimplement login, logout etc yourself. Sounds a bit like reinventing the wheel. I think you should first spend some time understanding what IdentityServer is before continuing any further with that.
o-l-i-g commented 4 years ago

Thanks @GFoley83 I got a new motivation to stick with IdentityServer4! Really appreciate the time you took to answer.

This video from Xamarin University helped me figure some of the missing pieces I didn't get from my initial reading on documentation from Microsoft or IdentityServer4's own tutorials for my intended use cases;

I'm definitely not married with the idea of re-writing login/logout etc endpoints, I certainly didn't enjoy it and I might even drop it (although I do have most of it working). In case you wanted to know why I'm doing probably something insane, my end goal is to have WebUI using RazorPages, together with WebAPI for mobile App all working with ASP.NET Identity in one solution. SPA using React is something we're interested down the line so I wanted to provision for that too if possible.

It's not entirely clear in my head yet, but my understanding is that I needed a login page in the WebUI to direct the user to ask the user for login details. So I started with the template here, removed SPA folder and various references, added Jason's changes for Role based authentication, and added the Asp.Net Identity's default UI for login/logout etc. Then I realised API needs endpoints too to authenticate users for the mobile app, which lead to how would that work with IdentitySever4 - and I was lost. I was extra lost from the error messages I got from changing the profile name of IdentityServer4 in appsettings.json as well.

I was hopelessly lost with how to go about that with IdentityServer4 involved, so I went down the route of 'do what you know', which lead to implementing my own MVC AuthController and Commands/Queries with the aforementioned user flows ignoring IdentityServer4. I was pretty happy because I now have integration tests working in the Application Layer covering basic security concerns.

Sorry this post really got long, but that's 'why' I was trying to reinvent the wheel!

Anyway, now that I know I should be directing users to the browser login page hosted by the webapp - even in the API consuming mobile app client scenario - I think I'm more content with how IdentityServer4 is intended to work. I like what IdentityServer4 offers and I will be trying to make this work probably for the next week!

Thanks

AlaaL commented 4 years ago

Hi @GFoley83 i am using your approach to add roles to the current solution, but i also want to implement custom roles and claims CRUD. So i created a UI to list the avilable roles and i can add, delete or modify roles, my problem is when reading the roles using RoleManager i am getting this error:

Cannot create a DbSet for 'ApplicationRole' because this type is not included in the model for the context.

And i couldn't find the source of the problem.

This my DependencyInjection class `public static class DependencyInjection { public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration, IWebHostEnvironment environment) { services.AddDbContext(options => options.UseSqlServer( configuration.GetConnectionString("DefaultConnection"), b => b.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName)));

        services.AddScoped<IApplicationDbContext>(provider => provider.GetService<ApplicationDbContext>());

        services
            .AddDefaultIdentity<ApplicationUser>(options =>
            {
                // Basic built in validations
                options.Password.RequireDigit = false;
                options.Password.RequireLowercase = false;
                options.Password.RequireNonAlphanumeric = false;
                options.Password.RequireUppercase = false;
                options.Password.RequiredLength = 6;
            })
            .AddRoles<ApplicationRole>()
            .AddRoleManager<RoleManager<ApplicationRole>>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();

        services.AddIdentityServer()
            .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();

        services.AddTransient<IDateTime, DateTimeService>();
        services.AddTransient<IIdentityService, IdentityService>();
        services.AddTransient<ICsvFileBuilder, CsvFileBuilder>();

        services.AddAuthentication()
            .AddIdentityServerJwt();

        return services;
    }
}`

And in the IdentityService class i added RoleManager like this:

` public class IdentityService : IIdentityService { private readonly UserManager _userManager; private readonly RoleManager _roleManager;

    public IdentityService(UserManager<ApplicationUser> userManager, RoleManager<ApplicationRole> roleManager)
    {
        _userManager = userManager;
        _roleManager = roleManager;
    }`

And a method GetAllRoles() : ` public async Task GetAllRoles() { RolesListDto listDto = new RolesListDto();

        var roles = _roleManager.Roles;

        listDto.Roles = await (from r in roles
                               select new RoleVM()
                               {
                                   Id = r.Id,
                                   Name = r.Name
                               })?.ToListAsync();

        return listDto;
    }`

I am getting the exception in roleManager.Roles; line.

I am so sorry if this is not the right place to post this issue but this is my first post in github :)

GFoley83 commented 4 years ago

It's most likely because you're using ApplicationRole and not IdentityRole and you didn't add a Db migration. By default IdentityRole is added to the Db: https://github.com/GFoley83/CleanArchitecture/blob/master/src/Infrastructure/Persistence/Migrations/ApplicationDbContextModelSnapshot.cs#L247

If you've no custom properties on ApplicationRole just change it to be IdentityRole and see if it works. Otherwise, you probably need to add a Db migration.

AlaaL commented 4 years ago

@GFoley83 Thank you greatly, It worked after using IdentityRole, but when i was using ApplicationRole i deleted all the migration files and snapshot and regenerated them and dropped the database and recreated it with new migration still didn't work. I dont' have custom properties right now but i thought i can prepare it for future use. Anyway thank you for your help and your awesome implementation for this feature.

ramax495 commented 4 years ago

@jasontaylordev Will these features be implemented in this template ?

jasontaylordev commented 4 years ago

@jasontaylordev Will these features be implemented in this template ?

Yes, sorry for the delay. Just put through a pull request now.