Подтвердить что ты не робот

ASP.NET MVC Forms Authentication + Авторизовать атрибут + простые роли

Я пытаюсь добавить простую аутентификацию и авторизацию в приложение ASP.NET MVC.

Я просто пытаюсь использовать некоторые дополнительные функции для базовой проверки подлинности форм (благодаря простоте и настраиваемой структуре базы данных).

Предполагая, что это моя структура базы данных: Пользователь: имя пользователя пароль (в идеале, некоторые перечислены. Строки, если нужно. В настоящее время у пользователя только одна роль, но это может измениться)

Проблема высокого уровня: Учитывая указанную выше структуру базы данных, я хотел бы иметь возможность сделать следующее:

  • Простой вход с использованием проверки подлинности с помощью форм
  • Украсьте мои действия с помощью: [Авторизовать (Роли = {MyRoles.Admin, MyRoles.Member})]
  • Используйте роли в моих представлениях (чтобы определить ссылки для отображения в некоторых частицах)

В настоящее время все, на что я действительно уверен, - это аутентификация. После этого я потерялся. Я не уверен, в какой момент я захвачу роль пользователя (логин, каждая авторизация?). Поскольку мои роли не могут быть строками, я не уверен, как они будут вписываться в User.IsInRole().

Теперь я спрашиваю здесь, потому что я не нашел "простого" решения, что мне нужно. Я видел несколько примеров.

Для аутентификации:

  • У нас есть простая проверка пользователей, которая проверяет базу данных и "SetAuthCookie"
  • Или мы переопределяем поставщика членства и делаем это внутри ValidateUser В любом из них я не уверен, как использовать мои простые пользовательские роли, чтобы они работали с: HttpContext.Current.User.IsInRole( "Администратор" ) Кроме того, я не уверен, как изменить это, чтобы работать с моими значениями перечисления.

Для авторизации я видел:

  • Получение полномочий AuthorizeAttribute и реализация AuthorizeCore OR OnAuthorization для обработки ролей?
  • Реализация IPrincipal?

Любая помощь будет принята с благодарностью. Тем не менее, я боюсь, что мне может понадобиться много деталей, потому что ничто из того, что я искал Google, похоже, соответствует тому, что мне нужно делать.

4b9b3361

Ответ 1

Создайте пользовательский AuthorizeAttribute, который может использовать ваши перечисления, а не строки. Когда вам нужно авторизоваться, преобразуйте перечисления в строки, добавив имя типа перечисления + значение перечисления и используйте оттуда IsInRole.

Чтобы добавить роли авторизованному пользователю, вам нужно присоединить к событию HttpApplication AuthenticateRequest что-то вроде первого кода в http://www.eggheadcafe.com/articles/20020906.asp (но инвертировать массивно вложенные операторы if в пункты охраны!).

Вы можете использовать роли пользователей в файлах cookie для проверки подлинности или извлекать их из базы данных каждый раз.

Ответ 2

Я думаю, что реализовал нечто подобное.
Мое решение, основанное на учебнике по NerdDinner tutorial, заключается в следующем.

Когда вы подписываете пользователя в, добавьте код, подобный следующему:

var authTicket = new FormsAuthenticationTicket(
    1,                             // version
    userName,                      // user name
    DateTime.Now,                  // created
    DateTime.Now.AddMinutes(20),   // expires
    rememberMe,                    // persistent?
    "Moderator;Admin"                        // can be used to store roles
    );

string encryptedTicket = FormsAuthentication.Encrypt(authTicket);

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

Добавьте следующий код в 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;
    try
    {
        authTicket = FormsAuthentication.Decrypt(authCookie.Value);
    }
    catch
    {
        return;
    }

    // retrieve roles from UserData
    string[] roles = authTicket.UserData.Split(';');

    if (Context.User != null)
        Context.User = new GenericPrincipal(Context.User.Identity, roles);
}

После этого вы можете использовать атрибут [Authorize] в коде действия вашего контроллера:

[Authorize(Roles="Admin")]
public ActionResult AdminIndex ()

