簡體   English   中英

ASP.NET MVC表單身份驗證+授權屬性+簡單角色

[英]ASP.NET MVC Forms Authentication + Authorize Attribute + Simple Roles

我正在嘗試向ASP.NET MVC應用程序添加簡單的身份驗證和授權。

我只是試圖在基本的表單身份驗證上增加一些功能(由於簡單性和自定義數據庫結構)

假設這是我的數據庫結構:用戶:用戶名密碼角色(理想情況下是一些枚舉。如果需要,則為字符串。目前,用戶只有一個角色,但這可能會改變)

高級問題:鑒於上述數據庫結構,我希望能夠做到以下幾點:

  • 使用表單身份驗證簡單登錄
  • 用以下方式裝飾我的行為:[授權(角色= {MyRoles.Admin,MyRoles.Member})]
  • 在我的視圖中使用角色(以確定在某些部分中顯示的鏈接)

目前,我真正確定的是如何進行身份驗證。 在那之后,我迷路了。 我不確定我在哪個位置獲取用戶角色(登錄,每次授權?)。 由於我的角色可能不是字符串,我不確定它們如何適應User.IsInRole()。

現在,我在這里問,因為我沒有找到一個“簡單”完成我需要的東西。 我見過多個例子。

對於身份驗證

  • 我們有簡單的用戶驗證來檢查數據庫和“SetAuthCookie”
  • 或者我們覆蓋成員資格提供程序並在ValidateUser中執行此操作。在其中任何一個中,我不確定如何處理我的簡單用戶角色,以便它們使用:HttpContext.Current.User.IsInRole(“Administrator”)此外,我不知道如何修改它以使用我的枚舉值。

對於授權,我看到:

  • 派生AuthorizeAttribute並實現AuthorizeCore OR OnAuthorization來處理角色?
  • 實施IPrincipal?

任何幫助將不勝感激。 但是,我擔心我可能需要很多細節,因為我用Google搜索的內容似乎都不適合我需要做的事情。

我想我已經實現了類似的東西。
我的解決方案基於NerdDinner 教程 ,正在關注。

當您為用戶簽名時 ,添加如下代碼:

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 ()

如果您有其他問題,請與我們聯系。

構建一個可以使用枚舉而不是字符串的自定義AuthorizeAttribute 當您需要授權時,通過附加枚舉類型名稱+枚舉值將枚舉轉換為字符串,並從那里使用IsInRole

要將角色添加到授權用戶,您需要附加到HttpApplication AuthenticateRequest事件,例如http://www.eggheadcafe.com/articles/20020906.asp中的第一個代碼(但將大量嵌套的if語句反轉為guard子句!) 。

您可以在表單auth cookie中往返用戶角色,也可以每次從數據庫中獲取它們。

我做了這樣的事情:

  • 使用Global.asax.cs加載要在會話,緩存或應用程序狀態中比較的角色,或者在ValidateUser控制器上即時加載它們

將[Authorize]屬性分配給控制器,您需要授權

 [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>

從窗體發布調用Login Controller和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;
    }
}

}

用戶已通過身份驗證,現在可以創建新身份

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

將您的用戶添加到“角色中的用戶”表中。 在代碼中使用存儲過程“addusertorole”(類似的東西)添加到各種角色。 您可以在“角色”表中非常簡單地創建角色。

您要使用的表:User,UsersInRole,Roles

使用內置的存儲過程來操作這些表。 然后,您只需添加屬性即可。

例如,您可以在視圖上使用“Admin”屬性來選擇用戶並將其添加到角色。 您可以使用存儲過程將該用戶添加到該角色。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM