1

I am trying to restrict access to my controller's methods, through roles, in the traditional way, the complete controller rejects the authentication of roles for all users of all roles

Authorize Attribute with Multiple Roles

     using MBC.ServiciosUtilidad.CatalogoUS.Implementacion;
     using MBC.ServiciosEntidad.ReportesDmsES.Implementacion;
     using System.Web.Mvc;
     using MBC.Models.ReportDms;
     using PagedList;
     using System.Data;
     using System.Linq;
     using MBC.ModeloCanonico.Constantes;
     using System.Web.Security;
     using static MBC.ModeloCanonico.Constantes.CatalogoConstante;

  namespace MBC.Controllers.Report.Vehiculos
 {
[Authorize]
//[Authorize(Roles = CatalogoConstante.Rol.Administrador)]
public class ReportDmsVehiculosController : MasterController
{
    private readonly ICatalogoUSContract _servicioCatalogo;
    private readonly IReportesDmsESContrato _servicioReportesDms;

    //CONSTRUCTOR

    public ReportDmsVehiculosController()
    {
        _servicioCatalogo = new CatalogoUSImplementacion();
        _servicioReportesDms = new ReportesDmsESImplementacion();
    }
    //[Authorize(Roles = CatalogoConstante.Rol.Administrador)] 
    [AuthorizeRoles(Rol.Administrador)]
    public ActionResult ReportDmsVehiculos()
    {
        return View();
    }
}

namespace MBC.ModeloCanonico.Constantes
{
    public static class CatalogoConstante
    {
    public struct Rol
    {
        public const string Administrador = "Administrador";
        public const string RecursosHumanos = "Recursos Humanos";

    }

}

This is the login () with a return message, 'access denied'

public ActionResult Login()
{
    //if (User.Identity.IsAuthenticated)
    if (User.IsInRole("ProvideASpecificRoleHere"))
        return RedirectToAction("Index", "Home");

    if (User.Identity.IsAuthenticated)
        ModelState.AddModelError("", "Acceso Denegado.");
    return View();
}

for some reason he keeps sending me to: RedirectToAction ("Index", "Home"), This should only happen at the start

[HttpPost]
    public ActionResult Login(LoginModel model)
    {
        if (User.Identity.IsAuthenticated)
        {
            return RedirectToAction("Index", "Home");
        }
        UserRol userRol = new UserRol();
        userRol.user = _serviceUsuario.ValidarCredencialesRol(model.Usuario, model.Contrasena);
        if (userRol.user != null)
        {
            model.Roles = userRol.user.Roles;
            FormsAuthentication.SetAuthCookie(model.Usuario, false);
            ((ClaimsIdentity)HttpContext.User.Identity).AddClaim(new Claim(ClaimTypes.Role, model.Roles));
            var authTicket = new FormsAuthenticationTicket(1, model.Usuario, DateTime.Now, DateTime.Now.AddMinutes(20), false, model.Roles);
            string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
            var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
            HttpContext.Response.Cookies.Add(authCookie);

            return RedirectToAction("Index", "Home");
        }
        else
        {
            ModelState.AddModelError("", "Invalid login attempt.");
            return View(model);
        }
    }
    protected override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        base.OnActionExecuted(filterContext);
        UsuarioLogueado();
    }

This is the verification function of the registered user. This class is used to obtain the information of the logged in user, to use as an audit and to show some data in the view.

    protected void UsuarioLogueado()
    {
        try
        {
            if (User.Identity.IsAuthenticated)
            {                   
                var usuarioLogueado = Session["UsarioEntityModel"] as UsarioEntityModel;
                if (usuarioLogueado == null)
                {
                    usuarioLogueado = _userService.ObtenerUsuarioLogueado(User.Identity.Name).ToUsarioEntityModel();
                    ((ClaimsIdentity)HttpContext.User.Identity).AddClaim(new Claim(ClaimTypes.Role, usuarioLogueado.Rol));
                    Session["UsarioEntityModel"] = usuarioLogueado;
                }
                ViewBag.usuarioLogueado = usuarioLogueado;
            }
            else
            {
                Session["UsarioEntityModel"] = null;
            }
        }
        catch (AggregateException ex)
        {
            throw ex;
        }
    }
  • Question is not clear, as per provided code action method "ReportDmsVehiculos" is accessible to user having role "Administrador". – Ashish Mishra Dec 30 '18 at 06:48
  • That is exactly what does not work, it is blocked for all users, now I have to leave it without a specific role. –  Jan 02 '19 at 13:43
  • Please try with [Authorize("Administrador") instead of [AuthorizeRoles(Rol.Administrador)] and see if it works. Not sure about AuthorizeRoles class. Please also share your AuthorizeRoles class, may be some thing has been missed out in that class. – Ashish Mishra Jan 02 '19 at 14:42
  • That was my first option but it does not work. –  Jan 02 '19 at 16:24
  • When the user logs in, how do I identify the role, with which is it authenticated? –  Jan 03 '19 at 14:06
  • You can check if role is in list of logged in user by : Request.HttpContext.User.IsInRole("rolename") It will return you true or false. Alternatively you can retrieve the claim Request.HttpContext.User.Claims – Ashish Mishra Jan 03 '19 at 15:48
  • `This should only happen at the start` What do you mean by `at the start`? – mjwills Jan 04 '19 at 04:18
  • No need to add claims in this case, Please see the solutions in below answer. https://stackoverflow.com/questions/53972268/how-to-authorize-a-method-from-one-controller-to-one-role-or-multiple-roles-with/54026150#54026150 – Ashish Mishra Jan 04 '19 at 06:05
  • @Maurico Bello: Please do not edit asked question multiple time as it may create confusion. Please be clear and crisp with your issues. Ask seperate question for different issues. – Ashish Mishra Jan 05 '19 at 16:01

2 Answers2

2

As per provided code your adding Roles in user data of authentication ticket (Last Parameter of new FormsAuthenticationTicket(). This user data can be utilized.

By default FormsAuthenticationTicket works with "Users" not with "Roles" so attribute [Authorize(Users = "model.Usuario")] will work but [Authorize(Roles= "Adminstrador")] will give you Unauthorized.

To work with roles you need to add roles in HttpContext.User from AuthTicket. Add below method in your controller:-

protected override void OnAuthorization(AuthorizationContext filterContext)
        {
            if (filterContext.HttpContext.User != null)
            {
                if (filterContext.HttpContext.User.Identity.IsAuthenticated)
                {
                    if (filterContext.HttpContext.User.Identity is FormsIdentity)
                    {
                        FormsIdentity id = (FormsIdentity)HttpContext.User.Identity;
                        FormsAuthenticationTicket ticket = id.Ticket;
                        string userData = ticket.UserData;
                        string[] roles = userData.Split(',');
                        HttpContext.User = new GenericPrincipal(HttpContext.User.Identity, roles);
                    }
                }
            }
        }

You can also create Authorization filter for same so that same can be used across your application.

If you override OnAuthorization, AuthorizeCore and HandleUnauthorizedRequest methods in your custom authorization class, then it will call OnAuthorization method, then if you call base.OnAuthorization(filterContext) method in overriden OnAuthorization method, then it will call AuthorizeCore method, if that return false, then it will call HandleUnauthorizedRequest method.

Ashish Mishra
  • 667
  • 7
  • 14
  • I tried but it does not work, for some reason it sends me to: RedirectToAction ("Index", "Home"), This should only happen at Start. –  Jan 03 '19 at 23:01
  • I just added some changes to the first code that I published. –  Jan 03 '19 at 23:13
  • ((ClaimsIdentity)HttpContext.User.Identity).AddClaim(new Claim(ClaimTypes.Role, model.Roles)); I use it in both functions, one at a time and then in both, it does not work. –  Jan 03 '19 at 23:33
  • Currently, the method of action is as follows: [Authorize(Roles = "Administrador")] public ActionResult ReportDmsVehiculos() { return View(); } –  Jan 03 '19 at 23:40
  • Please see the updated solution. No need to add Claims. – Ashish Mishra Jan 04 '19 at 05:46
  • One more question, how do I add an automatic message, when access is denied? I have tried like this: if (filterContext.Controller.TempData.ContainsValue("Unauthorized")) { ModelState.AddModelError("", "Acceso Denegado."); View("Index", "Home"); }; and in the view like this: But it does not work: @Html.ValidationSummary(true, "", new { @class = "text-danger text-center" })I do not know the name of the access attribute allowed or denied, when the Role does not correspond. –  Jan 04 '19 at 22:43
  • You need to create custom Authorize attribute and override methods like HandleUnauthorizedRequest and AuthorizeCore to get the desired output. https://stackoverflow.com/questions/9366085/why-is-onauthorization-executing-before-authentication – Ashish Mishra Jan 05 '19 at 04:08
0

User this for code returning view with respect to a Specific role:

Instead of This:

public ActionResult Login()
{
   if (User.Identity.IsAuthenticated)
      return RedirectToAction("Index", "Home");

   return View();
} 

Try This:

public ActionResult Login()
{
   if (User.IsInRole("ProvideASpecificRoleHere"))
      return RedirectToAction("Index", "Home");

   return View();
}
Rehan Shah
  • 1,505
  • 12
  • 28
  • Excellent is just what I needed. Thank you..: public ActionResult Login() { //if (User.Identity.IsAuthenticated) if (User.IsInRole("ProvideASpecificRoleHere")) return RedirectToAction("Index", "Home"); if (User.Identity.IsAuthenticated) ModelState.AddModelError("", "Acceso Denegado."); return View(); } –  Jan 05 '19 at 14:05
  • @MauricoBello Good To see that. – Rehan Shah Jan 05 '19 at 15:16
  • @MauricoBello - Mark it as a answer . -Thanks – Rehan Shah Jan 05 '19 at 15:18
  • One more question. How to implement authentication and role-based authorization in the C # web API I made this implementation with c # MVC5 Normal but it does not work with WEB API C # MVC5 https://stackoverflow.com/questions/54597216/how-to-implement-authentication-and-role-based-authorization-in-the-c-web-api –  Feb 08 '19 at 17:24