views:

1913

answers:

4

I'm trying to add simple Authentication and Authorization to an ASP.NET MVC application.

I'm just trying to tack on some added functionality to the basic Forms Authentication (due to simplicity and custom database structure)

Assuming this is my database structure: User: username password role (ideally some enum. Strings if need be. Currently, user only has ONE role, but this might change)

High Level Problem: Given the above database structure, I would like to be able to do the following:

  • Simple Login using Forms Authentication
  • Decorate my actions with: [Authorize(Roles={ MyRoles.Admin, MyRoles.Member})]
  • Use roles in my Views (to determine links to display in some partials)

Currently, all I'm really sure of is how to Authenticate. After that I'm lost. I'm not sure at which point do I grab the user role (login, every authorization?). Since my roles may not be strings, I'm not sure how they will fit in with the User.IsInRole().

Now, I'm asking here because I haven't found a "simple" accomplish what I need. I have seen multiple examples.

For Authentication:

  • We have simple user validation that checks the database and "SetAuthCookie"
  • Or we override the Membership provider and do this inside of ValidateUser In either of these, I'm not sure how to tack on my simple user Roles, so that they work with the: HttpContext.Current.User.IsInRole("Administrator") Furthermore, I'm not sure how to modify this to work with my enum values.

For Authorization, I've seen:

  • Deriving AuthorizeAttribute and implementing AuthorizeCore OR OnAuthorization to handle roles?
  • Implementing IPrincipal?

Any assistance would be greatly appreciated. However, I fear I may need a lot of detail, because none of what I've Googled seems to fit with what I need to do.

A: 

Add your users to the table "users in roles". Use the stored procedure "addusertorole" (something like that) in your code to add to various roles. You can create the roles very simply in the "roles" table.

Your tables to use: User, UsersInRole, Roles

Use the built in Stored Procs to manipulate those tables. Then all you have to do is add the attribute.

For example you can have an "Admin" attribute on a view that selects a user and adds them to a role. You can use the stored proc to add that user to the role.

Mike McClintock
I'm not concerned about the SQL database. I can handle that on my own. I just need to know "where".
Kevin
When you say "where" do you mean where do you put the attribute?
Mike McClintock
+1  A: 

Build a custom authorise attribe that can use your enums rather than strings. When you need to authorise, convert the enums into strings by appending the enum type name + the enum value and use the IsInRole from there.

To add roles into an authorised user you need to attach to the HttpApplication AuthenticateRequest event something like the first code in http://www.eggheadcafe.com/articles/20020906.asp ( but invert the massively nested if statements into guard clauses!).

You can round-trip the users roles in the forms auth cookie or grab them from the database each time.

Neal
Actually, that's exactly what I ended up doing. I finally realized that you can't get around the String thing if you're using IsInRole. So I could have my enums throughout my Controllers, but if I ever need to check Roles in the view, I'm stuck with IsInRole...ThanX
Kevin
Factor out the enum -> string conversion from the attribute into a helper, use the helper from the attribute and create a html helper extension method IsUserInRole that also uses the helper but is easily accessible from the view.
Neal
+2  A: 

i think i've met same thing,my sln is like following ( used tutorial NeedDinner ):

**step 1

when u sign in the login user , you can add code like this:**

    FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
        1,
        userName,
        DateTime.Now,
        DateTime.Now.AddMinutes(20),
        false,
        "2"//user's roles name
        );

    string encryptedTicket = FormsAuthentication.Encrypt(authTicket);

    System.Web.HttpCookie authCookie = new System.Web.HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
    System.Web.HttpContext.Current.Response.Cookies.Add(authCookie);

step 2

add following code in Global.asax.cs

protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
    HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
    if (authCookie == null || authCookie.Value == "")
    {
        return;
    }
    FormsAuthenticationTicket authTicket = null;
    try
    {
        authTicket = FormsAuthentication.Decrypt(authCookie.Value);
    }
    catch
    {
        return;
    }
    string[] roles = authTicket.UserData.Split(new char[] { ';' });
    //Context.ClearError();
    if (Context.User != null)
    {
        Context.User = new System.Security.Principal.GenericPrincipal(Context.User.Identity, roles);
    }
}

step 3 :

then , u can use the [Authorize] in you controller -> action

[Authorize(Roles="1")]
public ActionResult Index(int ? page)

========================================

and u can email to me for exchanging experience . my address is yinner*126.com.

yinner
A: 

using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Security; using SISWEBBSI.Models.Model; using SISWEBBSI.Models.Model.Entities; using SISWEBBSI.Models.ViewModel;

namespace SISWEBBSI.Controllers.ActionFilter { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)] public sealed class RequerAutorizacao : ActionFilterAttribute {

    public Grupo.Papeis[] Papeis = {} ;
    public string ViewName { get; set; }
    public ViewDataDictionary ViewDataDictionary { get; set; }
    public AcessoNegadoViewModel AcessoNegadoViewModel { get; set; }

    public override void OnActionExecuting(ActionExecutingContext FilterContext)
    {
        if (!FilterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            string UrlSucesso = FilterContext.HttpContext.Request.Url.AbsolutePath;
            string UrlRedirecionar = string.Format("?ReturnUrl={0}", UrlSucesso);
            string UrlLogin = FormsAuthentication.LoginUrl + UrlRedirecionar;
            FilterContext.HttpContext.Response.Redirect(UrlLogin, true);
        }
        else
        {
            if (Papeis.Length > 0)
            {
                //Papel ADMINISTRADOR sempre terá acesso quando alguma restrição de papeis for colocada.
                int NovoTamanho = Papeis.Count() + 1;
                Array.Resize(ref Papeis, NovoTamanho);
                Papeis[NovoTamanho - 1] = Grupo.Papeis.ADMINISTRADOR;
                UsuarioModel Model = new UsuarioModel();
                if (!Model.UsuarioExecutaPapel(FilterContext.HttpContext.User.Identity.Name, Papeis))
                {
                    ViewName = "AcessoNegado";
                    String Mensagem = "Você não possui privilégios suficientes para essa operação. Você deve estar nos grupos que possuem";
                    if(Papeis.Length == 1)
                    {
                        Mensagem = Mensagem + " o papel: <BR/>";
                    }
                    else if (Papeis.Length > 1)
                    {
                        Mensagem = Mensagem + " os papéis: <BR/>";
                    }

                    foreach (var papel in Papeis)
                    {
                        Mensagem = Mensagem + papel.ToString() + "<br/>";
                    }
                    AcessoNegadoViewModel = new AcessoNegadoViewModel();
                    AcessoNegadoViewModel.Mensagem = Mensagem;
                    ViewDataDictionary = new ViewDataDictionary(AcessoNegadoViewModel);
                    FilterContext.Result = new ViewResult { ViewName = ViewName, ViewData = ViewDataDictionary };
                    return;
                }
            }
        }
    }
}

}