Implement permissions on a REST API Asp.net core 2.0

Asked

Viewed 447 times

0

I am implementing an API in ASP.NET Core 2.0 in which I need to implement permissions, but the forms I found (Roles, Claims, Policies) left me very confused, because the permissions structure I need is much simpler than the ones presented.

In my model I have two classes, the User class and the Permissions class, in which they have a relationship N to N.

What do I want? Simply Register each permission from the Permissions table (Ex: "Register User", "Delete Product", "Approve Request") and attach to each user the necessary permissions for it and with this, my API would check in the database the user’s permission according to an actionresult of my controller.

Something like:

[hasPermission("CadastrarUsuario")]
public ActionResult Post([FromBody] Usuario usuario)
{
     ...
     ...
}

Someone has done something similar, or has an idea of how I can do this, being using Identitycore or another method?

  • Don’t get it, what the Identity roles don’t suit you? you want to build a Mobile from scratch?

  • I didn’t find a clear way of how I would do this by registering permissions in the database. Because I will have administrator users who will assign and remove permissions from other users registered on the system. I’m actually kind of lost in it. How I would make the relationship of registered users with the roles registered in the bank using Identity?

1 answer

0


With some research and a lot of reading I was able to solve my problem and implement Identity in my API.

First you need to change the inheritance of the context class from "Dbcontext" to "Identitydbcontext"

public class Context : IdentityDbContext<ApplicationUser, ApplicationRole, int>
{
    ...
    ...
}

Next you need to Create an Entity to Inherit from the Identityuser class that represents the users in which they will be used for authentication and an Entity that inherits from the Identityrole class that represents the Roles.

public class ApplicationUser : IdentityUser<int>
{
     ...
     ...
}

public class ApplicationRole : IdentityRole<int>
{
    ...
    ...
}

With these implementations, when creating Migration, you will create the script that implements the Identity tables. After updating the database, the Identity tables were created

inserir a descrição da imagem aqui

After this, in the authentication method I had to load the user roles that I am currently authenticating and assign to an object of the Claimsidentity class. The following is part of the implementation of my authentication class.

private IApplicationUserRepository _repository;
    private SigningConfigurations _signingConfigurations;
    private TokenConfiguration _tokenConfiguration;
    private SignInManager<ApplicationUser> _signInManager;
    private UserManager<ApplicationUser> _userManager;

    public ApplicationUserBusinessImpl(IApplicationUserRepository repository, 
                                        SigningConfigurations signingConfigurations, 
                                        TokenConfiguration tokenConfiguration,
                                        SignInManager<ApplicationUser> signInManager,
                                        UserManager<ApplicationUser> userManager)
    {
        _repository = repository;
        _signingConfigurations = signingConfigurations;
        _tokenConfiguration = tokenConfiguration;
        _signInManager = signInManager;
        _userManager = userManager;
    }

    public object Login(ApplicationUser applicationUser)
    {
        if (applicationUser != null && !string.IsNullOrWhiteSpace(applicationUser.Email))
        {
            var userIdentity = _userManager
                .FindByEmailAsync(applicationUser.Email).Result;

            if (userIdentity != null)
            {
                var credentialsIsValid = _signInManager
                   .CheckPasswordSignInAsync(userIdentity, applicationUser.PasswordHash, false)
                   .Result;

                if (credentialsIsValid.Succeeded && userIdentity.Ativo)
                {
                    ClaimsIdentity identity = new ClaimsIdentity(
                            new GenericIdentity(applicationUser.Email, "Email"),
                            new[]
                            {
                        new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString("N")),
                        new Claim(JwtRegisteredClaimNames.UniqueName, userIdentity.UserName)
                            }
                    );

                    //Carregando as permissões do usuário para ser incorporado ao token
                    var roles = _userManager.GetRolesAsync(userIdentity).Result;

                    foreach (string role in roles)
                    {
                        identity.AddClaim(new Claim(ClaimTypes.Role, role));
                    }

                    DateTime createDate = DateTime.Now;
                    DateTime expirationDate = createDate + TimeSpan.FromSeconds(_tokenConfiguration.Seconds);

                    var handler = new JwtSecurityTokenHandler();

                    string token = CreateToken(identity, createDate, expirationDate, handler);

                    return SuccessObject(createDate, expirationDate, token);
                }
                else
                {
                    return ExceptionObject();
                }
            }

        }
        return ExceptionObject();
    }

    private string CreateToken(ClaimsIdentity identity, DateTime createDate, DateTime expirationDate, JwtSecurityTokenHandler handler)
    {
        var securityToken = handler.CreateToken(new SecurityTokenDescriptor
        {
            Issuer = _tokenConfiguration.Issuer,
            Audience = _tokenConfiguration.Audience,
            SigningCredentials = _signingConfigurations.SigningCredentials,
            Subject = identity,
            NotBefore = createDate,
            Expires = expirationDate
        });

        var token = handler.WriteToken(securityToken);

        return token;
    }

    private object ExceptionObject()
    {
        return new
        {
            atenticated = false,
            message = "Falha na autenticação"
        };
    }

    private object SuccessObject(DateTime createDate, DateTime expirationDate, string token)
    {
        return new
        {
            atenticated = true,
            created = createDate.ToString("yyyy-MM-dd HH:mm:ss"),
            expiration = expirationDate.ToString("yyyy-MM-dd HH:mm:ss"),
            accessToken = token,
            message = "OK"
        };
    }

To test authentication, I created a class to insert some initial information into the API database.

public class IdentityInitializer
{
    private readonly Context _context;
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly RoleManager<ApplicationRole> _roleManager;

    public IdentityInitializer(
        Context context,
        UserManager<ApplicationUser> userManager,
        RoleManager<ApplicationRole> roleManager)
    {
        _context = context;
        _userManager = userManager;
        _roleManager = roleManager;
    }

    public void Initialize()
    {

        GenerateRoles();

        CreateUser(
            new ApplicationUser()
            {
                UserName = "Administrador",
                Email = "[email protected]",
                EmailConfirmed = true
            }, "Admin123!", "Administrador");

    }

    /// <summary>
    /// Método para gerar todas as roles do sistema
    /// caso elas ainda não existam dentro do banco de dados
    /// </summary>
    private void GenerateRoles()
    {
        //método para registrar todas as roles do sistema
        List<string> roles = new List<string>();

        //Listagem de todas as roles da API!
        roles.Add("Administrador");
        roles.Add("CadastrarUsuario");

        foreach (string role in roles)
        {
            if (!_roleManager.RoleExistsAsync(role).Result)
            {
                var resultado = _roleManager.CreateAsync(
                    new ApplicationRole
                    {
                        Name = role
                    }).Result;
                if (!resultado.Succeeded)
                {
                    throw new Exception($"Erro durante a criação da role {role}.");
                }
            }
        }
    }

    private void CreateUser(
        ApplicationUser user,
        string password,
        string initialRole = null)
    {
        if (_userManager.FindByNameAsync(user.UserName).Result == null)
        {
            var resultado = _userManager
                .CreateAsync(user, password).Result;

            if (resultado.Succeeded &&
                !String.IsNullOrWhiteSpace(initialRole))
            {
                _userManager.AddToRoleAsync(user, initialRole).Wait();
            }
        }
    }
}

To restrict access to a particular controller in my API, I added the following attribute in the controller header

[Authorize("Bearer", Roles = "Administrador")]

With this it was possible to access the endpoints of my api with the roles of Identity Core

References

ASP.NET Core 2.0: JWT + Identity Core in API authentication

Authorization in ASP.Net Core Apis

Browser other questions tagged

You are not signed in. Login or sign up in order to post.