Пожалуйста, дайте мне знать, если у вас есть дополнительные вопросы.

Ответ 3

Я сделал что-то вроде этого:

  • Используйте Global.asax.cs для загрузки роли, которую вы хотите сравнить в сеансе, кеше или состоянии приложения, или загружаете их на лету на контроллере ValidateUser.

Назначьте атрибут [Авторизовать] для своих контроллеров, для чего требуется разрешение для

 [Authorize(Roles = "Admin,Tech")]

или разрешить доступ, например, контроллеры Login и ValidateUser используют атрибут ниже

 [AllowAnonymous] 

Моя форма входа

<form id="formLogin" name="formLogin" method="post" action="ValidateUser">
<table>
  <tr>
    <td>
       <label for="txtUserName">Username: (AD username) </label>
    </td>
    <td>
       <input id="txtUserName" name="txtUserName" role="textbox" type="text" />
    </td>
  </tr>
  <tr>
     <td>
         <label for="txtPassword">Password: </label>
     </td>
     <td>
         <input id="txtPassword" name="txtPassword" role="textbox" type="password" />
     </td>
  </tr>
  <tr>
      <td>
         <p>
           <input id="btnLogin" type="submit" value="LogIn" class="formbutton" />
        </p>
      </td>
  </tr>
</table>
       @Html.Raw("<span id='lblLoginError'>" + @errMessage + "</span>")
</form>

Контроллер входа и контроллер ValidateUser, вызванный из сообщения формы

Проверка аутентификации пользователя через службу WCF, которая проверяет локальную службу Windows AD для службы, но вы можете изменить ее на свой собственный механизм проверки подлинности.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using System.Security.Principal;
using MyMVCProject.Extensions;
namespace MyMVCProject.Controllers
{
public class SecurityController : Controller
{
    [AllowAnonymous]
    public ActionResult Login(string returnUrl)
    {
        Session["LoginReturnURL"] = returnUrl;
        Session["PageName"] = "Login";
        return View("Login");
    }
    [AllowAnonymous]
    public ActionResult ValidateUser()
    {
        Session["PageName"] = "Login";
        ViewResult retVal = null;
        string loginError = string.Empty;
        HttpContext.User = null;

        var adClient = HttpContext.Application.GetApplicationStateWCFServiceProxyBase.ServiceProxyBase<UserOperationsReference.IUserOperations>>("ADService").Channel;

        var username = Request.Form["txtUserName"];
        var password = Request.Form["txtPassword"];

        //check for ad domain name prefix
        if (username.Contains(@"\"))
          username = username.Split('\\')[1];

        //check for the existence of the account 
        var acctReq = new UserOperationsReference.DoesAccountExistRequest();
        acctReq.userName = username;
        //account existence result
        var accountExist = adClient.DoesAccountExist(acctReq);
        if (!accountExist.DoesAccountExistResult)
        {
            //no account; inform the user
            return View("Login", new object[] { "NO_ACCOUNT", accountExist.errorMessage });
        }
        //authenticate
        var authReq = new UserOperationsReference.AuthenticateRequest();
        authReq.userName = username;
        authReq.passWord = password;
        var authResponse = adClient.Authenticate(authReq);
        String verifiedRoles = string.Empty;
        //check to make sure the login was as success against the ad service endpoint
        if (authResponse.AuthenticateResult == UserOperationsReference.DirectoryServicesEnumsUserProperties.SUCCESS)
        {
            Dictionary<string, string[]> siteRoles = null;

            //get the role types and roles
            if (HttpContext.Application["UISiteRoles"] != null)
                siteRoles = HttpContext.Application.GetApplicationState<Dictionary<string, string[]>>("UISiteRoles");

            string groupResponseError = string.Empty;
            if (siteRoles != null && siteRoles.Count > 0)
            {
                //get the user roles from the AD service
                var groupsReq = new UserOperationsReference.GetUsersGroupsRequest();
                groupsReq.userName = username;
                //execute the service method for getting the roles/groups
                var groupsResponse = adClient.GetUsersGroups(groupsReq);
                //retrieve the results
                if (groupsResponse != null)
                {
                    groupResponseError = groupsResponse.errorMessage;
                    var adRoles = groupsResponse.GetUsersGroupsResult;

                    if (adRoles != null)
                    {
                        //loop through the roles returned from the server
                        foreach (var adRole in adRoles)
                        {
                            //look for an admin role first
                            foreach (var roleName in siteRoles.Keys)
                            {
                                var roles = siteRoles[roleName].ToList();
                                foreach (var role in roles)
                                {
                                    if (adRole.Equals(role, StringComparison.InvariantCultureIgnoreCase))
                                    {
                                        //we found a role, stop looking
                                        verifiedRoles += roleName + ";";
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            if (String.IsNullOrEmpty(verifiedRoles))
            {
                //no valid role we need to inform the user
                return View("Login", new object[] { "NO_ACCESS_ROLE", groupResponseError });
            }

            if (verifiedRoles.EndsWith(";"))
                verifiedRoles = verifiedRoles.Remove(verifiedRoles.Length - 1, 1);

            //all is authenticated not build the auth ticket
            var authTicket = new FormsAuthenticationTicket(
            1,                             // version
            username,                      // user name
            DateTime.Now,                  // created
            DateTime.Now.AddMinutes(20),  // expires
            true,                    // persistent?
           verifiedRoles   // can be used to store roles
            );

            //encrypt the ticket before adding it to the http response
            string encryptedTicket = FormsAuthentication.Encrypt(authTicket);

            var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
            Response.Cookies.Add(authCookie);

            Session["UserRoles"] = verifiedRoles.Split(';');

            //redirect to calling page
            Response.Redirect(Session["LoginReturnURL"].ToString());
        }
        else
        {
            retVal = View("Login", new object[] { authResponse.AuthenticateResult.ToString(), authResponse.errorMessage });
        }

        return retVal;
    }
}

}

Пользователь аутентифицируется, теперь создайте новый Identity

protected void FormsAuthentication_OnAuthenticate(Object sender,     FormsAuthenticationEventArgs e)
    {
        if (FormsAuthentication.CookiesSupported == true)
        {
            HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
            if (authCookie == null || authCookie.Value == "")
                return;

            FormsAuthenticationTicket authTicket = null;
            try
            {
                authTicket = FormsAuthentication.Decrypt(authCookie.Value);
            }
            catch
            {
                return;
            }

            // retrieve roles from UserData
            if (authTicket.UserData == null)
                return;

            //get username from ticket
            string username = authTicket.Name;

            Context.User = new GenericPrincipal(
                      new System.Security.Principal.GenericIdentity(username, "MyCustomAuthTypeName"), authTicket.UserData.Split(';'));
        }
    }

На моем сайте в верхней части моего _Layout.cshtml у меня есть что-то вроде этого

 {
  bool authedUser = false;
  if (User != null && User.Identity.AuthenticationType == "MyCustomAuthTypeName" && User.Identity.IsAuthenticated)
   {
      authedUser = true;
   }
 }

Затем в теле

        @{
         if (authedUser)
          {
            <span id="loggedIn_userName">
                <label>User Logged In: </label>@User.Identity.Name.ToUpper()
            </span>
          }
          else
          {
            <span id="loggedIn_userName_none">

                <label>No User Logged In</label>
            </span>
          }
        }

Ответ 4

Добавьте пользователей в таблицу "пользователи в ролях". Используйте хранимую процедуру "addusertorole" (что-то в этом роде) в вашем коде, чтобы добавить к различным ролям. Вы можете создавать роли очень просто в таблице "ролей".

Ваши таблицы для использования: User, UsersInRole, Roles

Используйте встроенные хранимые процедуры для управления этими таблицами. Тогда все, что вам нужно сделать, это добавить атрибут.

Например, вы можете иметь атрибут "Admin" в представлении, которое выбирает пользователя и добавляет его в роль. Вы можете использовать сохраненный proc для добавления этого пользователя в роль.

Ответ 5

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;
                    }
                }
            }
        }
    }
}